[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"
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<uint32_t, 4096> 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<uint32_t, 4> 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<uint32_t, 2> 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");
}
}

View File

@ -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);