2015-05-06 49 views
1

我有一个非常慢的工作金属应用程序,需要运行得更快。我相信问题是我创建了太多的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更好的强制像素着色评估的方法。

我认为简单地分配一个比单个着色器通道所需要的大得多的缓冲区,并简单地使用偏移量在一个渲染命令编码器中排队几个调用,然后执行它们。这种方法看起来非常非常规,我想确保我正在解决需要以金属友好的方式为每个对象发送自定义数据的问题。

什么是使用同一个像素/顶点着色器的多个通道渲染每个调用自定义统一数据的最快方式?

回答

3

不要为每个对象重用相同的统一缓冲区。这样做会破坏CPU和GPU之间的所有并行性并导致常规同步点。

取而代之的是,您要在框架中呈现每个对象的单独统一缓冲区。实际上,您应该在每个对象之间创建2个对象,并在它们之间交替,以便在准备CPU上的下一个帧时,GPU可以渲染最后一个帧。

做完这些之后,您只需重构您的循环,以便命令缓冲区和渲染命令每帧完成一次。你的循环应该只包括复制统一数据,设置顶点缓冲区和调用绘制原语。