金属渲染速度缓慢-如何加快速度

3

我有一个正在工作的金属应用程序,但它非常缓慢,需要更快地运行。我认为问题在于我创建了太多的MTLCommandBuffer对象。

我之所以创建这么多的MTLCommandBuffer对象,是因为我需要向像素着色器发送不同的统一值。我在下面粘贴了一段代码片段来说明问题。

  for (int obj_i = 0 ; obj_i < n ; ++obj_i)
  {
     // I create one render command buffer per object I draw so I can use  different uniforms
     id <MTLCommandBuffer> mtlCommandBuffer = [metal_info.g_commandQueue commandBuffer];
     id <MTLRenderCommandEncoder> renderCommand = [mtlCommandBuffer renderCommandEncoderWithDescriptor:<#(MTLRenderPassDescriptor *)#>]

     // glossing over details, but this call has per object specific data
     memcpy([global_uniform_buffer contents], per_object_data, sizeof(per_data_object));

     [renderCommand setVertexBuffer:object_vertices  offset:0 atIndex:0];
     // I am reusing a single buffer for all shader calls
     // this is killing performance
     [renderCommand setVertexBuffer:global_uniform_buffer offset:0 atIndex:1];

     [renderCommand drawIndexedPrimitives:MTLPrimitiveTypeTriangle
                               indexCount:per_object_index_count
                               indexType:MTLIndexTypeUInt32
                             indexBuffer:indicies
                       indexBufferOffset:0];
     [renderCommand endEncoding];
     [mtlCommandBuffer presentDrawable:frameDrawable];
     [mtlCommandBuffer commit];
}  

上述代码按预期绘制,但非常慢。我猜这是因为有更好的方法来强制像素着色器评估,而无需为每个对象创建MTLCommandBuffer。
我考虑过简单地分配一个比单个着色器通道所需的缓冲区大得多的缓冲区,并仅使用偏移量在一个渲染命令编码器中排队多个调用,然后执行它们。这种方法似乎相当不正统,我想确保以符合Metal的方式解决必须发送每个对象的自定义数据问题。
使用相同像素/顶点着色器的多个传递和每次调用的自定义统一数据的最快渲染方式是什么?
1个回答

7
不要为每个对象重复使用相同的统一缓冲区。这样做会破坏CPU和GPU之间的所有并行性,并导致定期的同步点。
相反,为要在帧中呈现的每个对象制作一个单独的统一缓冲区。实际上,您应该为每个对象创建2个统一缓冲区,并在每个帧之间交替使用它们,以便GPU可以在您在CPU上准备下一帧时渲染上一帧。
完成此操作后,只需重构循环,使命令缓冲区和渲染命令工作每帧执行一次。您的循环应仅包括复制统一数据、设置顶点缓冲区并调用绘制原语。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接