非常に遅く、より高速に実行する必要がある作業中の金属アプリケーションがあります。問題は、作成している 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 を作成するよりも、ピクセル シェーダーの評価を強制するより良い方法があるためだと思います。
1 つのシェーダー パスに必要なサイズよりもはるかに大きなバッファーを単純に割り当て、単純にオフセットを使用して 1 つのレンダリング コマンド エンコーダーで複数の呼び出しをキューに入れ、それらを実行することを検討しました。この方法はかなり異例のようです。オブジェクトごとにカスタム データをメタルに適した方法で送信する必要があるという問題を確実に解決したいと考えています。
呼び出しごとのカスタム ユニフォーム データを使用して、同じピクセル/頂点シェーダーの複数のパスを使用してレンダリングする最速の方法は何ですか?