Implement D3D12 shader feedback for constant buffers

This commit is contained in:
baldurk
2025-09-23 14:49:20 +01:00
parent 3d1e78ba17
commit 659bdee578
@@ -114,7 +114,7 @@ static bool AnnotateDXBCShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
for(const Operand &operand : op.operands)
{
if(operand.type != TYPE_RESOURCE && operand.type != TYPE_UNORDERED_ACCESS_VIEW &&
operand.type != TYPE_SAMPLER)
operand.type != TYPE_SAMPLER && operand.type != TYPE_CONSTANT_BUFFER)
continue;
const Declaration *decl =
@@ -251,7 +251,7 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
// register IDs of each SRV/UAV/Sampler with slots, and record the base slot in this array for
// easy access later when annotating dx.op.createHandle calls. We also need to know the base
// register because the index dxc provides is register-relative
rdcarray<rdcpair<uint32_t, uint32_t>> srvBaseSlots, uavBaseSlots, sampBaseSlots;
rdcarray<rdcpair<uint32_t, uint32_t>> srvBaseSlots, uavBaseSlots, cbvBaseSlots, sampBaseSlots;
// declare the resource, this happens purely in metadata but we need to store the slot
uint32_t regSlot = 0;
@@ -271,6 +271,7 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
Metadata *srvs = reslist->children[0];
Metadata *uavs = reslist->children[1];
Metadata *cbvs = reslist->children[2];
Metadata *samps = reslist->children[3];
// if there isn't a UAV list, create an empty one so we can add our own
if(!uavs)
@@ -329,6 +330,56 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
srvBaseSlots[id] = {feedbackSlot, key.bind};
}
key.type = DXBCBytecode::TYPE_CONSTANT_BUFFER;
for(size_t i = 0; cbvs && i < cbvs->children.size(); i++)
{
// each Sampler child should have a fixed format
const Metadata *cbv = cbvs->children[i];
const Constant *slot = cast<Constant>(cbv->children[(size_t)ResField::ID]->value);
const Constant *cbvSpace = cast<Constant>(cbv->children[(size_t)ResField::Space]->value);
const Constant *reg = cast<Constant>(cbv->children[(size_t)ResField::RegBase]->value);
if(!slot)
{
RDCWARN("Unexpected non-constant slot ID in constant buffer");
continue;
}
if(!cbvSpace)
{
RDCWARN("Unexpected non-constant register space in constant buffer");
continue;
}
if(!reg)
{
RDCWARN("Unexpected non-constant register base in constant buffer");
continue;
}
uint32_t id = slot->getU32();
key.space = cbvSpace->getU32();
key.bind = reg->getU32();
// ensure every valid ID has an index, even if it's 0
cbvBaseSlots.resize_for_index(id);
auto it = slots.find(key);
// not annotated
if(it == slots.end())
continue;
uint32_t feedbackSlot = it->second.slot;
// we assume all feedback slots are non-zero, so that a 0 base slot can be used as an
// identifier for 'this resource isn't annotated'
RDCASSERT(feedbackSlot > 0);
cbvBaseSlots[id] = {feedbackSlot, key.bind};
}
key.type = DXBCBytecode::TYPE_SAMPLER;
for(size_t i = 0; samps && i < samps->children.size(); i++)
@@ -668,6 +719,8 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
slotInfo = uavBaseSlots[id];
else if(kind == HandleKind::Sampler && id < sampBaseSlots.size())
slotInfo = sampBaseSlots[id];
else if(kind == HandleKind::CBuffer && id < cbvBaseSlots.size())
slotInfo = cbvBaseSlots[id];
}
else
{
@@ -716,6 +769,8 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
key.type = DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW;
else if(kind == HandleKind::Sampler)
key.type = DXBCBytecode::TYPE_SAMPLER;
else if(kind == HandleKind::CBuffer)
key.type = DXBCBytecode::TYPE_CONSTANT_BUFFER;
else
continue;
key.space = spaceArg->getU32();
@@ -972,6 +1027,32 @@ static bool AddArraySlots(WrappedID3D12PipelineState::ShaderEntry *shad, uint32_
const ShaderReflection &refl = shad->GetDetails();
for(size_t i = 0; i < refl.constantBlocks.size(); i++)
{
const ConstantBlock &cb = refl.constantBlocks[i];
if(cb.bindArraySize > 1)
{
D3D12FeedbackKey key;
key.stage = refl.stage;
key.type = DXBCBytecode::TYPE_CONSTANT_BUFFER;
key.space = cb.fixedBindSetOrSpace;
key.bind = cb.fixedBindNumber;
DescriptorAccess access;
access.stage = refl.stage;
access.type = DescriptorType::ConstantBuffer;
access.index = i & 0xffff;
// descriptor storage side will be calculated later when finalising this with the root
// signature information.
slots[key].numDescriptors = RDCMIN(maxDescriptors, cb.bindArraySize);
slots[key].access = access;
slots[key].slot = numSlots;
numSlots += slots[key].numDescriptors;
dynamicUsed = true;
}
}
for(size_t i = 0; i < refl.readOnlyResources.size(); i++)
{
const ShaderResource &ro = refl.readOnlyResources[i];