From b8bc36559d1e44d94569221247bde79c8ad6c5ac Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 24 Jan 2021 13:46:05 +0100 Subject: [PATCH] [d3d11] Optimize index buffer binding with offset Do not rebind the buffer if only the offset changes. Instead, adjust StartIndexLocation in indexed draw calls. For indirect draws, this will be disabled on the fly. This may save a whole bunch of work in the backend, and reduces the number of commands being sent to the CS thread in the first place, which is why this optimization is not being done in the backend itself but rather on the client API side. --- src/d3d11/d3d11_context.cpp | 43 ++++++++++++++++++++++++++++++++- src/d3d11/d3d11_context.h | 3 +++ src/d3d11/d3d11_context_state.h | 2 ++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 88fa7cdf..24dc70cf 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -1459,6 +1459,7 @@ namespace dxvk { UINT StartIndexLocation, INT BaseVertexLocation) { D3D10DeviceLock lock = LockContext(); + StartIndexLocation += m_state.ia.indexBuffer.firstIndex; EmitCs([=] (DxvkContext* ctx) { ctx->drawIndexed( @@ -1493,6 +1494,7 @@ namespace dxvk { INT BaseVertexLocation, UINT StartInstanceLocation) { D3D10DeviceLock lock = LockContext(); + StartIndexLocation += m_state.ia.indexBuffer.firstIndex; EmitCs([=] (DxvkContext* ctx) { ctx->drawIndexed( @@ -1667,6 +1669,12 @@ namespace dxvk { if (needsUpdate) m_state.ia.indexBuffer.buffer = newBuffer; + if (likely(m_state.ia.indexBuffer.optimized)) { + uint32_t shift = Format == DXGI_FORMAT_R16_UINT ? 1 : 2; + m_state.ia.indexBuffer.firstIndex = Offset >> shift; + Offset = 0; + } + needsUpdate |= m_state.ia.indexBuffer.offset != Offset || m_state.ia.indexBuffer.format != Format; @@ -3377,7 +3385,13 @@ namespace dxvk { void D3D11DeviceContext::BindFramebuffer() { DxvkRenderTargets attachments; - + + // Re-enable index buffer optimization here. Some games will + // use indirect draws for actual scene rendering, but then + // use direct draws for things like the user interface. + if (!m_state.ia.indexBuffer.optimized) + SetIndexBufferOptimized(true); + // D3D11 doesn't have the concept of a framebuffer object, // so we'll just create a new one every time the render // target bindings are updated. Set up the attachments. @@ -3572,12 +3586,39 @@ namespace dxvk { } + void D3D11DeviceContext::SetIndexBufferOptimized( + BOOL Enable) { + uint32_t shift = m_state.ia.indexBuffer.format == DXGI_FORMAT_R16_UINT ? 1 : 2; + + if (Enable) { + m_state.ia.indexBuffer.firstIndex = m_state.ia.indexBuffer.offset >> shift; + m_state.ia.indexBuffer.offset = 0; + } else { + m_state.ia.indexBuffer.offset += m_state.ia.indexBuffer.firstIndex << shift; + m_state.ia.indexBuffer.firstIndex = 0; + } + + m_state.ia.indexBuffer.optimized = Enable; + + BindIndexBuffer( + m_state.ia.indexBuffer.buffer.ptr(), + m_state.ia.indexBuffer.offset, + m_state.ia.indexBuffer.format); + } + + void D3D11DeviceContext::SetDrawBuffers( ID3D11Buffer* pBufferForArgs, ID3D11Buffer* pBufferForCount) { auto argBuffer = static_cast(pBufferForArgs); auto cntBuffer = static_cast(pBufferForCount); + // Bind index buffer with the actual offset since otherwise the + // first index members of the indirect draw structures would be + // incorrect. + if (unlikely(m_state.ia.indexBuffer.optimized)) + SetIndexBufferOptimized(false); + if (m_state.id.argBuffer != argBuffer || m_state.id.cntBuffer != cntBuffer) { m_state.id.argBuffer = argBuffer; diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index de5b82b0..65cf1a8e 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -786,6 +786,9 @@ namespace dxvk { ID3D11Resource* pResource, UINT Subresource); + void SetIndexBufferOptimized( + BOOL Enable); + void SetDrawBuffers( ID3D11Buffer* pBufferForArgs, ID3D11Buffer* pBufferForCount); diff --git a/src/d3d11/d3d11_context_state.h b/src/d3d11/d3d11_context_state.h index eca2a3c9..98635eb0 100644 --- a/src/d3d11/d3d11_context_state.h +++ b/src/d3d11/d3d11_context_state.h @@ -103,6 +103,8 @@ namespace dxvk { Com buffer = nullptr; UINT offset = 0; DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + UINT firstIndex = 0; + BOOL optimized = true; };