From 45461ee54e691739abfae2edc61771b359302119 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 24 Nov 2020 18:09:19 +0100 Subject: [PATCH] [dxbc] Use opSelect for unbound texel fetch instructions Generates less annoying code compared to control flow instructions, and drivers should be able to optimize away the texture instruction anyway since the bound state is a specialization constant. --- src/dxbc/dxbc_compiler.cpp | 74 +++++++++++++++++++++----------------- src/dxbc/dxbc_compiler.h | 7 ++++ 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 39051b1a2..6c84ee2dd 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -3395,15 +3395,6 @@ namespace dxvk { // Extract coordinates from address const DxbcRegisterValue coord = emitCalcTexCoord(address, imageType); - // Fetch texels only if the resource is actually bound - const uint32_t labelMerge = m_module.allocateId(); - const uint32_t labelBound = m_module.allocateId(); - const uint32_t labelUnbound = m_module.allocateId(); - - m_module.opSelectionMerge(labelMerge, spv::SelectionControlMaskNone); - m_module.opBranchConditional(m_textures.at(textureId).specId, labelBound, labelUnbound); - m_module.opLabel(labelBound); - // Reading a typed image or buffer view // always returns a four-component vector. const uint32_t imageId = m_module.opLoad( @@ -3423,32 +3414,15 @@ namespace dxvk { ins.src[1].swizzle, ins.dst[0].mask); // If the texture is not bound, return zeroes - m_module.opBranch(labelMerge); - m_module.opLabel(labelUnbound); - - DxbcRegisterValue zeroes = [&] { - switch (result.type.ctype) { - case DxbcScalarType::Float32: return emitBuildConstVecf32(0.0f, 0.0f, 0.0f, 0.0f, ins.dst[0].mask); - case DxbcScalarType::Uint32: return emitBuildConstVecu32(0u, 0u, 0u, 0u, ins.dst[0].mask); - case DxbcScalarType::Sint32: return emitBuildConstVeci32(0, 0, 0, 0, ins.dst[0].mask); - default: throw DxvkError("DxbcCompiler: Invalid scalar type"); - } - }(); - - m_module.opBranch(labelMerge); - m_module.opLabel(labelMerge); - - // Merge the result with a phi function - const std::array phiLabels = {{ - { result.id, labelBound }, - { zeroes.id, labelUnbound }, - }}; + DxbcRegisterValue bound; + bound.type = { DxbcScalarType::Bool, 1 }; + bound.id = m_textures.at(textureId).specId; DxbcRegisterValue mergedResult; mergedResult.type = result.type; - mergedResult.id = m_module.opPhi( - getVectorTypeId(mergedResult.type), - phiLabels.size(), phiLabels.data()); + mergedResult.id = m_module.opSelect(getVectorTypeId(mergedResult.type), + emitBuildVector(bound, result.type.ccount).id, result.id, + emitBuildZeroVector(result.type).id); emitRegisterStore(ins.dst[0], mergedResult); } @@ -4433,6 +4407,42 @@ namespace dxvk { } + DxbcRegisterValue DxbcCompiler::emitBuildVector( + DxbcRegisterValue scalar, + uint32_t count) { + if (count == 1) + return scalar; + + std::array scalarIds = + { scalar.id, scalar.id, scalar.id, scalar.id }; + + DxbcRegisterValue result; + result.type.ctype = scalar.type.ctype; + result.type.ccount = count; + result.id = m_module.constComposite( + getVectorTypeId(result.type), + count, scalarIds.data()); + return result; + } + + + DxbcRegisterValue DxbcCompiler::emitBuildZeroVector( + DxbcVectorType type) { + DxbcRegisterValue result; + result.type.ctype = type.ctype; + result.type.ccount = 1; + + switch (type.ctype) { + case DxbcScalarType::Float32: result.id = m_module.constf32(0.0f); break; + case DxbcScalarType::Uint32: result.id = m_module.constu32(0u); break; + case DxbcScalarType::Sint32: result.id = m_module.consti32(0); break; + default: throw DxvkError("DxbcCompiler: Invalid scalar type"); + } + + return emitBuildVector(result, type.ccount); + } + + DxbcRegisterValue DxbcCompiler::emitRegisterBitcast( DxbcRegisterValue srcValue, DxbcScalarType dstType) { diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 55bb5ec25..90ed2a1e7 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -835,7 +835,14 @@ namespace dxvk { double xy, double zw, const DxbcRegMask& writeMask); + + DxbcRegisterValue emitBuildVector( + DxbcRegisterValue scalar, + uint32_t count); + DxbcRegisterValue emitBuildZeroVector( + DxbcVectorType type); + ///////////////////////////////////////// // Generic register manipulation methods DxbcRegisterValue emitRegisterBitcast(