我正在嘗試改進一些我已實現的簡單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兩次當着色器並沒有改變。這是一種過度簡化,但希望你能得到我來自哪裏,我的基本理解是這些不必要的綁定/調用是低效的?
如果是這種情況,那麼是否可以在兩個單獨的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);
}
兩個平局之間的唯一區別呼叫是使用不同的像素着色器。那麼下面是可能的優化還是每個繪製調用都會有效地重置管道?
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
這就是我現在要實現的目標,設計一個只在必要時才改變狀態的管道類,儘管在初始繪製調用之後我看到了問題,但管道的「狀態」似乎有已被重置,我必須重新設置所有內容,例如InputTopology,頂點緩衝區等。 – TheRarebit
您可以看看DirectX12如何封裝管道狀態(管道狀態對象)。我並不是說你實際上使用了DirectX 12,除非你已經是DirectX 11的專家用戶,但是這個設計反映了現代GPU硬件的偏好。 –