diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 8d918b24..b3b83136 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -41,6 +41,13 @@ namespace dxvk { m_oRegs.at(i) = 0; } + // Clear spec constants + for (uint32_t i = 0; i < m_specConstants.size(); i++) { + m_specConstants.at(i) = DxbcRegisterValue { + DxbcVectorType { DxbcScalarType::Uint32, 0 }, + 0 }; + } + this->emitInit(); } @@ -4557,15 +4564,21 @@ namespace dxvk { DxbcRegisterValue DxbcCompiler::emitQueryTextureSamples( const DxbcRegister& resource) { - const DxbcBufferInfo info = getBufferInfo(resource); - - DxbcRegisterValue result; - result.type.ctype = DxbcScalarType::Uint32; - result.type.ccount = 1; - result.id = m_module.opImageQuerySamples( - getVectorTypeId(result.type), - m_module.opLoad(info.typeId, info.varId)); - return result; + if (resource.type == DxbcOperandType::Rasterizer) { + // SPIR-V has no gl_NumSamples equivalent, so we have + // to work around it using a specialization constant + return getSpecConstant(DxvkSpecConstantId::RasterizerSampleCount); + } else { + DxbcBufferInfo info = getBufferInfo(resource); + + DxbcRegisterValue result; + result.type.ctype = DxbcScalarType::Uint32; + result.type.ccount = 1; + result.id = m_module.opImageQuerySamples( + getVectorTypeId(result.type), + m_module.opLoad(info.typeId, info.varId)); + return result; + } } @@ -4778,6 +4791,43 @@ namespace dxvk { } + DxbcRegisterValue DxbcCompiler::getSpecConstant(DxvkSpecConstantId specId) { + const uint32_t specIdOffset = uint32_t(specId) - uint32_t(DxvkSpecConstantId::SpecConstantIdMin); + + // Look up spec constant in the array + DxbcRegisterValue value = m_specConstants.at(specIdOffset); + + if (value.id != 0) + return value; + + // Declare a new specialization constant if needed + DxbcSpecConstant info = getSpecConstantProperties(specId); + + value.type.ctype = info.ctype; + value.type.ccount = info.ccount; + value.id = m_module.specConst32( + getVectorTypeId(value.type), + info.value); + + m_module.decorateSpecId(value.id, uint32_t(specId)); + m_module.setDebugName(value.id, info.name); + + m_specConstants.at(specIdOffset) = value; + return value; + } + + + DxbcSpecConstant DxbcCompiler::getSpecConstantProperties(DxvkSpecConstantId specId) { + static const std::array s_specConstants = {{ + { DxbcScalarType::Uint32, 1, 1, "RasterizerSampleCount" }, + }}; + + return s_specConstants.at(uint32_t(specId) - uint32_t(DxvkSpecConstantId::SpecConstantIdMin)); + } + + void DxbcCompiler::emitInputSetup() { // Copy all defined v# registers into the input array const uint32_t vecTypeId = m_module.defVectorType(m_module.defFloatType(32), 4); diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 7f82498a..b734d4ec 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -96,6 +96,20 @@ namespace dxvk { }; + /** + * \brief Specialization constant properties + * + * Stores the name, data type and initial + * value of a specialization constant. + */ + struct DxbcSpecConstant { + DxbcScalarType ctype; + uint32_t ccount; + uint32_t value; + const char* name; + }; + + /** * \brief Vertex shader-specific structure */ @@ -384,6 +398,13 @@ namespace dxvk { // currently active if-else blocks and loops. std::vector m_controlFlowBlocks; + /////////////////////////////////////////////// + // Specialization constants. These are defined + // as needed by the getSpecConstant method. + std::array m_specConstants; + /////////////////////////////////////////////////////////// // Array of input values. Since v# registers are indexable // in DXBC, we need to copy them into an array first. @@ -848,6 +869,14 @@ namespace dxvk { const DxbcRegister& reg, DxbcRegisterValue value); + //////////////////////////////////////// + // Spec constant declaration and access + DxbcRegisterValue getSpecConstant( + DxvkSpecConstantId specId); + + DxbcSpecConstant getSpecConstantProperties( + DxvkSpecConstantId specId); + //////////////////////////// // Input/output preparation void emitInputSetup();