From d904c3b2a711b9fde23bfb894d5695a1ddaf359d Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 15 Feb 2025 13:34:20 +0100 Subject: [PATCH] [dxbc] Track bindings with order-invariant atomic stores --- src/dxbc/dxbc_analysis.cpp | 36 ++++++++++++++++++++++++++++++------ src/dxbc/dxbc_analysis.h | 8 +++++--- src/dxbc/dxbc_compiler.cpp | 14 +++++++++++--- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/dxbc/dxbc_analysis.cpp b/src/dxbc/dxbc_analysis.cpp index dd4a51324dd6..bf1dd4af8725 100644 --- a/src/dxbc/dxbc_analysis.cpp +++ b/src/dxbc/dxbc_analysis.cpp @@ -30,26 +30,46 @@ namespace dxvk { switch (ins.opClass) { case DxbcInstClass::Atomic: { const uint32_t operandId = ins.dstCount - 1; - + if (ins.dst[operandId].type == DxbcOperandType::UnorderedAccessView) { const uint32_t registerId = ins.dst[operandId].idx[0].offset; m_analysis->uavInfos[registerId].accessAtomicOp = true; m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + + DxvkAtomicStore store = DxvkAtomicStore::None; + + switch (ins.op) { + case DxbcOpcode::AtomicAnd: store = DxvkAtomicStore::And; break; + case DxbcOpcode::AtomicOr: store = DxvkAtomicStore::Or; break; + case DxbcOpcode::AtomicXor: store = DxvkAtomicStore::Xor; break; + case DxbcOpcode::AtomicIAdd: store = DxvkAtomicStore::Add; break; + case DxbcOpcode::AtomicIMax: store = DxvkAtomicStore::IMax; break; + case DxbcOpcode::AtomicIMin: store = DxvkAtomicStore::IMin; break; + case DxbcOpcode::AtomicUMax: store = DxvkAtomicStore::UMax; break; + case DxbcOpcode::AtomicUMin: store = DxvkAtomicStore::UMin; break; + default: break; + } + + if (m_analysis->uavInfos[registerId].atomicStore == DxvkAtomicStore::None) + m_analysis->uavInfos[registerId].atomicStore = store; + + if (store == DxvkAtomicStore::None || m_analysis->uavInfos[registerId].atomicStore != store) + m_analysis->uavInfos[registerId].nonInvariantAccess = true; } } break; - + case DxbcInstClass::TextureSample: case DxbcInstClass::TextureGather: case DxbcInstClass::TextureQueryLod: case DxbcInstClass::VectorDeriv: { m_analysis->usesDerivatives = true; } break; - + case DxbcInstClass::ControlFlow: { if (ins.op == DxbcOpcode::Discard) m_analysis->usesKill = true; } break; - + case DxbcInstClass::BufferLoad: { uint32_t operandId = ins.op == DxbcOpcode::LdStructured ? 2 : 1; bool sparseFeedback = ins.dstCount == 2; @@ -58,16 +78,18 @@ namespace dxvk { const uint32_t registerId = ins.src[operandId].idx[0].offset; m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT; m_analysis->uavInfos[registerId].sparseFeedback |= sparseFeedback; + m_analysis->uavInfos[registerId].nonInvariantAccess = true; } else if (ins.src[operandId].type == DxbcOperandType::Resource) { const uint32_t registerId = ins.src[operandId].idx[0].offset; m_analysis->srvInfos[registerId].sparseFeedback |= sparseFeedback; } } break; - + case DxbcInstClass::BufferStore: { if (ins.dst[0].type == DxbcOperandType::UnorderedAccessView) { const uint32_t registerId = ins.dst[0].idx[0].offset; m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_WRITE_BIT; + m_analysis->uavInfos[registerId].nonInvariantAccess = true; } } break; @@ -75,13 +97,15 @@ namespace dxvk { const uint32_t registerId = ins.src[1].idx[0].offset; m_analysis->uavInfos[registerId].accessTypedLoad = true; m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT; + m_analysis->uavInfos[registerId].nonInvariantAccess = true; } break; case DxbcInstClass::TypedUavStore: { const uint32_t registerId = ins.dst[0].idx[0].offset; m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_WRITE_BIT; + m_analysis->uavInfos[registerId].nonInvariantAccess = true; } break; - + default: break; } diff --git a/src/dxbc/dxbc_analysis.h b/src/dxbc/dxbc_analysis.h index fcbc1ddadc33..c37c2bd5b397 100644 --- a/src/dxbc/dxbc_analysis.h +++ b/src/dxbc/dxbc_analysis.h @@ -17,9 +17,11 @@ namespace dxvk { * will be used to generate image types. */ struct DxbcUavInfo { - bool accessTypedLoad = false; - bool accessAtomicOp = false; - bool sparseFeedback = false; + bool accessTypedLoad = false; + bool accessAtomicOp = false; + bool sparseFeedback = false; + bool nonInvariantAccess = false; + DxvkAtomicStore atomicStore = DxvkAtomicStore::None; VkAccessFlags accessFlags = 0; }; diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 6ab3e9163345..49d16058a22c 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -1098,6 +1098,9 @@ namespace dxvk { : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; binding.access = m_analysis->uavInfos[registerId].accessFlags; + if (!m_analysis->uavInfos[registerId].nonInvariantAccess) + binding.storeOp = m_analysis->uavInfos[registerId].atomicStore; + if (!(binding.access & VK_ACCESS_SHADER_WRITE_BIT)) m_module.decorate(varId, spv::DecorationNonWritable); if (!(binding.access & VK_ACCESS_SHADER_READ_BIT)) @@ -1234,9 +1237,14 @@ namespace dxvk { : (isUav ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER); binding.viewType = VK_IMAGE_VIEW_TYPE_MAX_ENUM; binding.resourceBinding = bindingId; - binding.access = isUav - ? m_analysis->uavInfos[registerId].accessFlags - : VkAccessFlags(VK_ACCESS_SHADER_READ_BIT); + binding.access = VK_ACCESS_SHADER_READ_BIT; + + if (isUav) { + binding.access = m_analysis->uavInfos[registerId].accessFlags; + + if (!m_analysis->uavInfos[registerId].nonInvariantAccess) + binding.storeOp = m_analysis->uavInfos[registerId].atomicStore; + } if (useRawSsbo || isUav) { if (!(binding.access & VK_ACCESS_SHADER_WRITE_BIT))