From d5b68b364208c4c203301263d4fda98afa77d124 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 22 Aug 2022 03:38:12 +0200 Subject: [PATCH] [dxbc] Implement gather operations with sparse feedback --- src/dxbc/dxbc_compiler.cpp | 95 +++++++++++++++++++++++++++++++------- src/dxbc/dxbc_compiler.h | 17 ++++++- 2 files changed, 94 insertions(+), 18 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 98abfc8b6..d6a135d3e 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -3386,6 +3386,7 @@ namespace dxvk { void DxbcCompiler::emitTextureGather(const DxbcShaderInstruction& ins) { // Gather4 takes the following operands: // (dst0) The destination register + // (dst1) The residency code for sparse ops // (src0) Texture coordinates // (src1) The texture itself // (src2) The sampler, with a component selector @@ -3396,7 +3397,9 @@ namespace dxvk { // 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; + || ins.op == DxbcOpcode::Gather4PoC + || ins.op == DxbcOpcode::Gather4PoS + || ins.op == DxbcOpcode::Gather4PoCS; const DxbcRegister& texCoordReg = ins.src[0]; const DxbcRegister& textureReg = ins.src[1 + isExtendedGather]; @@ -3415,8 +3418,10 @@ namespace dxvk { // Load reference value for depth-compare operations const bool isDepthCompare = ins.op == DxbcOpcode::Gather4C - || ins.op == DxbcOpcode::Gather4PoC; - + || ins.op == DxbcOpcode::Gather4PoC + || ins.op == DxbcOpcode::Gather4CS + || ins.op == DxbcOpcode::Gather4PoCS; + const DxbcRegisterValue referenceValue = isDepthCompare ? emitRegisterLoad(ins.src[3 + isExtendedGather], DxbcRegMask(true, false, false, false)) @@ -3424,7 +3429,8 @@ namespace dxvk { // Accumulate additional image operands. SpirvImageOperands imageOperands; - + imageOperands.sparse = ins.dstCount == 2; + if (isExtendedGather) { m_module.enableCapability(spv::CapabilityImageGatherExtended); @@ -3445,30 +3451,41 @@ namespace dxvk { getVectorTypeId({ DxbcScalarType::Sint32, imageLayerDim }), imageLayerDim, offsetIds.data()); } - + // Gathering texels always returns a four-component // vector, even for the depth-compare variants. uint32_t sampledImageId = emitLoadSampledImage(texture, sampler, isDepthCompare); - DxbcRegisterValue result; - result.type.ctype = texture.sampledType; - result.type.ccount = 4; - + DxbcVectorType texelType; + texelType.ctype = texture.sampledType; + texelType.ccount = 4; + + uint32_t texelTypeId = getVectorTypeId(texelType); + uint32_t resultTypeId = texelTypeId; + uint32_t resultId = 0; + + if (imageOperands.sparse) + resultTypeId = getSparseResultTypeId(texelTypeId); + switch (ins.op) { // Simple image gather operation case DxbcOpcode::Gather4: - case DxbcOpcode::Gather4Po: { - result.id = m_module.opImageGather( - getVectorTypeId(result.type), sampledImageId, coord.id, + case DxbcOpcode::Gather4S: + case DxbcOpcode::Gather4Po: + case DxbcOpcode::Gather4PoS: { + resultId = m_module.opImageGather( + resultTypeId, sampledImageId, coord.id, m_module.consti32(samplerReg.swizzle[0]), imageOperands); } break; // Depth-compare operation case DxbcOpcode::Gather4C: - case DxbcOpcode::Gather4PoC: { - result.id = m_module.opImageDrefGather( - getVectorTypeId(result.type), sampledImageId, coord.id, + case DxbcOpcode::Gather4CS: + case DxbcOpcode::Gather4PoC: + case DxbcOpcode::Gather4PoCS: { + resultId = m_module.opImageDrefGather( + resultTypeId, sampledImageId, coord.id, referenceValue.id, imageOperands); } break; @@ -3478,13 +3495,23 @@ namespace dxvk { ins.op)); return; } - + + // If necessary, deal with the sparse result + DxbcRegisterValue result; + result.type = texelType; + result.id = imageOperands.sparse + ? emitExtractSparseTexel(texelTypeId, resultId) + : resultId; + // Swizzle components using the texture swizzle // and the destination operand's write mask result = emitRegisterSwizzle(result, textureReg.swizzle, ins.dst[0].mask); emitRegisterStore(ins.dst[0], result); + + if (imageOperands.sparse) + emitStoreSparseFeedback(ins.dst[1], resultId); } @@ -4549,6 +4576,33 @@ namespace dxvk { } + uint32_t DxbcCompiler::emitExtractSparseTexel( + uint32_t texelTypeId, + uint32_t resultId) { + uint32_t index = 1; + + return m_module.opCompositeExtract( + texelTypeId, resultId, 1, &index); + } + + + void DxbcCompiler::emitStoreSparseFeedback( + const DxbcRegister& feedbackRegister, + uint32_t resultId) { + if (feedbackRegister.type != DxbcOperandType::Null) { + uint32_t index = 0; + + DxbcRegisterValue result; + result.type = { DxbcScalarType::Uint32, 1 }; + result.id = m_module.opCompositeExtract( + getScalarTypeId(DxbcScalarType::Uint32), + resultId, 1, &index); + + emitRegisterStore(feedbackRegister, result); + } + } + + DxbcRegisterValue DxbcCompiler::emitDstOperandModifiers( DxbcRegisterValue value, DxbcOpModifiers modifiers) { @@ -7592,6 +7646,15 @@ namespace dxvk { } + uint32_t DxbcCompiler::getSparseResultTypeId(uint32_t baseType) { + m_module.enableCapability(spv::CapabilitySparseResidency); + + uint32_t uintType = getScalarTypeId(DxbcScalarType::Uint32); + std::array typeIds = { uintType, baseType }; + return m_module.defStructType(typeIds.size(), typeIds.data()); + } + + uint32_t DxbcCompiler::getPerVertexBlockId() { uint32_t t_f32 = m_module.defFloatType(32); uint32_t t_f32_v4 = m_module.defVectorType(t_f32, 4); diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 0a192e08e..17fb7d87e 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -882,6 +882,16 @@ namespace dxvk { DxbcRegisterValue value, DxbcOpModifiers modifiers); + /////////////////////////// + // Sparse feedback methods + uint32_t emitExtractSparseTexel( + uint32_t texelTypeId, + uint32_t resultId); + + void emitStoreSparseFeedback( + const DxbcRegister& feedbackRegister, + uint32_t resultId); + //////////////////////////////// // Pointer manipulation methods DxbcRegisterPointer emitArrayAccess( @@ -1149,7 +1159,7 @@ namespace dxvk { uint32_t emitSamplePosArray(); void emitFloatControl(); - + /////////////////////////////// // Variable definition methods uint32_t emitNewVariable( @@ -1223,7 +1233,10 @@ namespace dxvk { uint32_t getPointerTypeId( const DxbcRegisterInfo& type); - + + uint32_t getSparseResultTypeId( + uint32_t baseType); + uint32_t getPerVertexBlockId(); uint32_t getFunctionId(