2

非常に遅く、より高速に実行する必要がある作業中の金属アプリケーションがあります。問題は、作成している 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 つのレンダリング コマンド エンコーダーで複数の呼び出しをキューに入れ、それらを実行することを検討しました。この方法はかなり異例のようです。オブジェクトごとにカスタム データをメタルに適した方法で送信する必要があるという問題を確実に解決したいと考えています。

呼び出しごとのカスタム ユニフォーム データを使用して、同じピクセル/頂点シェーダーの複数のパスを使用してレンダリングする最速の方法は何ですか?

4

1 に答える 1

6

すべてのオブジェクトに同じ一様バッファを再利用しないでください。これを行うと、CPU と GPU 間のすべての並列処理が破棄され、通常の同期ポイントが発生します。

代わりに、フレームでレンダリングするオブジェクトごとに個別の均一バッファを作成してください。実際には、CPU で次のフレームを準備している間に GPU が最後のフレームをレンダリングできるように、オブジェクトごとに 2 つ作成し、フレームごとに交互に使用する必要があります。

その後、ループをリファクタリングするだけで、コマンド バッファーとレンダリング コマンドの作業がフレームごとに 1 回実行されます。ループは、ユニフォーム データのコピー、頂点バッファーの設定、描画プリミティブの呼び出しのみで構成する必要があります。

于 2015-05-08T07:17:14.057 に答える