VulkanとDirectX12は両方とも、スレッドセーフな方法で使用可能であると主張されています。人々はそれについて興奮しているようです。
なぜこれがそんなに大きな機能と見なされるのですか?とにかく、「実際の」処理は別の処理ユニットのメモリブリッジを介してスローされます。
また、非常に大きい場合、スレッドセーフなグラフィックスAPIが登場したのはなぜですか?
VulkanとDirectX12は両方とも、スレッドセーフな方法で使用可能であると主張されています。人々はそれについて興奮しているようです。
なぜこれがそんなに大きな機能と見なされるのですか?とにかく、「実際の」処理は別の処理ユニットのメモリブリッジを介してスローされます。
また、非常に大きい場合、スレッドセーフなグラフィックスAPIが登場したのはなぜですか?
回答:
主な利点は、グラフィックAPIへのアクセスに関するすべての困難な問題を解決する必要なく、CPUタスクを複数のスレッドに分割することが容易になることです。通常、コンテキストを最新にするか(パフォーマンスに悪い影響を与える可能性があります)、キューを提供してグラフィックスAPIを単一スレッドで呼び出す必要があります。GPUが実際にそれらを順番に処理するため、この方法でパフォーマンスが得られるとは思いませんが、開発者の仕事がずっと簡単になります。
これが今まで行われなかった理由は、おそらく、directxとopenglがマルチスレッドが実際には明らかにされていない時期に作成されたためです。また、KhronosボードはAPIを変更する際に非常に保守的です。Vulkanに関する彼らの見解は、OpenGLの隣に共存するということでもあります。両者は異なる目的に役立つからです。消費者がますます多くのプロセッサーにアクセスできるようになったため、パラリズムがそれほど重要になったのはおそらく最近のことでしょう。
編集:複数のCPUで作業を行ってもパフォーマンスが得られるわけではありません。呼び出しを複数のスレッドに分割してテクスチャ/シェーダーをより速く作成することは役に立ちません。むしろ、より多くのプロセッサをビジーにして、実行することでGPUをビジーにしておくことにより、パフォーマンスが向上します。
GPUのフレームを設定するためにCPUで多くの作業が必要であり、その作業の大部分はグラフィックスドライバー内にあります。DX12 / Vulkanより前は、そのグラフィックドライバーの動作は、APIの設計により本質的にシングルスレッドにすることを強制されていました。
DX12 / Vulkanがその制限を解除し、フレーム内の複数のCPUスレッドでドライバーの作業を並行して実行できるようになることが期待されています。これにより、マルチコアCPUをより効率的に使用できるようになり、ゲームエンジンはCPUに縛られることなく、より複雑なシーンをプッシュできます。それが希望です。実際にそれが実現されるかどうかは、今後数年にわたって見る必要があります。
少し詳しく説明すると、ゲームエンジンレンダラーの出力は、フレームをレンダリングする一連の操作を記述するDX / GL API呼び出しのストリームです。ただし、API呼び出しのストリームと、GPUハードウェアが消費する実際のバイナリコマンドバッファーとの間には大きな距離があります。ドライバーは、いわば、GPUのマシン言語にAPI呼び出しを「コンパイル」する必要があります。それは簡単なプロセスではありません。APIの概念を低レベルのハードウェアの現実に変換し、GPUが無効な状態に設定されないようにするための検証、メモリ割り当てとデータの調整、低レベルのコマンドなどを修正します。グラフィックスドライバーは、これらすべてを担当します。
DX11 / GL4以前のAPIでは、この作業は通常、単一のドライバースレッドによって行われます。APIを複数のスレッド(たとえば、DX11の遅延コマンドリストを使用して実行できます)から呼び出した場合でも、ドライバースレッドが後で噛むためにキューに作業を追加するだけです。これの1つの大きな理由は、前述した状態追跡です。ハードウェアレベルのGPU構成の詳細の多くは、現在のグラフィックスパイプラインの状態に関する知識を必要とするため、コマンドリストを並列処理可能なチャンクに分割する良い方法はありません。各チャンクは、開始する状態を正確に知る必要があります前のチャンクがまだ処理されていない場合でも。
これは、DX12 / Vulkanで変更された大きなことの1つです。一つには、ほぼすべてのグラフィックスパイプライン状態を1つのオブジェクトに組み込み、別のもの(少なくともDX12では)コマンドリストの作成を開始するとき、初期パイプライン状態を提供する必要があります。状態は、あるコマンドリストから次のコマンドリストに継承されません。原則として、これにより、ドライバーはコンパイルを開始する前に以前のコマンドリストについて何も知る必要がなくなります。これにより、アプリケーションはレンダリングを並列化可能なチャンクに分割し、完全にコンパイルされたコマンドリストを生成できます。連結され、最小限の手間でGPUに送信されます。
もちろん、新しいAPIには他にも多くの変更がありますが、マルチスレッドに関する限り、それが最も重要な部分です。
最近のGPUには一般に、CPUからのコマンドの完全に線形のストリームを処理する単一のフロントエンドセクションがあります。これが自然なハードウェア設計であるか、GPUのコマンドを生成する単一のCPUコアがあった時代から単純に進化したかどうかは議論の余地がありますが、現時点では現実です。したがって、ステートフルコマンドの単一の線形ストリームを生成する場合、もちろん、CPU上の単一スレッドでそのストリームを線形に生成することは理にかなっています。右?
まあ、最近のGPUには一般に、一度に多くのさまざまなことを処理できる非常に柔軟な統合バックエンドもあります。一般的に、GPUはかなり細かい粒度で頂点とピクセルを処理します。GPUが1つの描画で1024個の頂点を処理し、2つの異なる描画で512 + 512個の頂点を処理する場合、それほど大きな違いはありません。
これは、1回の描画呼び出しでGPUに膨大な数の頂点を投げるのではなく、モデルをセクションに分割し、それらのセクションで安価な粗選別を行い、各チャンクを個別に送信する代わりに、作業を減らすかなり自然な方法を示唆していますカリングテスト。適切な粒度でそれを行うと、素晴らしいスピードアップが得られます!
残念ながら、現在のグラフィックスAPIの現実では、描画呼び出しはCPUで非常に高価です。理由の簡単な説明:GPUの状態変更はグラフィックスAPI呼び出しに直接対応しない可能性があるため、多くのグラフィックスAPI呼び出しは単にドライバー内に何らかの状態を設定し、この新しい状態に依存する描画呼び出しはすべての最後の描画以降に変更されたとマークされた状態は、GPUのコマンドストリームに書き込み、実際に描画を開始します。これはすべて、GPUフロントエンドユニットの無駄のない平均的なコマンドストリームを取得するために行われる作業です。
要するに、ドライバーのオーバーヘッドによって完全に課されるドローコールの予算があるということです。(最近では、60 FPSタイトルの場合、フレームごとに約5,000で逃げることができると聞いたと思います。)このコマンドストリームを並列チャンクで構築することで、大幅に増やすことができます。
他にも理由があります(たとえば、VR遅延の改善のための非同期タイムワープ)が、これはグラフィックバウンドゲームや他の描画呼び出しが多いソフトウェア(3Dモデリングパッケージなど)にとって大きな理由です。