私が実装した単純なDirectXレンダリングコードを改善しようとしています。可能であれば、パイプラインの変更回数を最小限に抑えることが有益だと思うので、私の考えは、絶対に必要なときだけレンダリングパイプラインを更新することです。私はこれで意味次の擬似コードで実証されていますDirectXパイプラインの最適化の理解
ID3D11VertexShader *t_shader = getVertexShader();
ID3D11DeviceContext->VSSetShader(t_shader, nullptr, 0);
// Do some other processing/pipeline setup without modifying t_shader
ID3D11DeviceContext->VSSetShader(t_shader, nullptr, 0);
ID3D11DeviceContext->Draw(10, 0);
シェーダが変更されていないときに我々は二回VSSetShader呼び出しているので、これは非効率的です。これは単純化されていますが、うまくいけば私はどこから来ているのか、私の基本的な理解はこれらのタイプの不要なバインド/呼び出しは非効率的ですか?
この場合、2つの別々のID3D11DeviceContext :: Draw呼び出しの間で以下の最適化を行うことは可能ですか? (再び擬似コードはとても不足している手順を赦し、私たちが描く前に、我々が行うために必要なすべてのトポロジと一緒に頂点&ピクセルシェーダを設定されていると仮定してください):
void Object1::Draw() {
ID3D11VertexShader *t_vs = ShaderMgr::vertexShader1();
ID3D11DeviceContext->VSSetShader(t_vs, nullptr, 0);
ID3D11PixelShader *t_ps = ShaderMgr::pixelShader1();
ID3D11DeviceContext->PSSetShader(t_ps, nullptr, 0);
ID3D11DeviceContext->IASetPrimitiveTopology(ID3D11_PRIMITIVE_TOPOLOGY_LINELIST);
ID3D11DeviceContext->Draw(m_vertexCount, 0);
}
void Object2::Draw() {
ID3D11VertexShader *t_vs = ShaderMgr::vertexShader1();
ID3D11DeviceContext->VSSetShader(t_vs, nullptr, 0);
// Use a different pixel shader to Object1
ID3D11PixelShader *t_ps = ShaderMgr::pixelShader2();
ID3D11DeviceContext->PSSetShader(t_ps, nullptr, 0);
ID3D11DeviceContext->IASetPrimitiveTopology(ID3D11_PRIMITIVE_TOPOLOGY_LINELIST);
ID3D11DeviceContext->Draw(m_vertexCount, 0);
}
2つの引き分けの唯一の違いは、呼び出しをすることは、使用されます別のピクセルシェーダの次のような最適化が可能か、各描画呼び出しでパイプラインを効果的にリセットしますか?
void Object1::Draw() {
// Removed common set code
ID3D11PixelShader *t_ps = ShaderMgr::pixelShader1();
ID3D11DeviceContext->PSSetShader(t_ps, nullptr, 0);
ID3D11DeviceContext->Draw(m_vertexCount, 0);
}
void Object2::Draw() {
// Removed common set code
ID3D11PixelShader *t_ps = ShaderMgr::pixelShader2();
ID3D11DeviceContext->PSSetShader(t_ps, nullptr, 0);
ID3D11DeviceContext->Draw(m_vertexCount, 0);
}
void drawObjects() {
// Common states amongst object1 and object2
ID3D11VertexShader *t_vs = ShaderMgr::vertexShader1();
ID3D11DeviceContext->VSSetShader(t_vs, nullptr, 0);
ID3D11DeviceContext->IASetPrimitiveTopology(ID3D11_PRIMITIVE_TOPOLOGY_LINELIST);
m_object1->draw();
// Don't bother setting the vs or topology here
m_object2->draw();
}
フィードバック/情報は大歓迎です。
冗長性をキャッチするために、状態キャッシングを行うクラス内にデバイスをカプセル化するだけで済みます。ドライバーが通常不要な状態の変更をキャッシュしてテストしているため、これらの呼び出しを取り除くと、実際に悪いことが行われない限り、通常はパフォーマンスが向上しません。 – galop1n
これは私が現時点で実装しようとしている、パイプラインの "状態"があると思われる最初の描画呼び出しの後に、私は分で見ている問題、必要なときだけ状態を変更するPipelineクラスを設計していますリセットされ、すべてをもう一度設定する必要があります。入力トポロジ、頂点バッファなど – TheRarebit
DirectX12がパイプライン状態(パイプライン状態オブジェクト)をカプセル化する方法を見てみることができます。 DirectX 11を熟練したユーザーでない限り、実際にDirectX 12を使用することはお勧めしませんが、デザインには最新のGPUハードウェアの設定が反映されます。 –