diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index c4d092f5a..0cdb391ec 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -2436,11 +2436,16 @@ namespace dxvk { // (src2) The sampler, with a component selector // Gather4C takes the following additional operand: // (src3) The depth reference value + // The Gather4Po variants take an additional operand + // which defines an extended constant offset. // TODO reduce code duplication by moving some common code // in both sample() and gather() into separate methods + const bool isExtendedGather = ins.op == DxbcOpcode::Gather4Po + || ins.op == DxbcOpcode::Gather4PoC; + const DxbcRegister& texCoordReg = ins.src[0]; - const DxbcRegister& textureReg = ins.src[1]; - const DxbcRegister& samplerReg = ins.src[2]; + const DxbcRegister& textureReg = ins.src[1 + isExtendedGather]; + const DxbcRegister& samplerReg = ins.src[2 + isExtendedGather]; // Texture and sampler register IDs const uint32_t textureId = textureReg.idx[0].offset; @@ -2459,10 +2464,12 @@ namespace dxvk { DxbcRegisterValue coord = emitRegisterLoad(texCoordReg, coordArrayMask); // Load reference value for depth-compare operations - const bool isDepthCompare = ins.op == DxbcOpcode::Gather4C; + const bool isDepthCompare = ins.op == DxbcOpcode::Gather4C + || ins.op == DxbcOpcode::Gather4PoC; const DxbcRegisterValue referenceValue = isDepthCompare - ? emitRegisterLoad(ins.src[3], DxbcRegMask(true, false, false, false)) + ? emitRegisterLoad(ins.src[3 + isExtendedGather], + DxbcRegMask(true, false, false, false)) : DxbcRegisterValue(); if (isDepthCompare && m_options.packDrefValueIntoCoordinates) { @@ -2484,7 +2491,15 @@ namespace dxvk { // Accumulate additional image operands. SpirvImageOperands imageOperands; - if (ins.sampleControls.u != 0 || ins.sampleControls.v != 0 || ins.sampleControls.w != 0) { + if (isExtendedGather) { + m_module.enableCapability(spv::CapabilityImageGatherExtended); + + DxbcRegisterValue gatherOffset = emitRegisterLoad( + ins.src[1], DxbcRegMask::firstN(imageLayerDim)); + + imageOperands.flags |= spv::ImageOperandsOffsetMask; + imageOperands.gOffset = gatherOffset.id; + } else if (ins.sampleControls.u != 0 || ins.sampleControls.v != 0 || ins.sampleControls.w != 0) { const std::array offsetIds = { imageLayerDim >= 1 ? m_module.consti32(ins.sampleControls.u) : 0, imageLayerDim >= 2 ? m_module.consti32(ins.sampleControls.v) : 0, diff --git a/src/dxbc/dxbc_defs.cpp b/src/dxbc/dxbc_defs.cpp index 8be6e7a81..876a93984 100644 --- a/src/dxbc/dxbc_defs.cpp +++ b/src/dxbc/dxbc_defs.cpp @@ -600,9 +600,22 @@ namespace dxvk { { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, } }, /* Gather4Po */ - { }, + { 5, DxbcInstClass::TextureGather, { + { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + } }, /* Gather4PoC */ - { }, + { 6, DxbcInstClass::TextureGather, { + { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + } }, /* Rcp */ { 2, DxbcInstClass::VectorAlu, { { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index fa1cea670..7875a22e2 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -933,6 +933,64 @@ namespace dxvk { } + uint32_t SpirvModule::opBitCount( + uint32_t resultType, + uint32_t operand) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpBitCount, 4); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(operand); + return resultId; + } + + + uint32_t SpirvModule::opFindILsb( + uint32_t resultType, + uint32_t operand) { + 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::GLSLstd450FindILsb); + m_code.putWord(operand); + return resultId; + } + + + uint32_t SpirvModule::opFindUMsb( + uint32_t resultType, + uint32_t operand) { + 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::GLSLstd450FindUMsb); + m_code.putWord(operand); + return resultId; + } + + + uint32_t SpirvModule::opFindSMsb( + uint32_t resultType, + uint32_t operand) { + 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::GLSLstd450FindSMsb); + m_code.putWord(operand); + return resultId; + } + + uint32_t SpirvModule::opBitFieldInsert( uint32_t resultType, uint32_t base, diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index 18b262106..60f735626 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -377,6 +377,22 @@ namespace dxvk { uint32_t resultType, uint32_t operand); + uint32_t opBitCount( + uint32_t resultType, + uint32_t operand); + + uint32_t opFindILsb( + uint32_t resultType, + uint32_t operand); + + uint32_t opFindUMsb( + uint32_t resultType, + uint32_t operand); + + uint32_t opFindSMsb( + uint32_t resultType, + uint32_t operand); + uint32_t opBitFieldInsert( uint32_t resultType, uint32_t base,