From 7815b6942d75ba3514040ba900a03d2f6790f319 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 21 Feb 2025 14:16:34 +0100 Subject: [PATCH] [d3d11] Implement direct draw batching Not super useful without backend support though. --- src/d3d11/d3d11_cmd.h | 2 + src/d3d11/d3d11_context.cpp | 121 ++++++++++++++++++++++++++---------- src/d3d11/d3d11_context.h | 6 ++ 3 files changed, 95 insertions(+), 34 deletions(-) diff --git a/src/d3d11/d3d11_cmd.h b/src/d3d11/d3d11_cmd.h index 635f63b72..df853153e 100644 --- a/src/d3d11/d3d11_cmd.h +++ b/src/d3d11/d3d11_cmd.h @@ -14,6 +14,8 @@ namespace dxvk { None, DrawIndirect, DrawIndirectIndexed, + Draw, + DrawIndexed, }; diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index c99c40178..16b396aa9 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -1037,14 +1037,13 @@ namespace dxvk { UINT StartVertexLocation) { D3D10DeviceLock lock = LockContext(); - if (unlikely(HasDirtyGraphicsBindings())) - ApplyDirtyGraphicsBindings(); + VkDrawIndirectCommand draw = { }; + draw.vertexCount = VertexCount; + draw.instanceCount = 1u; + draw.firstVertex = StartVertexLocation; + draw.firstInstance = 0u; - EmitCs([=] (DxvkContext* ctx) { - ctx->draw( - VertexCount, 1, - StartVertexLocation, 0); - }); + BatchDraw(draw); } @@ -1055,15 +1054,14 @@ namespace dxvk { INT BaseVertexLocation) { D3D10DeviceLock lock = LockContext(); - if (unlikely(HasDirtyGraphicsBindings())) - ApplyDirtyGraphicsBindings(); + VkDrawIndexedIndirectCommand draw = { }; + draw.indexCount = IndexCount; + draw.instanceCount = 1u; + draw.firstIndex = StartIndexLocation; + draw.vertexOffset = BaseVertexLocation; + draw.firstInstance = 0u; - EmitCs([=] (DxvkContext* ctx) { - ctx->drawIndexed( - IndexCount, 1, - StartIndexLocation, - BaseVertexLocation, 0); - }); + BatchDrawIndexed(draw); } @@ -1075,16 +1073,13 @@ namespace dxvk { UINT StartInstanceLocation) { D3D10DeviceLock lock = LockContext(); - if (unlikely(HasDirtyGraphicsBindings())) - ApplyDirtyGraphicsBindings(); + VkDrawIndirectCommand draw = { }; + draw.vertexCount = VertexCountPerInstance; + draw.instanceCount = InstanceCount; + draw.firstVertex = StartVertexLocation; + draw.firstInstance = StartInstanceLocation; - EmitCs([=] (DxvkContext* ctx) { - ctx->draw( - VertexCountPerInstance, - InstanceCount, - StartVertexLocation, - StartInstanceLocation); - }); + BatchDraw(draw); } @@ -1097,17 +1092,14 @@ namespace dxvk { UINT StartInstanceLocation) { D3D10DeviceLock lock = LockContext(); - if (unlikely(HasDirtyGraphicsBindings())) - ApplyDirtyGraphicsBindings(); + VkDrawIndexedIndirectCommand draw = { }; + draw.indexCount = IndexCountPerInstance; + draw.instanceCount = InstanceCount; + draw.firstIndex = StartIndexLocation; + draw.vertexOffset = BaseVertexLocation; + draw.firstInstance = StartInstanceLocation; - EmitCs([=] (DxvkContext* ctx) { - ctx->drawIndexed( - IndexCountPerInstance, - InstanceCount, - StartIndexLocation, - BaseVertexLocation, - StartInstanceLocation); - }); + BatchDrawIndexed(draw); } @@ -3568,6 +3560,67 @@ namespace dxvk { } + template + void D3D11CommonContext::BatchDraw( + const VkDrawIndirectCommand& draw) { + if (unlikely(HasDirtyGraphicsBindings())) + ApplyDirtyGraphicsBindings(); + + // Batch consecutive draws if there are no state changes + if (m_csDataType == D3D11CmdType::Draw) { + auto* drawInfo = m_csChunk->pushData(m_csData, 1u); + + if (likely(drawInfo)) { + new (drawInfo) VkDrawIndirectCommand(draw); + return; + } + } + + EmitCsCmd(D3D11CmdType::Draw, 1u, + [] (DxvkContext* ctx, const VkDrawIndirectCommand* draws, size_t count) { + for (size_t i = 0; i < count; i++) { + ctx->draw(draws[i].vertexCount, + draws[i].instanceCount, + draws[i].firstVertex, + draws[i].firstInstance); + } + }); + + new (m_csData->first()) VkDrawIndirectCommand(draw); + } + + + template + void D3D11CommonContext::BatchDrawIndexed( + const VkDrawIndexedIndirectCommand& draw) { + if (unlikely(HasDirtyGraphicsBindings())) + ApplyDirtyGraphicsBindings(); + + // Batch consecutive draws if there are no state changes + if (m_csDataType == D3D11CmdType::DrawIndexed) { + auto* drawInfo = m_csChunk->pushData(m_csData, 1u); + + if (likely(drawInfo)) { + new (drawInfo) VkDrawIndexedIndirectCommand(draw); + return; + } + } + + EmitCsCmd(D3D11CmdType::DrawIndexed, 1u, + [] (DxvkContext* ctx, const VkDrawIndexedIndirectCommand* draws, size_t count) { + for (size_t i = 0; i < count; i++) { + ctx->drawIndexed(draws[i].indexCount, + draws[i].instanceCount, + draws[i].firstIndex, + draws[i].vertexOffset, + draws[i].firstInstance); + } + }); + + new (m_csData->first()) VkDrawIndexedIndirectCommand(draw); + } + + template template void D3D11CommonContext::BindShader( diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index 02dd816ab..6fe65a019 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -848,6 +848,12 @@ namespace dxvk { void ApplyViewportState(); + void BatchDraw( + const VkDrawIndirectCommand& draw); + + void BatchDrawIndexed( + const VkDrawIndexedIndirectCommand& draw); + template void BindShader( const D3D11CommonShader* pShaderModule);