From 21667690960c7edcd7deb105ee995e598f326504 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 30 Jul 2018 20:52:42 +0200 Subject: [PATCH] [dxbc] Map large ICBs to a constant buffer Should fix an issue with compiling a specific compute shader in the game Dragon Ball Xenoverse 2 (#523). --- src/dxbc/dxbc_compiler.cpp | 107 ++++++++++++++++++++++++++----------- src/dxbc/dxbc_compiler.h | 15 +++++- 2 files changed, 89 insertions(+), 33 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 194d37e6..444326ec 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -1,13 +1,14 @@ #include "dxbc_compiler.h" namespace dxvk { + + constexpr uint32_t Icb_BindingSlotId = 14; + constexpr uint32_t Icb_MaxBakedDwords = 16; constexpr uint32_t PerVertex_Position = 0; constexpr uint32_t PerVertex_CullDist = 1; constexpr uint32_t PerVertex_ClipDist = 2; - constexpr uint32_t PushConstant_InstanceId = 0; - DxbcCompiler::DxbcCompiler( const std::string& fileName, const DxbcModuleInfo& moduleInfo, @@ -206,7 +207,7 @@ namespace dxvk { m_resourceSlots.data(), m_interfaceSlots, m_module.compile(), - DxvkShaderConstData()); + std::move(m_immConstData)); } @@ -684,11 +685,18 @@ namespace dxvk { const uint32_t bufferId = ins.dst[0].idx[0].offset; const uint32_t elementCount = ins.dst[0].idx[1].offset; + this->emitDclConstantBufferVar(bufferId, elementCount); + } + + + void DxbcCompiler::emitDclConstantBufferVar( + uint32_t regIdx, + uint32_t numConstants) { // Uniform buffer data is stored as a fixed-size array // of 4x32-bit vectors. SPIR-V requires explicit strides. const uint32_t arrayType = m_module.defArrayTypeUnique( getVectorTypeId({ DxbcScalarType::Float32, 4 }), - m_module.constu32(elementCount)); + m_module.constu32(numConstants)); m_module.decorateArrayStride(arrayType, 16); // SPIR-V requires us to put that array into a @@ -698,7 +706,7 @@ namespace dxvk { m_module.decorateBlock (structType); m_module.memberDecorateOffset(structType, 0, 0); - m_module.setDebugName (structType, str::format("struct_cb", bufferId).c_str()); + m_module.setDebugName (structType, str::format("struct_cb", regIdx).c_str()); m_module.setDebugMemberName (structType, 0, "m"); // Variable that we'll use to access the buffer @@ -707,13 +715,13 @@ namespace dxvk { spv::StorageClassUniform); m_module.setDebugName(varId, - str::format("cb", bufferId).c_str()); + str::format("cb", regIdx).c_str()); // Compute the DXVK binding slot index for the buffer. // D3D11 needs to bind the actual buffers to this slot. const uint32_t bindingId = computeResourceSlotId( m_version.type(), DxbcBindingType::ConstantBuffer, - bufferId); + regIdx); m_module.decorateDescriptorSet(varId, 0); m_module.decorateBinding(varId, bindingId); @@ -723,13 +731,13 @@ namespace dxvk { const uint32_t specConstId = m_module.specConstBool(true); m_module.decorateSpecId(specConstId, bindingId); m_module.setDebugName(specConstId, - str::format("cb", bufferId, "_bound").c_str()); + str::format("cb", regIdx, "_bound").c_str()); DxbcConstantBuffer buf; buf.varId = varId; buf.specId = specConstId; - buf.size = elementCount; - m_constantBuffers.at(bufferId) = buf; + buf.size = numConstants; + m_constantBuffers.at(regIdx) = buf; // Store descriptor info for the shader interface DxvkResourceSlot resource; @@ -738,8 +746,8 @@ namespace dxvk { resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM; m_resourceSlots.push_back(resource); } - - + + void DxbcCompiler::emitDclSampler(const DxbcShaderInstruction& ins) { // dclSampler takes one operand: // (dst0) The sampler register to declare @@ -1302,6 +1310,19 @@ namespace dxvk { if ((ins.customDataSize & 0x3) != 0) throw DxvkError("DxbcCompiler: Immediate constant buffer size not a multiple of four DWORDs"); + if (ins.customDataSize <= Icb_MaxBakedDwords) { + this->emitDclImmediateConstantBufferBaked( + ins.customDataSize, ins.customData); + } else { + this->emitDclImmediateConstantBufferUbo( + ins.customDataSize, ins.customData); + } + } + + + void DxbcCompiler::emitDclImmediateConstantBufferBaked( + uint32_t dwordCount, + const uint32_t* dwordArray) { // Declare individual vector constants as 4x32-bit vectors std::array vectorIds; @@ -1310,14 +1331,14 @@ namespace dxvk { vecType.ccount = 4; const uint32_t vectorTypeId = getVectorTypeId(vecType); - const uint32_t vectorCount = ins.customDataSize / 4; + const uint32_t vectorCount = dwordCount / 4; for (uint32_t i = 0; i < vectorCount; i++) { std::array scalarIds = { - m_module.constu32(ins.customData[4 * i + 0]), - m_module.constu32(ins.customData[4 * i + 1]), - m_module.constu32(ins.customData[4 * i + 2]), - m_module.constu32(ins.customData[4 * i + 3]), + m_module.constu32(dwordArray[4 * i + 0]), + m_module.constu32(dwordArray[4 * i + 1]), + m_module.constu32(dwordArray[4 * i + 2]), + m_module.constu32(dwordArray[4 * i + 3]), }; vectorIds.at(i) = m_module.constComposite( @@ -1346,6 +1367,14 @@ namespace dxvk { } + void DxbcCompiler::emitDclImmediateConstantBufferUbo( + uint32_t dwordCount, + const uint32_t* dwordArray) { + this->emitDclConstantBufferVar(Icb_BindingSlotId, dwordCount / 4); + m_immConstData = DxvkShaderConstData(dwordCount, dwordArray); + } + + void DxbcCompiler::emitCustomData(const DxbcShaderInstruction& ins) { switch (ins.customDataType) { case DxbcCustomDataClass::ImmConstBuf: @@ -4280,25 +4309,39 @@ namespace dxvk { DxbcRegisterPointer DxbcCompiler::emitGetImmConstBufPtr( const DxbcRegister& operand) { - if (m_immConstBuf == 0) - throw DxvkError("DxbcCompiler: Immediate constant buffer not defined"); + DxbcRegisterInfo ptrInfo; + ptrInfo.type.ctype = DxbcScalarType::Float32; + ptrInfo.type.ccount = 4; + ptrInfo.type.alength = 0; + + DxbcRegisterPointer result; + result.type.ctype = ptrInfo.type.ctype; + result.type.ccount = ptrInfo.type.ccount; const DxbcRegisterValue constId = emitIndexLoad(operand.idx[0]); - DxbcRegisterInfo ptrInfo; - ptrInfo.type.ctype = DxbcScalarType::Uint32; - ptrInfo.type.ccount = 4; - ptrInfo.type.alength = 0; - ptrInfo.sclass = spv::StorageClassPrivate; - - DxbcRegisterPointer result; - result.type.ctype = ptrInfo.type.ctype; - result.type.ccount = ptrInfo.type.ccount; - result.id = m_module.opAccessChain( - getPointerTypeId(ptrInfo), - m_immConstBuf, 1, &constId.id); - return result; + if (m_immConstBuf != 0) { + ptrInfo.sclass = spv::StorageClassPrivate; + + result.id = m_module.opAccessChain( + getPointerTypeId(ptrInfo), + m_immConstBuf, 1, &constId.id); + return result; + } else if (m_constantBuffers.at(Icb_BindingSlotId).varId != 0) { + const std::array indices = + {{ m_module.consti32(0), constId.id }}; + + ptrInfo.sclass = spv::StorageClassUniform; + + result.id = m_module.opAccessChain( + getPointerTypeId(ptrInfo), + m_constantBuffers.at(Icb_BindingSlotId).varId, + indices.size(), indices.data()); + return result; + } else { + throw DxvkError("DxbcCompiler: Immediate constant buffer not defined"); + } } diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 699aedf1..78169897 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -458,7 +458,8 @@ namespace dxvk { ////////////////////////////////////////////////// // Immediate constant buffer. If defined, this is // an array of four-component uint32 vectors. - uint32_t m_immConstBuf = 0; + uint32_t m_immConstBuf = 0; + DxvkShaderConstData m_immConstData; /////////////////////////////////////////////////// // Sample pos array. If defined, this iis an array @@ -528,6 +529,10 @@ namespace dxvk { void emitDclConstantBuffer( const DxbcShaderInstruction& ins); + void emitDclConstantBufferVar( + uint32_t regIdx, + uint32_t numConstants); + void emitDclSampler( const DxbcShaderInstruction& ins); @@ -584,6 +589,14 @@ namespace dxvk { void emitDclImmediateConstantBuffer( const DxbcShaderInstruction& ins); + void emitDclImmediateConstantBufferBaked( + uint32_t dwordCount, + const uint32_t* dwordArray); + + void emitDclImmediateConstantBufferUbo( + uint32_t dwordCount, + const uint32_t* dwordArray); + void emitCustomData( const DxbcShaderInstruction& ins);