From 1544b561d52c563bb3089802944cbe223e649d4b Mon Sep 17 00:00:00 2001 From: cyy Date: Thu, 25 Jun 2026 10:48:52 +0800 Subject: [PATCH] d3d11: dirty only stages that bind a discard-mapped resource WRITE_DISCARD of a dynamic buffer/texture used to dirty every shader stage's CB/SRV set, forcing a redundant argument-table re-encode next draw on stages that never bound it. Now only stages that actually bind the resource are dirtied, on both immediate and deferred contexts. --- src/d3d11/d3d11_context_def.cpp | 16 ++++------------ src/d3d11/d3d11_context_imm.cpp | 16 ++++------------ src/d3d11/d3d11_context_state.hpp | 26 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/d3d11/d3d11_context_def.cpp b/src/d3d11/d3d11_context_def.cpp index 821a842ec..a6783b36a 100644 --- a/src/d3d11/d3d11_context_def.cpp +++ b/src/d3d11/d3d11_context_def.cpp @@ -162,14 +162,10 @@ class MTLD3D11DeferredContext : public DeferredContextBase { state_.InputAssembler.VertexBuffers.set_dirty(); } if (bind_flag & D3D11_BIND_CONSTANT_BUFFER) { - for (auto &stage : state_.ShaderStages) { - stage.ConstantBuffers.set_dirty(); - } + dirtyConstantBufferStages(state_.ShaderStages, GetResourceCommon(pResource)); } if (bind_flag & D3D11_BIND_SHADER_RESOURCE) { - for (auto &stage : state_.ShaderStages) { - stage.SRVs.set_dirty(); - } + dirtyShaderResourceStages(state_.ShaderStages, GetResourceCommon(pResource)); } pMappedResource->pData = MapDynamicBuffer(dynamic); @@ -201,9 +197,7 @@ class MTLD3D11DeferredContext : public DeferredContextBase { case D3D11_MAP_READ_WRITE: return E_INVALIDARG; case D3D11_MAP_WRITE_DISCARD: { - for (auto &stage : state_.ShaderStages) { - stage.SRVs.set_dirty(); - } + dirtyShaderResourceStages(state_.ShaderStages, GetResourceCommon(pResource)); Rc new_allocation = dynamic->allocate(ctx_state.cmd_queue.CoherentSeqId()); uint32_t id = ctx_state.current_cmdlist->used_dynamic_lineartextures.size(); // track the current allocation in case of a following NO_OVERWRITE map @@ -251,9 +245,7 @@ class MTLD3D11DeferredContext : public DeferredContextBase { case D3D11_MAP_WRITE_NO_OVERWRITE: return E_INVALIDARG; case D3D11_MAP_WRITE_DISCARD: { - for (auto &stage : state_.ShaderStages) { - stage.SRVs.set_dirty(); - } + dirtyShaderResourceStages(state_.ShaderStages, GetResourceCommon(pResource)); pMappedResource->pData = MapDynamicBuffer(dynamic); pMappedResource->RowPitch = row_pitch; pMappedResource->DepthPitch = depth_pitch; diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index b361f178e..afc81e0c3 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -156,14 +156,10 @@ class MTLD3D11ImmediateContext : public ImmediateContextBase { state_.InputAssembler.VertexBuffers.set_dirty(); } if (bind_flag & D3D11_BIND_CONSTANT_BUFFER) { - for (auto &stage : state_.ShaderStages) { - stage.ConstantBuffers.set_dirty(); - } + dirtyConstantBufferStages(state_.ShaderStages, GetResourceCommon(pResource)); } if (bind_flag & D3D11_BIND_SHADER_RESOURCE) { - for (auto &stage : state_.ShaderStages) { - stage.SRVs.set_dirty(); - } + dirtyShaderResourceStages(state_.ShaderStages, GetResourceCommon(pResource)); } pMappedResource->pData = MapDynamicBuffer(dynamic, current_seq_id, coherent_seq_id); @@ -188,9 +184,7 @@ class MTLD3D11ImmediateContext : public ImmediateContextBase { case D3D11_MAP_WRITE_NO_OVERWRITE: return E_INVALIDARG; case D3D11_MAP_WRITE_DISCARD: { - for (auto &stage : state_.ShaderStages) { - stage.SRVs.set_dirty(); - } + dirtyShaderResourceStages(state_.ShaderStages, GetResourceCommon(pResource)); pMappedResource->pData = MapDynamicBuffer(dynamic, current_seq_id, coherent_seq_id); pMappedResource->RowPitch = row_pitch; @@ -207,9 +201,7 @@ class MTLD3D11ImmediateContext : public ImmediateContextBase { case D3D11_MAP_READ_WRITE: return E_INVALIDARG; case D3D11_MAP_WRITE_DISCARD: { - for (auto &stage : state_.ShaderStages) { - stage.SRVs.set_dirty(); - } + dirtyShaderResourceStages(state_.ShaderStages, GetResourceCommon(pResource)); dynamic->updateImmediateName(current_seq_id, dynamic->allocate(coherent_seq_id), false); EmitST([allocation = dynamic->immediateName(), diff --git a/src/d3d11/d3d11_context_state.hpp b/src/d3d11/d3d11_context_state.hpp index 3484bda07..1426839cc 100644 --- a/src/d3d11/d3d11_context_state.hpp +++ b/src/d3d11/d3d11_context_state.hpp @@ -213,4 +213,30 @@ class MTLD3D11DeviceContextState } }; +/** On discard-map the backing rotates, so dirty only the stages that bind the + * mapped resource — the rest would re-encode their tables for nothing. */ +inline void +dirtyConstantBufferStages(D3D11StagesState &stages, D3D11ResourceCommon *resource) { + for (auto &stage : stages) { + for (const auto &[slot, entry] : stage.ConstantBuffers) { + if (entry.Buffer.ptr() == resource) { + stage.ConstantBuffers.set_dirty(); + break; + } + } + } +} + +inline void +dirtyShaderResourceStages(D3D11StagesState &stages, D3D11ResourceCommon *resource) { + for (auto &stage : stages) { + for (const auto &[slot, entry] : stage.SRVs) { + if (entry.SRV->resource_.ptr() == resource) { + stage.SRVs.set_dirty(); + break; + } + } + } +} + } // namespace dxmt \ No newline at end of file