1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-14 22:29:15 +01:00

[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).
This commit is contained in:
Philip Rebohle 2018-07-30 20:52:42 +02:00
parent bf06654a83
commit 2166769096
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 89 additions and 33 deletions

View File

@ -1,13 +1,14 @@
#include "dxbc_compiler.h" #include "dxbc_compiler.h"
namespace dxvk { namespace dxvk {
constexpr uint32_t Icb_BindingSlotId = 14;
constexpr uint32_t Icb_MaxBakedDwords = 16;
constexpr uint32_t PerVertex_Position = 0; constexpr uint32_t PerVertex_Position = 0;
constexpr uint32_t PerVertex_CullDist = 1; constexpr uint32_t PerVertex_CullDist = 1;
constexpr uint32_t PerVertex_ClipDist = 2; constexpr uint32_t PerVertex_ClipDist = 2;
constexpr uint32_t PushConstant_InstanceId = 0;
DxbcCompiler::DxbcCompiler( DxbcCompiler::DxbcCompiler(
const std::string& fileName, const std::string& fileName,
const DxbcModuleInfo& moduleInfo, const DxbcModuleInfo& moduleInfo,
@ -206,7 +207,7 @@ namespace dxvk {
m_resourceSlots.data(), m_resourceSlots.data(),
m_interfaceSlots, m_interfaceSlots,
m_module.compile(), 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 bufferId = ins.dst[0].idx[0].offset;
const uint32_t elementCount = ins.dst[0].idx[1].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 // Uniform buffer data is stored as a fixed-size array
// of 4x32-bit vectors. SPIR-V requires explicit strides. // of 4x32-bit vectors. SPIR-V requires explicit strides.
const uint32_t arrayType = m_module.defArrayTypeUnique( const uint32_t arrayType = m_module.defArrayTypeUnique(
getVectorTypeId({ DxbcScalarType::Float32, 4 }), getVectorTypeId({ DxbcScalarType::Float32, 4 }),
m_module.constu32(elementCount)); m_module.constu32(numConstants));
m_module.decorateArrayStride(arrayType, 16); m_module.decorateArrayStride(arrayType, 16);
// SPIR-V requires us to put that array into a // SPIR-V requires us to put that array into a
@ -698,7 +706,7 @@ namespace dxvk {
m_module.decorateBlock (structType); m_module.decorateBlock (structType);
m_module.memberDecorateOffset(structType, 0, 0); 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"); m_module.setDebugMemberName (structType, 0, "m");
// Variable that we'll use to access the buffer // Variable that we'll use to access the buffer
@ -707,13 +715,13 @@ namespace dxvk {
spv::StorageClassUniform); spv::StorageClassUniform);
m_module.setDebugName(varId, 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. // Compute the DXVK binding slot index for the buffer.
// D3D11 needs to bind the actual buffers to this slot. // D3D11 needs to bind the actual buffers to this slot.
const uint32_t bindingId = computeResourceSlotId( const uint32_t bindingId = computeResourceSlotId(
m_version.type(), DxbcBindingType::ConstantBuffer, m_version.type(), DxbcBindingType::ConstantBuffer,
bufferId); regIdx);
m_module.decorateDescriptorSet(varId, 0); m_module.decorateDescriptorSet(varId, 0);
m_module.decorateBinding(varId, bindingId); m_module.decorateBinding(varId, bindingId);
@ -723,13 +731,13 @@ namespace dxvk {
const uint32_t specConstId = m_module.specConstBool(true); const uint32_t specConstId = m_module.specConstBool(true);
m_module.decorateSpecId(specConstId, bindingId); m_module.decorateSpecId(specConstId, bindingId);
m_module.setDebugName(specConstId, m_module.setDebugName(specConstId,
str::format("cb", bufferId, "_bound").c_str()); str::format("cb", regIdx, "_bound").c_str());
DxbcConstantBuffer buf; DxbcConstantBuffer buf;
buf.varId = varId; buf.varId = varId;
buf.specId = specConstId; buf.specId = specConstId;
buf.size = elementCount; buf.size = numConstants;
m_constantBuffers.at(bufferId) = buf; m_constantBuffers.at(regIdx) = buf;
// Store descriptor info for the shader interface // Store descriptor info for the shader interface
DxvkResourceSlot resource; DxvkResourceSlot resource;
@ -738,8 +746,8 @@ namespace dxvk {
resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM; resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
m_resourceSlots.push_back(resource); m_resourceSlots.push_back(resource);
} }
void DxbcCompiler::emitDclSampler(const DxbcShaderInstruction& ins) { void DxbcCompiler::emitDclSampler(const DxbcShaderInstruction& ins) {
// dclSampler takes one operand: // dclSampler takes one operand:
// (dst0) The sampler register to declare // (dst0) The sampler register to declare
@ -1302,6 +1310,19 @@ namespace dxvk {
if ((ins.customDataSize & 0x3) != 0) if ((ins.customDataSize & 0x3) != 0)
throw DxvkError("DxbcCompiler: Immediate constant buffer size not a multiple of four DWORDs"); 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 // Declare individual vector constants as 4x32-bit vectors
std::array<uint32_t, 4096> vectorIds; std::array<uint32_t, 4096> vectorIds;
@ -1310,14 +1331,14 @@ namespace dxvk {
vecType.ccount = 4; vecType.ccount = 4;
const uint32_t vectorTypeId = getVectorTypeId(vecType); 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++) { for (uint32_t i = 0; i < vectorCount; i++) {
std::array<uint32_t, 4> scalarIds = { std::array<uint32_t, 4> scalarIds = {
m_module.constu32(ins.customData[4 * i + 0]), m_module.constu32(dwordArray[4 * i + 0]),
m_module.constu32(ins.customData[4 * i + 1]), m_module.constu32(dwordArray[4 * i + 1]),
m_module.constu32(ins.customData[4 * i + 2]), m_module.constu32(dwordArray[4 * i + 2]),
m_module.constu32(ins.customData[4 * i + 3]), m_module.constu32(dwordArray[4 * i + 3]),
}; };
vectorIds.at(i) = m_module.constComposite( 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) { void DxbcCompiler::emitCustomData(const DxbcShaderInstruction& ins) {
switch (ins.customDataType) { switch (ins.customDataType) {
case DxbcCustomDataClass::ImmConstBuf: case DxbcCustomDataClass::ImmConstBuf:
@ -4280,25 +4309,39 @@ namespace dxvk {
DxbcRegisterPointer DxbcCompiler::emitGetImmConstBufPtr( DxbcRegisterPointer DxbcCompiler::emitGetImmConstBufPtr(
const DxbcRegister& operand) { const DxbcRegister& operand) {
if (m_immConstBuf == 0) DxbcRegisterInfo ptrInfo;
throw DxvkError("DxbcCompiler: Immediate constant buffer not defined"); 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 const DxbcRegisterValue constId
= emitIndexLoad(operand.idx[0]); = emitIndexLoad(operand.idx[0]);
DxbcRegisterInfo ptrInfo; if (m_immConstBuf != 0) {
ptrInfo.type.ctype = DxbcScalarType::Uint32; ptrInfo.sclass = spv::StorageClassPrivate;
ptrInfo.type.ccount = 4;
ptrInfo.type.alength = 0; result.id = m_module.opAccessChain(
ptrInfo.sclass = spv::StorageClassPrivate; getPointerTypeId(ptrInfo),
m_immConstBuf, 1, &constId.id);
DxbcRegisterPointer result; return result;
result.type.ctype = ptrInfo.type.ctype; } else if (m_constantBuffers.at(Icb_BindingSlotId).varId != 0) {
result.type.ccount = ptrInfo.type.ccount; const std::array<uint32_t, 2> indices =
result.id = m_module.opAccessChain( {{ m_module.consti32(0), constId.id }};
getPointerTypeId(ptrInfo),
m_immConstBuf, 1, &constId.id); ptrInfo.sclass = spv::StorageClassUniform;
return result;
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");
}
} }

View File

@ -458,7 +458,8 @@ namespace dxvk {
////////////////////////////////////////////////// //////////////////////////////////////////////////
// Immediate constant buffer. If defined, this is // Immediate constant buffer. If defined, this is
// an array of four-component uint32 vectors. // 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 // Sample pos array. If defined, this iis an array
@ -528,6 +529,10 @@ namespace dxvk {
void emitDclConstantBuffer( void emitDclConstantBuffer(
const DxbcShaderInstruction& ins); const DxbcShaderInstruction& ins);
void emitDclConstantBufferVar(
uint32_t regIdx,
uint32_t numConstants);
void emitDclSampler( void emitDclSampler(
const DxbcShaderInstruction& ins); const DxbcShaderInstruction& ins);
@ -584,6 +589,14 @@ namespace dxvk {
void emitDclImmediateConstantBuffer( void emitDclImmediateConstantBuffer(
const DxbcShaderInstruction& ins); const DxbcShaderInstruction& ins);
void emitDclImmediateConstantBufferBaked(
uint32_t dwordCount,
const uint32_t* dwordArray);
void emitDclImmediateConstantBufferUbo(
uint32_t dwordCount,
const uint32_t* dwordArray);
void emitCustomData( void emitCustomData(
const DxbcShaderInstruction& ins); const DxbcShaderInstruction& ins);