我正在构建一个在Metal中渲染2D几何的应用程序。

现在,顶点的位置是从顶点函数中求解的。我想要的是将解决的位置从同一顶点函数内部写回到缓冲区。

我的印象是这是possible,尽管在我初次尝试时即是:

vertex VertexOut basic_vertex(device VertexIn *vertices [[ buffer(0) ]],
                              device VertexOut *solvedVertices [[ buffer(1) ]],
                              vid [[ vertex_id ]])
{
    VertexIn in vertices[vid];
    VertexOut out;
    out.position = ... // Solve the position of the vertex

    solvedVertices[vid] = out // Write to the buffer later to be read by CPU

    return out;
}

我很高兴看到这个编译时错误:

Metal 写入顶点功能的缓冲区-LMLPHP

好的,所以我想到了一些解决方案-我可以首先通过以下声明的顶点函数来求解顶点位置-非栅格化-
vertex void solve_vertex(device VertexIn *unsolved [[ buffer(0) ]],
                         device VertexOut *solved [[ buffer(1) ]],
                         vid [[ vertex_id ]])
{
    solved[vid] = ...
}

然后将那些求解的顶点通过管道传输到现在更简单的栅格化顶点函数中。

另一个可行但似乎不太吸引人的解决方案是在计算功能中解决它们。

那么,在这种情况下最好的前进方法是什么?从我的一点点研究中,我可以发现在Transform Feedback中完成了相同的过程,但是我没有运气(除了link乞求这个问题以外)在Apple文档/示例代码或其他地方没有找到示例遇到此类问题时,请在网络上获取最佳做法。

最佳答案

好吧,事实证明,使用非光栅化顶点函数是可行的方法。需要注意一些事项,以备将来引用:
非栅格化顶点函数只是返回void的顶点函数,即:

vertex void non_rasterizing_vertex(...) { }
在执行非光栅化的“渲染”过程时,出于我不知道的原因,MTLRenderPassDescriptor仍需要设置纹理(例如在MTLRenderPassDescriptorcolorAttachments[0].texture中)(我假设这仅仅是由于GPU编程的固定性质) 。MTLRenderPipelineState需要将其rasterizationEnabled属性设置为false,然后可以将非光栅化顶点函数分配给它的vertexFunction属性。 fragmentFunction属性可以保持为零。
在实际执行传递时,仍然需要在已配置的drawPrimitives:上调用MTLRenderCommandEncoder方法之一(其名称可能是misleading)。我结束了一个渲染MTLPrimitiveType.Point的调用,因为这似乎是最明智的。
完成所有这些操作后,就可以设置“渲染”逻辑,准备好从顶点函数写回顶点缓冲区了,只要它们位于device地址空间中即可:
vertex void non_rasterizing_vertex(device float *writeableBuffer [[ buffer(0) ]],
                                   uint vid [[ vertex_id ]])
{
    writeableBuffer[vid] = 42; // Write away!
}
这个“答案”最终更像是一篇博文,但我希望它对将来的引用仍然有用。
去做
我仍然想研究在计算管道中进行像这样的计算工作与在如上所述的渲染管道中进行计算工作之间的性能折衷。一旦有更多时间可以执行此操作,我将更新此答案。

关于 Metal 写入顶点功能的缓冲区,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35750397/

10-16 14:07