diff --git a/src/dxbc/dxbc_analysis.cpp b/src/dxbc/dxbc_analysis.cpp index a5bf4fc19..2a6747b05 100644 --- a/src/dxbc/dxbc_analysis.cpp +++ b/src/dxbc/dxbc_analysis.cpp @@ -108,6 +108,47 @@ namespace dxvk { m_analysis->uavInfos[registerId].nonInvariantAccess = true; } break; + case DxbcInstClass::Declaration: { + switch (ins.op) { + case DxbcOpcode::DclConstantBuffer: { + uint32_t registerId = ins.dst[0].idx[0].offset; + + if (registerId < DxbcConstBufBindingCount) + m_analysis->bindings.cbvMask |= 1u << registerId; + } break; + + case DxbcOpcode::DclSampler: { + uint32_t registerId = ins.dst[0].idx[0].offset; + + if (registerId < DxbcSamplerBindingCount) + m_analysis->bindings.samplerMask |= 1u << registerId; + } break; + + case DxbcOpcode::DclResource: + case DxbcOpcode::DclResourceRaw: + case DxbcOpcode::DclResourceStructured: { + uint32_t registerId = ins.dst[0].idx[0].offset; + + uint32_t idx = registerId / 64u; + uint32_t bit = registerId % 64u; + + if (registerId < DxbcResourceBindingCount) + m_analysis->bindings.srvMask[idx] |= uint64_t(1u) << bit; + } break; + + case DxbcOpcode::DclUavTyped: + case DxbcOpcode::DclUavRaw: + case DxbcOpcode::DclUavStructured: { + uint32_t registerId = ins.dst[0].idx[0].offset; + + if (registerId < DxbcUavBindingCount) + m_analysis->bindings.uavMask |= uint64_t(1u) << registerId; + } break; + + default: ; + } + } break; + default: break; } diff --git a/src/dxbc/dxbc_analysis.h b/src/dxbc/dxbc_analysis.h index fa589f4fd..64e987038 100644 --- a/src/dxbc/dxbc_analysis.h +++ b/src/dxbc/dxbc_analysis.h @@ -53,6 +53,8 @@ namespace dxvk { DxbcClipCullInfo clipCullIn; DxbcClipCullInfo clipCullOut; + + DxbcBindingMask bindings = { }; bool usesDerivatives = false; bool usesKill = false; diff --git a/src/dxbc/dxbc_common.cpp b/src/dxbc/dxbc_common.cpp index d150c585b..db3d71529 100644 --- a/src/dxbc/dxbc_common.cpp +++ b/src/dxbc/dxbc_common.cpp @@ -10,9 +10,8 @@ namespace dxvk { case DxbcProgramType::HullShader : return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; case DxbcProgramType::DomainShader : return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; case DxbcProgramType::ComputeShader : return VK_SHADER_STAGE_COMPUTE_BIT; + default: throw DxvkError("DxbcProgramInfo::shaderStage: Unsupported program type"); } - - throw DxvkError("DxbcProgramInfo::shaderStage: Unsupported program type"); } @@ -24,9 +23,8 @@ namespace dxvk { case DxbcProgramType::HullShader : return spv::ExecutionModelTessellationControl; case DxbcProgramType::DomainShader : return spv::ExecutionModelTessellationEvaluation; case DxbcProgramType::ComputeShader : return spv::ExecutionModelGLCompute; + default: throw DxvkError("DxbcProgramInfo::executionModel: Unsupported program type"); } - - throw DxvkError("DxbcProgramInfo::executionModel: Unsupported program type"); } -} \ No newline at end of file +} diff --git a/src/dxbc/dxbc_common.h b/src/dxbc/dxbc_common.h index 9c490d62c..d9d420767 100644 --- a/src/dxbc/dxbc_common.h +++ b/src/dxbc/dxbc_common.h @@ -17,7 +17,11 @@ namespace dxvk { HullShader = 3, DomainShader = 4, ComputeShader = 5, + + Count }; + + using DxbcProgramTypeFlags = Flags; /** diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index f0f362334..9e58e6497 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -237,6 +237,7 @@ namespace dxvk { case DxbcProgramType::GeometryShader: this->emitGsFinalize(); break; case DxbcProgramType::PixelShader: this->emitPsFinalize(); break; case DxbcProgramType::ComputeShader: this->emitCsFinalize(); break; + default: throw DxvkError("Invalid shader stage"); } // Emit float control mode if the extension is supported @@ -6138,7 +6139,7 @@ namespace dxvk { case DxbcProgramType::HullShader: emitHsSystemValueStore(sv, mask, value); break; case DxbcProgramType::DomainShader: emitDsSystemValueStore(sv, mask, value); break; case DxbcProgramType::PixelShader: emitPsSystemValueStore(sv, mask, value); break; - case DxbcProgramType::ComputeShader: break; + default: break; } } } @@ -6822,6 +6823,7 @@ namespace dxvk { case DxbcProgramType::GeometryShader: emitGsInit(); break; case DxbcProgramType::PixelShader: emitPsInit(); break; case DxbcProgramType::ComputeShader: emitCsInit(); break; + default: throw DxvkError("Invalid shader stage"); } } diff --git a/src/dxbc/dxbc_module.cpp b/src/dxbc/dxbc_module.cpp index d406bf292..16e37ebbb 100644 --- a/src/dxbc/dxbc_module.cpp +++ b/src/dxbc/dxbc_module.cpp @@ -42,7 +42,7 @@ namespace dxvk { Rc DxbcModule::compile( const DxbcModuleInfo& moduleInfo, - const std::string& fileName) const { + const std::string& fileName) { if (m_shexChunk == nullptr) throw DxvkError("DxbcModule::compile: No SHDR/SHEX chunk"); @@ -54,6 +54,8 @@ namespace dxvk { m_psgnChunk, analysisInfo); this->runAnalyzer(analyzer, m_shexChunk->slice()); + + m_bindings = std::make_optional(analysisInfo.bindings); DxbcCompiler compiler( fileName, moduleInfo, @@ -62,7 +64,7 @@ namespace dxvk { m_psgnChunk, analysisInfo); this->runCompiler(compiler, m_shexChunk->slice()); - + return compiler.finalize(); } diff --git a/src/dxbc/dxbc_module.h b/src/dxbc/dxbc_module.h index 7609e2322..7d6088bae 100644 --- a/src/dxbc/dxbc_module.h +++ b/src/dxbc/dxbc_module.h @@ -7,6 +7,7 @@ #include "dxbc_header.h" #include "dxbc_modinfo.h" #include "dxbc_reader.h" +#include "dxbc_util.h" // References used for figuring out DXBC: // - https://github.com/tgjones/slimshader-cpp @@ -41,7 +42,16 @@ namespace dxvk { return m_shexChunk->programInfo(); } - + + /** + * \brief Queries shader binding mask + * + * Only valid after successfully compiling the shader. + */ + std::optional bindings() const { + return m_bindings; + } + /** * \brief Input and output signature chunks * @@ -50,7 +60,7 @@ namespace dxvk { */ Rc isgn() const { return m_isgnChunk; } Rc osgn() const { return m_osgnChunk; } - + /** * \brief Compiles DXBC shader to SPIR-V module * @@ -61,7 +71,7 @@ namespace dxvk { */ Rc compile( const DxbcModuleInfo& moduleInfo, - const std::string& fileName) const; + const std::string& fileName); /** * \brief Compiles a pass-through geometry shader @@ -85,6 +95,8 @@ namespace dxvk { Rc m_osgnChunk; Rc m_psgnChunk; Rc m_shexChunk; + + std::optional m_bindings; void runAnalyzer( DxbcAnalyzer& analyzer, diff --git a/src/dxbc/dxbc_util.h b/src/dxbc/dxbc_util.h index 04bec752a..53394c2a9 100644 --- a/src/dxbc/dxbc_util.h +++ b/src/dxbc/dxbc_util.h @@ -33,6 +33,43 @@ namespace dxvk { }; + /** + * \brief Shader binding mask + * + * Stores a bit masks of resource bindings + * that are accessed by any given shader. + */ + struct DxbcBindingMask { + uint32_t cbvMask = 0u; + uint32_t samplerMask = 0u; + uint64_t uavMask = 0u; + std::array srvMask = { }; + + void reset() { + cbvMask = 0u; + samplerMask = 0u; + uavMask = 0u; + srvMask = { }; + } + + bool empty() const { + uint64_t mask = (uint64_t(cbvMask) | uint64_t(samplerMask) << 32u) + | (uavMask | srvMask[0] | srvMask[1]); + return !mask; + } + + DxbcBindingMask operator & (const DxbcBindingMask& other) const { + DxbcBindingMask result = *this; + result.cbvMask &= other.cbvMask; + result.samplerMask &= other.samplerMask; + result.uavMask &= other.uavMask; + result.srvMask[0] &= other.srvMask[0]; + result.srvMask[1] &= other.srvMask[1]; + return result; + } + }; + + /** * \brief Computes first binding index for a given stage * @@ -124,4 +161,4 @@ namespace dxvk { uint32_t primitiveVertexCount( DxbcPrimitive primitive); -} \ No newline at end of file +}