diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index af0cbc94e..050a8d5da 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -85,6 +85,9 @@ namespace dxvk { case DxbcInstClass::GeometryEmit: return this->emitGeometryEmit(ins); + case DxbcInstClass::Interpolate: + return this->emitInterpolate(ins); + case DxbcInstClass::TextureQuery: return this->emitTextureQuery(ins); @@ -2253,6 +2256,55 @@ namespace dxvk { } + void DxbcCompiler::emitInterpolate(const DxbcShaderInstruction& ins) { + // The SPIR-V instructions operate on input variable pointers, + // which are all declared as four-component float vectors. + const uint32_t registerId = ins.src[0].idx[0].offset; + + DxbcRegisterValue result; + result.type.ctype = DxbcScalarType::Float32; + result.type.ccount = 4; + + switch (ins.op) { + case DxbcOpcode::EvalCentroid: { + result.id = m_module.opInterpolateAtCentroid( + getVectorTypeId(result.type), + m_vRegs.at(registerId)); + } break; + + case DxbcOpcode::EvalSampleIndex: { + const DxbcRegisterValue sampleIndex = emitRegisterLoad( + ins.src[1], DxbcRegMask(true, false, false, false)); + + result.id = m_module.opInterpolateAtSample( + getVectorTypeId(result.type), + m_vRegs.at(registerId), + sampleIndex.id); + } break; + + case DxbcOpcode::EvalSnapped: { + const DxbcRegisterValue offset = emitRegisterLoad( + ins.src[1], DxbcRegMask(true, true, false, false)); + + result.id = m_module.opInterpolateAtOffset( + getVectorTypeId(result.type), + m_vRegs.at(registerId), + offset.id); + } break; + + default: + Logger::warn(str::format( + "DxbcCompiler: Unhandled instruction: ", + ins.op)); + return; + } + + result = emitRegisterSwizzle(result, + ins.src[0].swizzle, ins.dst[0].mask); + emitRegisterStore(ins.dst[0], result); + } + + void DxbcCompiler::emitTextureQuery(const DxbcShaderInstruction& ins) { // resinfo has three operands: // (dst0) The destination register @@ -4813,8 +4865,8 @@ namespace dxvk { void DxbcCompiler::emitPsInit() { - m_module.enableCapability( - spv::CapabilityDerivativeControl); + m_module.enableCapability(spv::CapabilityDerivativeControl); + m_module.enableCapability(spv::CapabilityInterpolationFunction); m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeOriginUpperLeft); diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 1b98da769..ca146154e 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -527,6 +527,9 @@ namespace dxvk { void emitConvertFloat16( const DxbcShaderInstruction& ins); + void emitInterpolate( + const DxbcShaderInstruction& ins); + void emitTextureQuery( const DxbcShaderInstruction& ins); diff --git a/src/dxbc/dxbc_defs.cpp b/src/dxbc/dxbc_defs.cpp index 9e9dd3845..983dd4e07 100644 --- a/src/dxbc/dxbc_defs.cpp +++ b/src/dxbc/dxbc_defs.cpp @@ -972,11 +972,22 @@ namespace dxvk { /* FtoD */ { }, /* EvalSnapped */ - { }, + { 3, DxbcInstClass::Interpolate, { + { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + } }, /* EvalSampleIndex */ - { }, + { 3, DxbcInstClass::Interpolate, { + { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 }, + } }, /* EvalCentroid */ - { }, + { 2, DxbcInstClass::Interpolate, { + { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + } }, /* DclGsInstanceCount */ { }, }}; diff --git a/src/dxbc/dxbc_defs.h b/src/dxbc/dxbc_defs.h index 8826add5b..ae0487807 100644 --- a/src/dxbc/dxbc_defs.h +++ b/src/dxbc/dxbc_defs.h @@ -41,6 +41,7 @@ namespace dxvk { BufferLoad, ///< Structured or raw buffer load BufferStore, ///< Structured or raw buffer store ConvertFloat16, ///< 16-bit float packing/unpacking + Interpolate, ///< Input attribute interpolation TextureQuery, ///< Texture query instruction TextureQueryLod, ///< Texture LOD query instruction TextureQueryMs, ///< Multisample texture query diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index dd4367233..756a04410 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -2306,6 +2306,55 @@ namespace dxvk { } + uint32_t SpirvModule::opInterpolateAtCentroid( + uint32_t resultType, + uint32_t interpolant) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpExtInst, 6); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(m_instExtGlsl450); + m_code.putWord(spv::GLSLstd450InterpolateAtCentroid); + m_code.putWord(interpolant); + return resultId; + } + + + uint32_t SpirvModule::opInterpolateAtSample( + uint32_t resultType, + uint32_t interpolant, + uint32_t sample) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpExtInst, 7); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(m_instExtGlsl450); + m_code.putWord(spv::GLSLstd450InterpolateAtSample); + m_code.putWord(interpolant); + m_code.putWord(sample); + return resultId; + } + + + uint32_t SpirvModule::opInterpolateAtOffset( + uint32_t resultType, + uint32_t interpolant, + uint32_t offset) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpExtInst, 7); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(m_instExtGlsl450); + m_code.putWord(spv::GLSLstd450InterpolateAtOffset); + m_code.putWord(interpolant); + m_code.putWord(offset); + return resultId; + } + + uint32_t SpirvModule::opImageRead( uint32_t resultType, uint32_t image, diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index 68bc7f588..660949f95 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -808,6 +808,20 @@ namespace dxvk { uint32_t pointerId, uint32_t valueId); + uint32_t opInterpolateAtCentroid( + uint32_t resultType, + uint32_t interpolant); + + uint32_t opInterpolateAtSample( + uint32_t resultType, + uint32_t interpolant, + uint32_t sample); + + uint32_t opInterpolateAtOffset( + uint32_t resultType, + uint32_t interpolant, + uint32_t offset); + uint32_t opImageRead( uint32_t resultType, uint32_t image,