diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 076d4e75..66ac72f3 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -88,6 +88,9 @@ namespace dxvk { case DxbcInstClass::TextureQuery: return this->emitTextureQuery(ins); + case DxbcInstClass::TextureQueryLod: + return this->emitTextureQueryLod(ins); + case DxbcInstClass::TextureQueryMs: return this->emitTextureQueryMs(ins); @@ -2283,6 +2286,52 @@ namespace dxvk { } + void DxbcCompiler::emitTextureQueryLod(const DxbcShaderInstruction& ins) { + // All sample instructions have at least these operands: + // (dst0) The destination register + // (src0) Texture coordinates + // (src1) The texture itself + // (src2) The sampler object + const DxbcRegister& texCoordReg = ins.src[0]; + const DxbcRegister& textureReg = ins.src[1]; + const DxbcRegister& samplerReg = ins.src[2]; + + // Texture and sampler register IDs + const uint32_t textureId = textureReg.idx[0].offset; + const uint32_t samplerId = samplerReg.idx[0].offset; + + // Load texture coordinates + const uint32_t imageCoordDim = getTexCoordDim( + m_textures.at(textureId).imageInfo); + + const DxbcRegisterValue coord = emitRegisterLoad( + texCoordReg, DxbcRegMask::firstN(imageCoordDim)); + + // Query the LOD. The result is a two-dimensional float32 + // vector containing the mip level and virtual LOD numbers. + const uint32_t sampledImageId = emitLoadSampledImage( + m_textures.at(textureId), m_samplers.at(samplerId), false); + + const uint32_t queriedLodId = m_module.opImageQueryLod( + getVectorTypeId({ DxbcScalarType::Float32, 2 }), + sampledImageId, coord.id); + + // Build the result array vector by filling up + // the remaining two components with zeroes. + const uint32_t zero = m_module.constf32(0.0f); + const std::array resultIds + = {{ queriedLodId, zero, zero }}; + + DxbcRegisterValue result; + result.type = DxbcVectorType { DxbcScalarType::Float32, 4 }; + result.id = m_module.opCompositeConstruct( + getVectorTypeId(result.type), + resultIds.size(), resultIds.data()); + + emitRegisterStore(ins.dst[0], result); + } + + void DxbcCompiler::emitTextureQueryMs(const DxbcShaderInstruction& ins) { // sampleinfo has two operands: // (dst0) The destination register @@ -2624,11 +2673,6 @@ namespace dxvk { ? emitRegisterLoad(ins.src[3], DxbcRegMask(true, false, false, false)) : DxbcRegisterValue(); - // Determine the sampled image type based on the opcode. - const uint32_t sampledImageType = isDepthCompare - ? m_module.defSampledImageType(m_textures.at(textureId).depthTypeId) - : m_module.defSampledImageType(m_textures.at(textureId).colorTypeId); - // Accumulate additional image operands. These are // not part of the actual operand token in SPIR-V. SpirvImageOperands imageOperands; @@ -2647,14 +2691,9 @@ namespace dxvk { } // Combine the texture and the sampler into a sampled image - const uint32_t sampledImageId = m_module.opSampledImage( - sampledImageType, - m_module.opLoad( - m_textures.at(textureId).imageTypeId, - m_textures.at(textureId).varId), - m_module.opLoad( - m_samplers.at(samplerId).typeId, - m_samplers.at(samplerId).varId)); + const uint32_t sampledImageId = emitLoadSampledImage( + m_textures.at(textureId), m_samplers.at(samplerId), + isDepthCompare); // Sampling an image always returns a four-component // vector, whereas depth-compare ops return a scalar. @@ -3501,6 +3540,20 @@ namespace dxvk { } + uint32_t DxbcCompiler::emitLoadSampledImage( + const DxbcShaderResource& textureResource, + const DxbcSampler& samplerResource, + bool isDepthCompare) { + const uint32_t sampledImageType = isDepthCompare + ? m_module.defSampledImageType(textureResource.depthTypeId) + : m_module.defSampledImageType(textureResource.colorTypeId); + + return m_module.opSampledImage(sampledImageType, + m_module.opLoad(textureResource.imageTypeId, textureResource.varId), + m_module.opLoad(samplerResource.typeId, samplerResource.varId)); + } + + DxbcRegisterPointer DxbcCompiler::emitGetTempPtr( const DxbcRegister& operand) { // r# regs are indexed as follows: diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 0e8c3e9b..e9c257c9 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -524,6 +524,9 @@ namespace dxvk { void emitTextureQuery( const DxbcShaderInstruction& ins); + void emitTextureQueryLod( + const DxbcShaderInstruction& ins); + void emitTextureQueryMs( const DxbcShaderInstruction& ins); @@ -659,6 +662,13 @@ namespace dxvk { DxbcRegisterValue value, DxbcOpModifiers modifiers); + /////////////////////////////////////// + // Image register manipulation methods + uint32_t emitLoadSampledImage( + const DxbcShaderResource& textureResource, + const DxbcSampler& samplerResource, + bool isDepthCompare); + //////////////////////// // Address load methods DxbcRegisterPointer emitGetTempPtr( diff --git a/src/dxbc/dxbc_defs.cpp b/src/dxbc/dxbc_defs.cpp index 15849d32..314afcb1 100644 --- a/src/dxbc/dxbc_defs.cpp +++ b/src/dxbc/dxbc_defs.cpp @@ -536,7 +536,12 @@ namespace dxvk { /* Reserved0 */ { 0, DxbcInstClass::Undefined }, /* Lod */ - { }, + { 4, DxbcInstClass::TextureQueryLod, { + { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, + } }, /* Gather4 */ { 4, DxbcInstClass::TextureGather, { { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, diff --git a/src/dxbc/dxbc_defs.h b/src/dxbc/dxbc_defs.h index 36061428..8826add5 100644 --- a/src/dxbc/dxbc_defs.h +++ b/src/dxbc/dxbc_defs.h @@ -42,6 +42,7 @@ namespace dxvk { BufferStore, ///< Structured or raw buffer store ConvertFloat16, ///< 16-bit float packing/unpacking TextureQuery, ///< Texture query instruction + TextureQueryLod, ///< Texture LOD query instruction TextureQueryMs, ///< Multisample texture query TextureFetch, ///< Texture fetch instruction TextureGather, ///< Texture gather instruction diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index 14a8e26b..3de4dbac 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -2400,6 +2400,21 @@ namespace dxvk { } + uint32_t SpirvModule::opImageQueryLod( + uint32_t resultType, + uint32_t sampledImage, + uint32_t coordinates) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpImageQueryLod, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(sampledImage); + m_code.putWord(coordinates); + return resultId; + } + + uint32_t SpirvModule::opImageQuerySamples( uint32_t resultType, uint32_t image) { diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index d4d02935..c036c6ea 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -840,6 +840,11 @@ namespace dxvk { uint32_t resultType, uint32_t image); + uint32_t opImageQueryLod( + uint32_t resultType, + uint32_t sampledImage, + uint32_t coordinates); + uint32_t opImageQuerySamples( uint32_t resultType, uint32_t image);