Add support for shader model 6.6 bindless resources.

This commit is contained in:
Benoit Dumesnil
2022-02-06 19:02:16 +01:00
committed by Baldur Karlsson
parent c122b41155
commit dfd00b1e38
8 changed files with 793 additions and 150 deletions
@@ -91,15 +91,19 @@ struct D3D12ViewTag
OMDepth,
};
D3D12ViewTag() : type(SRV), space(0), rootSignatureIndex(0), immediate(false) {}
D3D12ViewTag()
: type(SRV), space(0), rootSignatureIndex(0), immediate(false), directHeapAccess(false)
{
}
D3D12ViewTag(ResType t, int s, int el, bool imm, const D3D12Pipe::View &rs)
: type(t), space(s), rootSignatureIndex(el), immediate(imm), res(rs)
: type(t), space(s), rootSignatureIndex(el), immediate(imm), directHeapAccess(false), res(rs)
{
}
ResType type;
int space, rootSignatureIndex;
bool immediate;
bool directHeapAccess;
D3D12Pipe::View res;
};
@@ -731,9 +735,10 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, const Bi
{
const D3D12Pipe::View &r = view.res;
bool uav = view.type == D3D12ViewTag::UAV;
bool directHeapAccess = view.directHeapAccess;
bool filledSlot = (r.resourceId != ResourceId());
bool usedSlot = (bind && bind->used && r.dynamicallyUsed);
bool usedSlot = (bind && bind->used && r.dynamicallyUsed) || directHeapAccess;
// if a target is set to RTVs or DSV, it is implicitly used
if(filledSlot)
@@ -752,6 +757,9 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, const Bi
if(view.type == D3D12ViewTag::OMDepth)
regname = tr("Depth");
if(directHeapAccess)
regname = tr("");
uint32_t w = 1, h = 1, d = 1;
uint32_t a = 1;
QString format = tr("Unknown");
@@ -847,12 +855,20 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, const Bi
}
else
{
QString rootel = view.immediate
? tr("#%1 Direct").arg(view.rootSignatureIndex)
: tr("#%1 Table[%2]").arg(view.rootSignatureIndex).arg(r.tableIndex);
QString spaceStr;
if(!directHeapAccess)
spaceStr = QString::number(view.space);
QString rootel;
if(directHeapAccess)
rootel = tr("ResourceDescriptorHeap[%1]").arg(r.tableIndex);
else if(view.immediate)
rootel = tr("#%1 Direct").arg(view.rootSignatureIndex);
else
rootel = tr("#%1 Table[%2]").arg(view.rootSignatureIndex).arg(r.tableIndex);
node = new RDTreeWidgetItem(
{rootel, view.space, regname, r.resourceId, typeName, w, h, d, a, format, QString()});
{rootel, spaceStr, regname, r.resourceId, typeName, w, h, d, a, format, QString()});
}
node->setTag(QVariant::fromValue(view));
@@ -1076,6 +1092,8 @@ void D3D12PipelineStateViewer::setShaderState(
tag.rootSignatureIndex = rootElements[i].rootSignatureIndex;
tag.immediate = rootElements[i].immediate;
bool directHeapAccess = rootElements[i].registerSpace == ~0U;
switch(rootElements[i].type)
{
case BindType::ReadOnlyResource:
@@ -1093,6 +1111,19 @@ void D3D12PipelineStateViewer::setShaderState(
const rdcarray<D3D12Pipe::View> &views = rootElements[i].views;
// add direct heap access resources
if(directHeapAccess)
{
for(size_t view = 0; view < views.size(); ++view)
{
tag.space = -1;
tag.res = views[view];
tag.directHeapAccess = directHeapAccess;
addResourceRow(tag, NULL, NULL, tree);
}
continue;
}
size_t firstView = rootElements[i].firstUsedIndex;
size_t lastView = qMin(views.size() - 1, size_t(rootElements[i].lastUsedIndex));
@@ -1219,7 +1250,7 @@ void D3D12PipelineStateViewer::setShaderState(
const Bindpoint *bind = NULL;
const ShaderSampler *shaderInput = NULL;
if(stage.reflection)
if(stage.reflection && !directHeapAccess)
{
for(int k = 0; k < stage.bindpointMapping.samplers.count(); ++k)
{
@@ -1241,19 +1272,30 @@ void D3D12PipelineStateViewer::setShaderState(
}
}
}
QString rootel =
rootElements[i].immediate
? tr("#%1 Static").arg(rootElements[i].rootSignatureIndex)
: tr("#%1 Table[%2]").arg(rootElements[i].rootSignatureIndex).arg(s.tableIndex);
QString spaceStr = QString::number(rootElements[i].registerSpace);
QString rootel;
if(directHeapAccess)
{
rootel = tr("SamplerDescriptorHeap[%1]").arg(s.tableIndex);
spaceStr = tr("");
}
else if(rootElements[i].immediate)
{
rootel = tr("#%1 Static").arg(rootElements[i].rootSignatureIndex);
}
else
{
rootel = tr("#%1 Table[%2]").arg(rootElements[i].rootSignatureIndex).arg(s.tableIndex);
}
bool filledSlot = s.filter.minify != FilterMode::NoFilter;
bool usedSlot = (bind && bind->used);
bool usedSlot = (bind && bind->used) || directHeapAccess;
if(showNode(usedSlot, filledSlot))
{
QString regname = QString::number(s.bind);
QString regname;
if(!directHeapAccess)
regname = QString::number(s.bind);
if(shaderInput && !shaderInput->name.empty())
regname += lit(": ") + shaderInput->name;
@@ -1307,7 +1349,7 @@ void D3D12PipelineStateViewer::setShaderState(
filter += QFormatStr(" (%1)").arg(ToQStr(s.filter.filter));
RDTreeWidgetItem *node = new RDTreeWidgetItem(
{rootel, rootElements[i].registerSpace, regname, addressing, filter,
{rootel, spaceStr, regname, addressing, filter,
QFormatStr("%1 - %2")
.arg(s.minLOD == -FLT_MAX ? lit("0") : QString::number(s.minLOD))
.arg(s.maxLOD == FLT_MAX ? lit("FLT_MAX") : QString::number(s.maxLOD)),
@@ -1335,7 +1377,7 @@ void D3D12PipelineStateViewer::setShaderState(
const Bindpoint *bind = NULL;
const ConstantBlock *shaderCBuf = NULL;
if(stage.reflection)
if(stage.reflection && !directHeapAccess)
{
for(int k = 0; k < stage.bindpointMapping.constantBlocks.count(); ++k)
{
@@ -1360,14 +1402,19 @@ void D3D12PipelineStateViewer::setShaderState(
}
}
}
if(directHeapAccess)
cbuftag = QVariant::fromValue(D3D12CBufTag(0, (uint32_t)j, (uint32_t)i));
if(!cbuftag.isValid())
cbuftag =
QVariant::fromValue(D3D12CBufTag(rootElements[i].registerSpace, b.bind, (uint32_t)i));
QString rootel;
if(rootElements[i].immediate)
if(directHeapAccess)
{
rootel = tr("ResourceDescriptorHeap[%1]").arg(b.tableIndex);
}
else if(rootElements[i].immediate)
{
if(!b.rootValues.empty())
rootel = tr("#%1 Consts").arg(rootElements[i].rootSignatureIndex);
@@ -1383,7 +1430,7 @@ void D3D12PipelineStateViewer::setShaderState(
if(rootElements[i].immediate && !b.rootValues.empty())
filledSlot = true;
bool usedSlot = (bind && bind->used);
bool usedSlot = (bind && bind->used) || directHeapAccess;
if(showNode(usedSlot, filledSlot))
{
@@ -1397,12 +1444,18 @@ void D3D12PipelineStateViewer::setShaderState(
QString regname = QString::number(b.bind);
if(shaderCBuf && !shaderCBuf->name.empty())
regname += lit(": ") + shaderCBuf->name;
if(bind != NULL && bind->arraySize > 1)
regname += tr("[%1]").arg(b.bind - bind->bind);
if(directHeapAccess)
{
regname = tr("");
}
else
{
if(shaderCBuf && !shaderCBuf->name.empty())
regname += lit(": ") + shaderCBuf->name;
if(bind != NULL && bind->arraySize > 1)
regname += tr("[%1]").arg(b.bind - bind->bind);
}
QString sizestr;
if(bytesize == (uint32_t)length)
sizestr = tr("%1 Variables, %2 bytes").arg(numvars).arg(length);
@@ -1413,8 +1466,11 @@ void D3D12PipelineStateViewer::setShaderState(
if(length < bytesize)
filledSlot = false;
QString spaceStr = QString::number(rootElements[i].registerSpace);
if(directHeapAccess)
spaceStr = tr("");
RDTreeWidgetItem *node = new RDTreeWidgetItem(
{rootel, (qulonglong)rootElements[i].registerSpace, regname, b.resourceId,
{rootel, spaceStr, regname, b.resourceId,
QFormatStr("%1 - %2").arg(offset).arg(offset + bytesize), sizestr, QString()});
node->setTag(cbuftag);
@@ -2703,6 +2759,10 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
{
if((els[i].visibility & MaskForStage(sh.stage)) == ShaderStageMask::Unknown)
continue;
bool directHeapAccess = els[i].registerSpace == ~0U;
QString spaceStr;
if(!directHeapAccess)
spaceStr = QString::number(els[i].registerSpace);
switch(els[i].type)
{
@@ -2713,7 +2773,7 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
const D3D12Pipe::View &v = els[i].views[j];
const ShaderResource *shaderInput = NULL;
if(sh.reflection)
if(sh.reflection && !directHeapAccess)
{
for(int32_t k = 0; k < sh.bindpointMapping.readOnlyResources.count(); ++k)
{
@@ -2737,13 +2797,17 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
}
}
QString rootel = els[i].immediate
? tr("#%1 Direct").arg(els[i].rootSignatureIndex)
: tr("#%1 Table[%2]").arg(els[i].rootSignatureIndex).arg(v.tableIndex);
QString rootel;
if(directHeapAccess)
rootel = tr("ResourceDescriptorHeap[%1]").arg(v.tableIndex);
else if(els[i].immediate)
rootel = tr("#%1 Direct").arg(els[i].rootSignatureIndex);
else
rootel = tr("#%1 Table[%2]").arg(els[i].rootSignatureIndex).arg(v.tableIndex);
QVariantList row = exportViewHTML(v, false, shaderInput, QString());
row.push_front(els[i].registerSpace);
row.push_front(spaceStr);
row.push_front(rootel);
rowsRO.push_back(row);
@@ -2757,7 +2821,7 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
const D3D12Pipe::View &v = els[i].views[j];
const ShaderResource *shaderInput = NULL;
if(sh.reflection)
if(sh.reflection && !directHeapAccess)
{
for(int32_t k = 0; k < sh.bindpointMapping.readWriteResources.count(); ++k)
{
@@ -2780,14 +2844,16 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
}
}
}
QString rootel = els[i].immediate
? tr("#%1 Direct").arg(els[i].rootSignatureIndex)
: tr("#%1 Table[%2]").arg(els[i].rootSignatureIndex).arg(v.tableIndex);
QString rootel;
if(directHeapAccess)
rootel = tr("ResourceDescriptorHeap[%1]").arg(v.tableIndex);
else if(els[i].immediate)
rootel = tr("#%1 Direct").arg(els[i].rootSignatureIndex);
else
rootel = tr("#%1 Table[%2]").arg(els[i].rootSignatureIndex).arg(v.tableIndex);
QVariantList row = exportViewHTML(v, true, shaderInput, QString());
row.push_front(els[i].registerSpace);
row.push_front(spaceStr);
row.push_front(rootel);
rowsRW.push_back(row);
@@ -2801,7 +2867,7 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
const D3D12Pipe::Sampler &s = els[i].samplers[j];
const ShaderSampler *shaderInput = NULL;
if(sh.reflection)
if(sh.reflection && !directHeapAccess)
{
for(int32_t k = 0; k < sh.bindpointMapping.samplers.count(); ++k)
{
@@ -2824,14 +2890,18 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
}
}
}
QString rootel = els[i].immediate
? tr("#%1 Static").arg(els[i].rootSignatureIndex)
: tr("#%1 Table[%2]").arg(els[i].rootSignatureIndex).arg(s.tableIndex);
QString rootel;
if(directHeapAccess)
rootel = tr("SamplerDescriptorHeap[%1]").arg(s.tableIndex);
else if(els[i].immediate)
rootel = tr("#%1 Static").arg(els[i].rootSignatureIndex);
else
rootel = tr("#%1 Table[%2]").arg(els[i].rootSignatureIndex).arg(s.tableIndex);
{
QString regname = QString::number(s.bind);
QString regname;
if(!directHeapAccess)
regname = QString::number(s.bind);
if(shaderInput && !shaderInput->name.empty())
regname += lit(": ") + shaderInput->name;
@@ -2885,7 +2955,7 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
filter += QFormatStr(" (%1)").arg(ToQStr(s.filter.filter));
rowsSampler.push_back(
{rootel, els[i].registerSpace, regname, addressing, filter,
{rootel, spaceStr, regname, addressing, filter,
QFormatStr("%1 - %2")
.arg(s.minLOD == -FLT_MAX ? lit("0") : QString::number(s.minLOD))
.arg(s.maxLOD == FLT_MAX ? lit("FLT_MAX") : QString::number(s.maxLOD)),
@@ -2901,7 +2971,7 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
const D3D12Pipe::ConstantBuffer &b = els[i].constantBuffers[j];
const ConstantBlock *shaderCBuf = NULL;
if(sh.reflection)
if(sh.reflection && !directHeapAccess)
{
for(int32_t k = 0; k < sh.bindpointMapping.constantBlocks.count(); ++k)
{
@@ -2927,8 +2997,11 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
}
QString rootel;
if(els[i].immediate)
if(directHeapAccess)
{
rootel = tr("ResourceDescriptorHeap[%1]").arg(b.tableIndex);
}
else if(els[i].immediate)
{
if(!b.rootValues.empty())
rootel = tr("#%1 Consts").arg(els[i].rootSignatureIndex);
@@ -2955,15 +3028,16 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe
else
name = tr("Empty");
QString regname = QString::number(b.bind);
QString regname;
if(!directHeapAccess)
regname = QString::number(b.bind);
if(shaderCBuf && !shaderCBuf->name.empty())
regname += lit(": ") + shaderCBuf->name;
length = qMin(length, (uint64_t)bytesize);
rowsCB.push_back({rootel, els[i].registerSpace, regname, name, (qulonglong)offset,
(qulonglong)length, numvars});
rowsCB.push_back(
{rootel, spaceStr, regname, name, (qulonglong)offset, (qulonglong)length, numvars});
}
}
break;
+96 -17
View File
@@ -932,6 +932,24 @@ void D3D12Replay::FillResourceView(D3D12Pipe::View &view, const D3D12Descriptor
}
}
void D3D12Replay::FillSampler(D3D12Pipe::Sampler &samp, const D3D12_SAMPLER_DESC &sampDesc)
{
samp.addressU = MakeAddressMode(sampDesc.AddressU);
samp.addressV = MakeAddressMode(sampDesc.AddressV);
samp.addressW = MakeAddressMode(sampDesc.AddressW);
samp.borderColor = sampDesc.BorderColor;
samp.compareFunction = MakeCompareFunc(sampDesc.ComparisonFunc);
samp.filter = MakeFilter(sampDesc.Filter);
samp.maxAnisotropy = 0;
if(samp.filter.minify == FilterMode::Anisotropic)
samp.maxAnisotropy = sampDesc.MaxAnisotropy;
samp.maxLOD = sampDesc.MaxLOD;
samp.minLOD = sampDesc.MinLOD;
samp.mipLODBias = sampDesc.MipLODBias;
}
ShaderStageMask ToShaderStageMask(D3D12_SHADER_VISIBILITY vis)
{
switch(vis)
@@ -959,7 +977,7 @@ void D3D12Replay::FillRootElements(uint32_t eventId, const D3D12RenderState::Roo
const D3D12FeedbackBindIdentifier *curUsage = usage.used.begin();
const D3D12FeedbackBindIdentifier *lastUsage = usage.used.end();
D3D12FeedbackBindIdentifier curIdentifier;
D3D12FeedbackBindIdentifier curIdentifier = {};
WrappedID3D12RootSignature *sig =
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(rootSig.rootsig);
@@ -1232,22 +1250,7 @@ void D3D12Replay::FillRootElements(uint32_t eventId, const D3D12RenderState::Roo
if(desc)
{
const D3D12_SAMPLER_DESC &sampDesc = desc->GetSampler();
samp.addressU = MakeAddressMode(sampDesc.AddressU);
samp.addressV = MakeAddressMode(sampDesc.AddressV);
samp.addressW = MakeAddressMode(sampDesc.AddressW);
samp.borderColor = sampDesc.BorderColor;
samp.compareFunction = MakeCompareFunc(sampDesc.ComparisonFunc);
samp.filter = MakeFilter(sampDesc.Filter);
samp.maxAnisotropy = 0;
if(samp.filter.minify == FilterMode::Anisotropic)
samp.maxAnisotropy = sampDesc.MaxAnisotropy;
samp.maxLOD = sampDesc.MaxLOD;
samp.minLOD = sampDesc.MinLOD;
samp.mipLODBias = sampDesc.MipLODBias;
FillSampler(samp, sampDesc);
desc++;
}
}
@@ -1355,6 +1358,82 @@ void D3D12Replay::FillRootElements(uint32_t eventId, const D3D12RenderState::Roo
}
}
}
// direct heap access resources
{
D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState;
WrappedID3D12DescriptorHeap *resourceHeap = NULL;
WrappedID3D12DescriptorHeap *samplerHeap = NULL;
for(ResourceId id : rs.heaps)
{
WrappedID3D12DescriptorHeap *heap =
(WrappedID3D12DescriptorHeap *)rm->GetCurrentAs<ID3D12DescriptorHeap>(id);
D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc();
if(desc.Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
resourceHeap = heap;
else
samplerHeap = heap;
}
D3D12Pipe::RootSignatureRange *element = NULL;
while(curUsage < lastUsage && curUsage->directAccess)
{
ShaderStageMask visibility = (ShaderStageMask)(1 << (int)curUsage->shaderStage);
if(element == NULL || (element->visibility != visibility) ||
(element->type != curUsage->bindType))
{
rootElements.resize_for_index(ridx);
element = &rootElements[ridx++];
element->immediate = false;
element->rootSignatureIndex = ~0U;
element->type = curUsage->bindType;
element->visibility = visibility;
element->registerSpace = ~0U;
element->dynamicallyUsedCount = 0;
element->samplers.clear();
element->constantBuffers.clear();
element->views.clear();
}
if(curUsage->bindType == BindType::Sampler)
{
D3D12Descriptor *desc =
(D3D12Descriptor *)samplerHeap->GetCPUDescriptorHandleForHeapStart().ptr;
desc += curUsage->descIndex;
element->samplers.push_back(D3D12Pipe::Sampler());
D3D12Pipe::Sampler &samp = element->samplers.back();
const D3D12_SAMPLER_DESC &sampDesc = desc->GetSampler();
FillSampler(samp, sampDesc);
samp.tableIndex = curUsage->descIndex;
element->dynamicallyUsedCount++;
}
else if(curUsage->bindType == BindType::ConstantBuffer)
{
D3D12Descriptor *desc =
(D3D12Descriptor *)resourceHeap->GetCPUDescriptorHandleForHeapStart().ptr;
desc += curUsage->descIndex;
element->constantBuffers.push_back(D3D12Pipe::ConstantBuffer());
D3D12Pipe::ConstantBuffer &cb = element->constantBuffers.back();
const D3D12_CONSTANT_BUFFER_VIEW_DESC &cbv = desc->GetCBV();
WrappedID3D12Resource::GetResIDFromAddr(cbv.BufferLocation, cb.resourceId, cb.byteOffset);
cb.resourceId = rm->GetOriginalID(cb.resourceId);
cb.byteSize = cbv.SizeInBytes;
cb.tableIndex = curUsage->descIndex;
element->dynamicallyUsedCount++;
}
else
{
D3D12Descriptor *desc =
(D3D12Descriptor *)resourceHeap->GetCPUDescriptorHandleForHeapStart().ptr;
desc += curUsage->descIndex;
D3D12Pipe::View view;
FillResourceView(view, desc);
view.tableIndex = curUsage->descIndex;
element->views.push_back(view);
element->dynamicallyUsedCount++;
}
curUsage++;
}
}
// Each static sampler gets its own RootElement
for(size_t i = 0; i < sig->sig.StaticSamplers.size(); i++)
+22 -5
View File
@@ -55,19 +55,35 @@ struct D3D12FeedbackBindIdentifier
size_t rootEl;
size_t rangeIndex;
UINT descIndex;
ShaderStage shaderStage; // Only used for direct access views
BindType bindType; // Only used for direct access views
bool directAccess;
bool operator<(const D3D12FeedbackBindIdentifier &o) const
{
if(rootEl != o.rootEl)
return rootEl < o.rootEl;
if(rangeIndex != o.rangeIndex)
return rangeIndex < o.rangeIndex;
if(directAccess != o.directAccess)
return directAccess < o.directAccess;
if(!directAccess)
{
if(rootEl != o.rootEl)
return rootEl < o.rootEl;
if(rangeIndex != o.rangeIndex)
return rangeIndex < o.rangeIndex;
}
else
{
if(shaderStage != o.shaderStage)
return shaderStage < o.shaderStage;
if(bindType != o.bindType)
return bindType < o.bindType;
}
return descIndex < o.descIndex;
}
bool operator==(const D3D12FeedbackBindIdentifier &o) const
{
return rootEl == o.rootEl && rangeIndex == o.rangeIndex && descIndex == o.descIndex;
return rootEl == o.rootEl && rangeIndex == o.rangeIndex && descIndex == o.descIndex &&
directAccess == o.directAccess && shaderStage == o.shaderStage && bindType == o.bindType;
}
};
@@ -245,6 +261,7 @@ private:
const ShaderBindpointMapping *mappings[(uint32_t)ShaderStage::Count],
rdcarray<D3D12Pipe::RootSignatureRange> &rootElements);
void FillResourceView(D3D12Pipe::View &view, const D3D12Descriptor *desc);
void FillSampler(D3D12Pipe::Sampler &view, const D3D12_SAMPLER_DESC &desc);
bool CreateSOBuffers();
void ClearPostVSCache();
+483 -56
View File
@@ -70,7 +70,20 @@ private:
};
static const uint32_t numReservedSlots = 4;
static const uint32_t magicFeedbackValue = 0xbeebf33d;
static const uint32_t magicFeedbackValue = 0xbeebf330;
// keep the 4 lower bits to store the type of resource for direct heap access bindless
static const uint32_t magicFeedbackTypeMask = 0x0000000f;
static D3D12FeedbackKey GetDirectHeapAccessKey()
{
Bindpoint bind;
bind.bind = -1;
bind.bindset = -1;
D3D12FeedbackKey key;
key.type = DXBCBytecode::OperandType::TYPE_RESOURCE;
key.bind = bind;
return key;
}
static bool AnnotateDXBCShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
const std::map<D3D12FeedbackKey, D3D12FeedbackSlot> &slots,
@@ -195,16 +208,81 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
const DXIL::Type *handleType = editor.GetTypeByName("dx.types.Handle");
const DXIL::Function *createHandle = editor.GetFunctionByName("dx.op.createHandle");
const DXIL::Function *createHandleFromBinding =
editor.GetFunctionByName("dx.op.createHandleFromBinding");
const DXIL::Function *createHandleFromHeap =
editor.GetFunctionByName("dx.op.createHandleFromHeap");
const DXIL::Function *annotateHandle = editor.GetFunctionByName("dx.op.annotateHandle");
bool isShaderModel6_6OrAbove =
dxbc->m_Version.Major > 6 || (dxbc->m_Version.Major == 6 && dxbc->m_Version.Minor >= 6);
// if we don't have the handle type then this shader can't use any dynamically! we have no
// feedback to get
if(!handleType || !createHandle)
if(!handleType || (!createHandle && !isShaderModel6_6OrAbove) ||
(isShaderModel6_6OrAbove && !createHandleFromHeap && !createHandleFromBinding))
return false;
const DXIL::Type *i32 = editor.GetInt32Type();
const DXIL::Type *i8 = editor.GetInt8Type();
const DXIL::Type *i1 = editor.GetBoolType();
// Create createHandleFromBinding we'll need to create the feedback UAV
if(!createHandleFromBinding && isShaderModel6_6OrAbove)
{
const DXIL::Type *resBindType = editor.GetTypeByName("dx.types.ResBind");
if(!resBindType)
{
DXIL::Type resBindTypeTmp;
resBindTypeTmp.type = DXIL::Type::Struct;
resBindTypeTmp.scalarType = DXIL::Type::Void;
resBindTypeTmp.name = "dx.types.ResBind";
resBindTypeTmp.members = {i32, i32, i32, i8};
resBindType = editor.AddType(resBindTypeTmp);
}
const DXIL::Type *funcType = NULL;
for(const DXIL::Type &type : editor.GetTypes())
{
if(type.type == DXIL::Type::Function && type.inner == handleType &&
type.members.size() == 4 && type.members[0] == i32 && type.members[1] == resBindType &&
type.members[2] == i32 && type.members[3] == i1)
{
funcType = &type;
break;
}
}
if(!funcType)
{
DXIL::Type funcTypeTmp;
funcTypeTmp.type = DXIL::Type::Function;
funcTypeTmp.inner = handleType;
funcTypeTmp.members = {i32, resBindType, i32, i1};
funcType = editor.AddType(funcTypeTmp);
}
DXIL::Type funcPtrType;
funcPtrType.type = DXIL::Type::Pointer;
funcPtrType.inner = funcType;
DXIL::Function createHandleBaseFunction;
createHandleBaseFunction.name = "dx.op.createHandleFromBinding";
createHandleBaseFunction.funcType = editor.AddType(funcPtrType);
createHandleBaseFunction.external = true;
for(const DXIL::AttributeSet &attrs : editor.GetAttributeSets())
{
if(attrs.functionSlot && attrs.functionSlot->params == DXIL::Attribute::NoUnwind)
{
createHandleBaseFunction.attrs = &attrs;
break;
}
}
if(!createHandleBaseFunction.attrs)
RDCWARN("Couldn't find existing nounwind attr set");
createHandleFromBinding = editor.DeclareFunction(createHandleBaseFunction);
}
// get the atomic function we'll need
const DXIL::Function *atomicBinOp = editor.GetFunctionByName("dx.op.atomicBinOp.i32");
if(!atomicBinOp)
@@ -280,7 +358,15 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
}
DXIL::Metadata *resources = editor.GetMetadataByName("dx.resources");
if(!resources)
{
DXIL::Metadata tmpResList;
tmpResList.children.resize(4);
DXIL::NamedMetadata tmpResources;
tmpResources.name = "dx.resources";
tmpResources.children.push_back(editor.AddMetadata(tmpResList));
resources = editor.AddNamedMetadata(tmpResources);
}
// if there are no resources declared we can't have any dynamic indexing
if(!resources)
return false;
@@ -575,9 +661,14 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
return false;
}
// One ( and only one ) of createHandle or createHandleFromBinding should be defined
RDCASSERTNOTEQUAL(createHandle == NULL, createHandleFromBinding == NULL);
int startInst = 0;
// create our handle first thing
DXIL::Instruction *handle;
DXIL::Instruction *handle = NULL;
if(createHandle)
{
RDCASSERT(!isShaderModel6_6OrAbove);
DXIL::Instruction inst;
inst.op = DXIL::Operation::Call;
inst.type = handleType;
@@ -595,7 +686,64 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i1, 0U))),
};
handle = editor.AddInstruction(f, 0, inst);
handle = editor.AddInstruction(f, startInst++, inst);
}
else if(createHandleFromBinding)
{
RDCASSERT(isShaderModel6_6OrAbove);
const DXIL::Type *resBindType = editor.GetTypeByName("dx.types.ResBind");
DXIL::Constant resBindConstant(resBindType, 0U);
resBindConstant.members = {
// Lower id bound
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 0))),
// Upper id bound
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 0))),
// Space ID
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, space))),
// kind = UAV
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i8, (uint32_t)DXIL::HandleKind::UAV))),
};
DXIL::Instruction inst;
inst.op = DXIL::Operation::Call;
inst.type = handleType;
inst.funcCall = createHandleFromBinding;
inst.args = {
// dx.op.createHandleFromBinding opcode
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 217U))),
// resBind
DXIL::Value(editor.GetOrAddConstant(f, resBindConstant)),
// ID/slot
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 0U))),
// non-uniform
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i1, 0U))),
};
handle = editor.AddInstruction(f, startInst++, inst);
const DXIL::Type *resPropsType = editor.GetTypeByName("dx.types.ResourceProperties");
DXIL::Constant resPropConstant(resPropsType, 0U);
resPropConstant.members = {
// IsUav : (1 << 12)
DXIL::Value(editor.GetOrAddConstant(
f, DXIL::Constant(i32, (1 << 12) | (uint32_t)DXIL::ResourceKind::RawBuffer))),
//
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 0))),
};
// Annotate handle
DXIL::Instruction inst2;
inst2.op = DXIL::Operation::Call;
inst2.type = handleType;
inst2.funcCall = editor.GetFunctionByName("dx.op.annotateHandle");
inst2.args = {// dx.op.annotateHandle opcode
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 216U))),
// Resource handle
DXIL::Value(handle),
// Resource properties
DXIL::Value(editor.GetOrAddConstant(f, resPropConstant))};
handle = editor.AddInstruction(f, startInst++, inst2);
}
const DXIL::Constant *undefi32;
@@ -629,41 +777,102 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, magicFeedbackValue))),
};
editor.AddInstruction(f, 1, inst);
editor.AddInstruction(f, startInst++, inst);
}
for(size_t i = 2; i < f->instructions.size(); i++)
for(size_t i = startInst; i < f->instructions.size(); i++)
{
const DXIL::Instruction &inst = f->instructions[i];
// we want to annotate any calls to createHandle
if(inst.op == DXIL::Operation::Call && inst.funcCall->name == createHandle->name)
if(inst.op == DXIL::Operation::Call &&
((createHandle && inst.funcCall->name == createHandle->name) ||
(createHandleFromBinding && inst.funcCall->name == createHandleFromBinding->name)))
{
if(inst.args.size() != 5)
{
RDCERR("Unexpected number of arguments to createHandle");
continue;
}
DXIL::Value kindArg = inst.args[1];
DXIL::Value idArg = inst.args[2];
DXIL::Value idxArg = inst.args[3];
if(kindArg.type != DXIL::ValueType::Constant || idArg.type != DXIL::ValueType::Constant)
{
RDCERR("Unexpected non-constant argument to createHandle");
continue;
}
DXIL::HandleKind kind = (DXIL::HandleKind)kindArg.constant->val.u32v[0];
uint32_t id = idArg.constant->val.u32v[0];
DXIL::Value idxArg;
rdcpair<uint32_t, int32_t> slotInfo = {0, 0};
if((createHandle && inst.funcCall->name == createHandle->name))
{
RDCASSERT(!isShaderModel6_6OrAbove);
if(inst.args.size() != 5)
{
RDCERR("Unexpected number of arguments to createHandle");
continue;
}
if(kind == DXIL::HandleKind::SRV && id < srvBaseSlots.size())
slotInfo = srvBaseSlots[id];
else if(kind == DXIL::HandleKind::UAV && id < uavBaseSlots.size())
slotInfo = uavBaseSlots[id];
DXIL::Value kindArg = inst.args[1];
DXIL::Value idArg = inst.args[2];
idxArg = inst.args[3];
if(kindArg.type != DXIL::ValueType::Constant || idArg.type != DXIL::ValueType::Constant)
{
RDCERR("Unexpected non-constant argument to createHandle");
continue;
}
DXIL::HandleKind kind = (DXIL::HandleKind)kindArg.constant->val.u32v[0];
uint32_t id = idArg.constant->val.u32v[0];
if(kind == DXIL::HandleKind::SRV && id < srvBaseSlots.size())
slotInfo = srvBaseSlots[id];
else if(kind == DXIL::HandleKind::UAV && id < uavBaseSlots.size())
slotInfo = uavBaseSlots[id];
}
else
{
RDCASSERT(isShaderModel6_6OrAbove);
if(inst.args.size() != 4)
{
RDCERR("Unexpected number of arguments to createHandleFromBinding");
continue;
}
DXIL::Value resBindArg = inst.args[1];
idxArg = inst.args[2];
if(resBindArg.type != DXIL::ValueType::Constant)
{
RDCERR("Unexpected non-constant argument to createHandleFromBinding");
continue;
}
if(resBindArg.constant->members.size() != 4 && !resBindArg.constant->nullconst)
{
RDCERR("Unexpected number of members to resBind");
continue;
}
D3D12FeedbackKey key;
if(resBindArg.constant->nullconst)
{
key.type = DXBCBytecode::TYPE_RESOURCE;
key.bind.bindset = 0;
key.bind.bind = 0;
}
else
{
DXIL::Value regArg = resBindArg.constant->members[0];
DXIL::Value spaceArg = resBindArg.constant->members[2];
DXIL::Value kindArg = resBindArg.constant->members[3];
if(regArg.type != DXIL::ValueType::Constant ||
spaceArg.type != DXIL::ValueType::Constant || kindArg.type != DXIL::ValueType::Constant)
{
RDCERR("Unexpected non-constant argument to createHandleFromBinding");
continue;
}
DXIL::HandleKind kind = (DXIL::HandleKind)kindArg.constant->val.u32v[0];
if(kind != DXIL::HandleKind::SRV && kind != DXIL::HandleKind::UAV)
continue;
key.type = kind == DXIL::HandleKind::UAV ? DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW
: DXBCBytecode::TYPE_RESOURCE;
key.bind.bindset = spaceArg.constant->val.u32v[0];
key.bind.bind = regArg.constant->val.u32v[0];
}
auto it = slots.find(key);
// not annotated
if(it == slots.end())
continue;
// static used i.e. not arrayed? ignore
if(it->second.StaticUsed())
continue;
slotInfo = {it->second.Slot(), key.bind.bind};
}
if(slotInfo.first == 0)
continue;
@@ -724,6 +933,148 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, magicFeedbackValue))),
};
// don't care about the return value from this
editor.AddInstruction(f, i, op);
i++;
}
else if(inst.op == DXIL::Operation::Call && createHandleFromHeap &&
inst.funcCall->name == createHandleFromHeap->name)
{
RDCASSERT(isShaderModel6_6OrAbove);
if(inst.args.size() != 4)
{
RDCERR("Unexpected number of arguments to createHandleFromHeap");
continue;
}
DXIL::Value isSamplerArg = inst.args[2];
if(isSamplerArg.type != DXIL::ValueType::Constant)
{
RDCERR("Unexpected non-constant argument to createHandleFromHeap");
continue;
}
bool isSampler = isSamplerArg.constant->val.u32v[0] != 0;
D3D12FeedbackKey key = GetDirectHeapAccessKey();
auto it = slots.find(key);
if(it == slots.end())
continue;
// Look for annotation for the type of this view ( SRV/UAV/CBV/Sampler )
const DXIL::Instruction *annotateInst = NULL;
for(size_t nextInstIndex = i + 1; nextInstIndex < f->instructions.size(); nextInstIndex++)
{
const DXIL::Instruction &nextInst = f->instructions[nextInstIndex];
if(nextInst.op == DXIL::Operation::Call && annotateHandle &&
nextInst.funcCall->name == annotateHandle->name)
{
if(nextInst.args.size() != 3)
{
RDCERR("Unexpected number of arguments to annotateHandle");
continue;
}
DXIL::Value idxArg = nextInst.args[1];
DXIL::Value instValue(&inst);
if(idxArg.instruction->resultID == instValue.instruction->resultID)
{
annotateInst = &nextInst;
break;
}
}
}
if(annotateInst == NULL)
{
RDCERR("Unexpected, could not find annotateHandle for createHandleFromHeap");
continue;
}
DXIL::Value resPropArg = annotateInst->args[2];
if(resPropArg.type != DXIL::ValueType::Constant)
{
RDCERR("Unexpected non-constant argument for dx.types.ResourceProperties");
continue;
}
if(resPropArg.constant->members.size() != 2)
{
RDCERR("Unexpected number of arguments to dx.types.ResourceProperties");
continue;
}
DXIL::Value resKindArg = resPropArg.constant->members[0];
if(resKindArg.type != DXIL::ValueType::Constant)
{
RDCERR("Unexpected non-constant argument for dx.types.ResourceProperties's resource kind");
continue;
}
DXIL::HandleKind handleKind = DXIL::HandleKind::SRV;
DXIL::ResourceKind resKind = (DXIL::ResourceKind)(resKindArg.constant->val.u32v[0] & 0xFF);
bool isUav = (resKindArg.constant->val.u32v[0] & (1 << 12)) != 0;
if(resKind == DXIL::ResourceKind::Sampler || resKind == DXIL::ResourceKind::SamplerComparison)
{
handleKind = DXIL::HandleKind::Sampler;
RDCASSERT(isSampler);
RDCASSERT(!isUav);
}
else if(resKind == DXIL::ResourceKind::CBuffer)
{
handleKind = DXIL::HandleKind::CBuffer;
RDCASSERT(!isSampler);
RDCASSERT(!isUav);
}
else if(isUav)
{
handleKind = DXIL::HandleKind::UAV;
RDCASSERT(!isSampler);
}
else
{
handleKind = DXIL::HandleKind::SRV;
RDCASSERT(!isSampler);
}
DXIL::Value idxArg = inst.args[1];
DXIL::Instruction op;
op.op = DXIL::Operation::Add;
op.type = i32;
op.args = {
// idx to the createHandleFromHeap op
DXIL::Value(idxArg),
// base slot
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, it->second.Slot()))),
};
// slotPlusBase = idx0Based + slot
DXIL::Instruction *slotPlusBase = editor.AddInstruction(f, i, op);
i++;
op.op = DXIL::Operation::ShiftLeft;
op.type = i32;
op.args = {
DXIL::Value(slotPlusBase), DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 2U))),
};
// byteOffset = slotPlusBase << 2
DXIL::Instruction *byteOffset = editor.AddInstruction(f, i, op);
i++;
uint32_t feedbackValue = magicFeedbackValue | (1 << (uint32_t)handleKind);
op.op = DXIL::Operation::Call;
op.type = i32;
op.funcCall = atomicBinOp;
op.args = {
// dx.op.atomicBinOp.i32 opcode
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 78U))),
// feedback UAV handle
DXIL::Value(handle),
// operation OR
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, 2U))),
// offset
DXIL::Value(byteOffset),
// offset 2
DXIL::Value(undefi32),
// offset 3
DXIL::Value(undefi32),
// value
DXIL::Value(editor.GetOrAddConstant(f, DXIL::Constant(i32, feedbackValue))),
};
// don't care about the return value from this
editor.AddInstruction(f, i, op);
i++;
@@ -736,7 +1087,7 @@ static bool AnnotateDXILShader(const DXBC::DXBCContainer *dxbc, uint32_t space,
static void AddArraySlots(WrappedID3D12PipelineState::ShaderEntry *shad, uint32_t space,
uint32_t maxDescriptors,
std::map<D3D12FeedbackKey, D3D12FeedbackSlot> &slots, uint32_t &numSlots,
bytebuf &editedBlob, D3D12_SHADER_BYTECODE &desc)
bytebuf &editedBlob, D3D12_SHADER_BYTECODE &desc, bool directHeapAccess)
{
if(!shad)
return;
@@ -798,6 +1149,21 @@ static void AddArraySlots(WrappedID3D12PipelineState::ShaderEntry *shad, uint32_
}
}
if(shad->GetDXBC()->m_Version.Major < 6 ||
(shad->GetDXBC()->m_Version.Major == 6 && shad->GetDXBC()->m_Version.Minor < 6))
{
directHeapAccess = false;
}
if(directHeapAccess)
directHeapAccess = shad->GetDXBC()->GetDXILByteCode()->GetDirectHeapAcessCount() > 0;
if(directHeapAccess)
{
D3D12FeedbackKey key = GetDirectHeapAccessKey();
slots[key].SetSlot(numSlots);
numSlots += maxDescriptors;
}
// if we haven't encountered any array slots, no need to do any patching
if(numSlots == numReservedSlots)
return;
@@ -888,7 +1254,7 @@ void D3D12Replay::FetchShaderFeedback(uint32_t eventId)
return;
}
bytebuf editedBlob[5];
bytebuf editedBlob[(uint32_t)ShaderStage::Count];
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC pipeDesc;
pipe->Fill(pipeDesc);
@@ -898,17 +1264,14 @@ void D3D12Replay::FetchShaderFeedback(uint32_t eventId)
uint32_t maxDescriptors = 0;
for(ResourceId id : rs.heaps)
{
D3D12_DESCRIPTOR_HEAP_DESC desc = rm->GetCurrentAs<ID3D12DescriptorHeap>(id)->GetDesc();
if(desc.Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
{
maxDescriptors = desc.NumDescriptors;
RDCDEBUG("Clamping any unbounded ranges to %u descriptors", maxDescriptors);
break;
}
WrappedID3D12DescriptorHeap *heap =
(WrappedID3D12DescriptorHeap *)rm->GetCurrentAs<ID3D12DescriptorHeap>(id);
D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc();
maxDescriptors = RDCMAX(maxDescriptors, desc.NumDescriptors);
}
RDCDEBUG("Clamping any unbounded ranges to %u descriptors", maxDescriptors);
std::map<D3D12FeedbackKey, D3D12FeedbackSlot> slots[6];
std::map<D3D12FeedbackKey, D3D12FeedbackSlot> slots[(uint32_t)ShaderStage::Count];
// reserve the first 4 dwords for debug info and a validity flag
uint32_t numSlots = numReservedSlots;
@@ -925,10 +1288,13 @@ void D3D12Replay::FetchShaderFeedback(uint32_t eventId)
return;
modsig = ((WrappedID3D12RootSignature *)sig)->sig;
bool directHeapAccess =
(modsig.Flags & (D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |
D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED)) != 0;
space = modsig.maxSpaceIndex;
AddArraySlots(pipe->CS(), space, maxDescriptors, slots[0], numSlots, editedBlob[0], pipeDesc.CS);
AddArraySlots(pipe->CS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Compute], numSlots,
editedBlob[(uint32_t)ShaderStage::Compute], pipeDesc.CS, directHeapAccess);
}
else
{
@@ -938,14 +1304,22 @@ void D3D12Replay::FetchShaderFeedback(uint32_t eventId)
return;
modsig = ((WrappedID3D12RootSignature *)sig)->sig;
bool directHeapAccess =
(modsig.Flags & (D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |
D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED)) != 0;
space = modsig.maxSpaceIndex;
AddArraySlots(pipe->VS(), space, maxDescriptors, slots[0], numSlots, editedBlob[0], pipeDesc.VS);
AddArraySlots(pipe->HS(), space, maxDescriptors, slots[1], numSlots, editedBlob[1], pipeDesc.HS);
AddArraySlots(pipe->DS(), space, maxDescriptors, slots[2], numSlots, editedBlob[2], pipeDesc.DS);
AddArraySlots(pipe->GS(), space, maxDescriptors, slots[3], numSlots, editedBlob[3], pipeDesc.GS);
AddArraySlots(pipe->PS(), space, maxDescriptors, slots[4], numSlots, editedBlob[4], pipeDesc.PS);
AddArraySlots(pipe->VS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Vertex], numSlots,
editedBlob[uint32_t(ShaderStage::Vertex)], pipeDesc.VS, directHeapAccess);
AddArraySlots(pipe->HS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Hull], numSlots,
editedBlob[uint32_t(ShaderStage::Hull)], pipeDesc.HS, directHeapAccess);
AddArraySlots(pipe->DS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Domain], numSlots,
editedBlob[uint32_t(ShaderStage::Domain)], pipeDesc.DS, directHeapAccess);
AddArraySlots(pipe->GS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Geometry], numSlots,
editedBlob[uint32_t(ShaderStage::Geometry)], pipeDesc.GS, directHeapAccess);
AddArraySlots(pipe->PS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Pixel], numSlots,
editedBlob[uint32_t(ShaderStage::Pixel)], pipeDesc.PS, directHeapAccess);
}
// if numSlots wasn't increased, none of the resources were arrayed so we have nothing to do.
@@ -1139,12 +1513,20 @@ void D3D12Replay::FetchShaderFeedback(uint32_t eventId)
// see which shader's binds we should look up for this range
switch(p.ShaderVisibility)
{
case D3D12_SHADER_VISIBILITY_ALL: visMask = result.compute ? 0x1 : 0xff; break;
case D3D12_SHADER_VISIBILITY_VERTEX: visMask = 1 << 0; break;
case D3D12_SHADER_VISIBILITY_HULL: visMask = 1 << 1; break;
case D3D12_SHADER_VISIBILITY_DOMAIN: visMask = 1 << 2; break;
case D3D12_SHADER_VISIBILITY_GEOMETRY: visMask = 1 << 3; break;
case D3D12_SHADER_VISIBILITY_PIXEL: visMask = 1 << 4; break;
case D3D12_SHADER_VISIBILITY_ALL:
visMask = result.compute ? (uint32_t)ShaderStageMask::Compute : 0xff;
break;
case D3D12_SHADER_VISIBILITY_VERTEX:
visMask = (uint32_t)ShaderStageMask::Vertex;
break;
case D3D12_SHADER_VISIBILITY_HULL: visMask = (uint32_t)ShaderStageMask::Hull; break;
case D3D12_SHADER_VISIBILITY_DOMAIN:
visMask = (uint32_t)ShaderStageMask::Domain;
break;
case D3D12_SHADER_VISIBILITY_GEOMETRY:
visMask = (uint32_t)ShaderStageMask::Geometry;
break;
case D3D12_SHADER_VISIBILITY_PIXEL: visMask = uint32_t(ShaderStageMask::Pixel); break;
default: RDCERR("Unexpected shader visibility %d", p.ShaderVisibility); return;
}
@@ -1154,7 +1536,7 @@ void D3D12Replay::FetchShaderFeedback(uint32_t eventId)
else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV)
curKey.type = DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW;
for(uint32_t st = 0; st < 5; st++)
for(uint32_t st = 0; st < (uint32_t)ShaderStage::Count; st++)
{
if(visMask & (1 << st))
{
@@ -1214,6 +1596,51 @@ void D3D12Replay::FetchShaderFeedback(uint32_t eventId)
}
}
D3D12FeedbackKey directAccessKey = GetDirectHeapAccessKey();
for(uint32_t shaderStage = 0; shaderStage < (uint32_t)ShaderStage::Count; shaderStage++)
{
if(slots[shaderStage].find(directAccessKey) == slots[shaderStage].end())
continue;
D3D12FeedbackSlot &feedbackSlots = slots[shaderStage].at(directAccessKey);
for(uint32_t i = feedbackSlots.Slot(); i < feedbackSlots.Slot() + maxDescriptors; ++i)
{
if((slotsData[i] & magicFeedbackValue) == magicFeedbackValue)
{
uint32_t usedSlot = i - feedbackSlots.Slot();
D3D12FeedbackBindIdentifier directAccessIdentifier = {};
directAccessIdentifier.descIndex = usedSlot;
directAccessIdentifier.rootEl = ~0U;
directAccessIdentifier.rangeIndex = ~0U;
directAccessIdentifier.directAccess = true;
directAccessIdentifier.shaderStage = (ShaderStage)shaderStage;
uint32_t handleKind = slotsData[i] & magicFeedbackTypeMask;
if((handleKind & (1 << (uint32_t)DXIL::HandleKind::Sampler)) != 0)
{
directAccessIdentifier.bindType = BindType::Sampler;
result.used.push_back(directAccessIdentifier);
}
bool isCBV = (handleKind & (1 << (uint32_t)DXIL::HandleKind::CBuffer)) != 0;
bool isSRV = (handleKind & (1 << (uint32_t)DXIL::HandleKind::SRV)) != 0;
bool isUAV = (handleKind & (1 << (uint32_t)DXIL::HandleKind::UAV)) != 0;
if(isCBV || isSRV || isUAV)
{
if((isCBV && isSRV) || (isCBV && isUAV) || (isSRV && isUAV))
{
RDCERR("Unexpected, resource used with multiple incompatible types");
continue;
}
if(isCBV)
directAccessIdentifier.bindType = BindType::ConstantBuffer;
else if(isSRV)
directAccessIdentifier.bindType = BindType::ReadOnlyResource;
else if(isUAV)
directAccessIdentifier.bindType = BindType::ReadWriteResource;
result.used.push_back(directAccessIdentifier);
}
}
}
}
std::sort(result.used.begin(), result.used.end());
}
else
@@ -1300,6 +1300,8 @@ Program::Program(const byte *bytes, size_t length)
if(!inst.type->isVoid())
m_Values.push_back(Value(&f.instructions.back()));
if(inst.funcCall->name == "dx.op.createHandleFromHeap")
m_directHeapAccessCount++;
}
else if(op.type == FunctionRecord::INST_CAST)
{
@@ -673,6 +673,7 @@ public:
const Metadata *GetMetadataByName(const rdcstr &name) const;
size_t GetMetadataCount() const { return m_Metadata.size() + m_NamedMeta.size(); }
uint32_t GetDirectHeapAcessCount() const { return m_directHeapAccessCount; }
protected:
void MakeDisassemblyString();
@@ -703,6 +704,7 @@ protected:
rdcarray<Alias> m_Aliases;
rdcarray<Value> m_Values;
rdcarray<rdcstr> m_Sections;
uint32_t m_directHeapAccessCount = 0;
rdcarray<rdcstr> m_Kinds;
@@ -722,6 +722,34 @@ Metadata *ProgramEditor::AddMetadata(const Metadata &m)
return &m_Metadata.back();
}
NamedMetadata *ProgramEditor::AddNamedMetadata(const NamedMetadata &m)
{
if(m.dwarf || m.debugLoc)
{
RDCERR("Metadata with debug information is not supported");
return NULL;
}
// check that inner pointers are valid
if(m.type && !IN_ARRAY(m_Types, m.type) && !IN_ARRAY(m_OldTypes, m.type))
{
RDCERR("Metadata references invalid type");
return NULL;
}
for(const Metadata *c : m.children)
{
if(c && !IN_ARRAY(m_Metadata, c) && !IN_ARRAY(m_OldMetadata, c))
{
RDCERR("New metadata references invalid member metadata");
return NULL;
}
}
m_NamedMeta.push_back(m);
return &m_NamedMeta.back();
}
const Constant *ProgramEditor::GetOrAddConstant(const Constant &c)
{
// check that inner pointers are valid
@@ -1974,28 +2002,40 @@ void ProgramEditor::RegisterUAV(DXILResourceType type, uint32_t space, uint32_t
if(cur >= end)
return;
uint32_t *resourceBindSize = (uint32_t *)cur;
cur += sizeof(uint32_t);
if(cur >= end)
return;
// fortunately UAVs are the last entry so we don't need to walk the list to insert in the right
// place, we can just add it at the end
cur += (*resourceBindSize) * (*numResources);
if(cur >= end)
return;
// add an extra resource
(*numResources)++;
if(*resourceBindSize == sizeof(ResourceBind1) || *resourceBindSize == sizeof(ResourceBind0))
if(*numResources > 0)
{
psv0blob.insert(cur - begin, (byte *)&bind, *resourceBindSize);
uint32_t *resourceBindSize = (uint32_t *)cur;
cur += sizeof(uint32_t);
if(cur >= end)
return;
// fortunately UAVs are the last entry so we don't need to walk the list to insert in the
// right place, we can just add it at the end
cur += (*resourceBindSize) * (*numResources);
if(cur >= end)
return;
// add an extra resource
(*numResources)++;
if(*resourceBindSize == sizeof(ResourceBind1) || *resourceBindSize == sizeof(ResourceBind0))
{
psv0blob.insert(cur - begin, (byte *)&bind, *resourceBindSize);
}
else
{
RDCERR("Unexpected resource bind size %u", *resourceBindSize);
return;
}
}
else
{
RDCERR("Unexpected resource bind size %u", *resourceBindSize);
return;
// If there is no resource in the chunk we also need to insert the size of a resource bind
*numResources = 1;
size_t insertOffset = cur - begin;
uint32_t resourceBindSize = sizeof(ResourceBind1);
psv0blob.insert(insertOffset, (byte *)&resourceBindSize, sizeof(resourceBindSize));
psv0blob.insert(insertOffset + sizeof(resourceBindSize), (byte *)&bind, resourceBindSize);
}
DXBC::DXBCContainer::ReplaceChunk(m_OutBlob, DXBC::FOURCC_PSV0, psv0blob);
@@ -76,6 +76,7 @@ public:
const rdcarray<AttributeSet> &GetAttributeSets() { return m_AttributeSets; }
// find existing type or metadata by name, returns NULL if not found
const rdcarray<Type> &GetTypes() const { return m_Types; }
const Type *GetTypeByName(const rdcstr &name);
Function *GetFunctionByName(const rdcstr &name);
Metadata *GetMetadataByName(const rdcstr &name);
@@ -85,6 +86,7 @@ public:
const Type *AddType(const Type &t);
const Function *DeclareFunction(const Function &f);
Metadata *AddMetadata(const Metadata &m);
NamedMetadata *AddNamedMetadata(const NamedMetadata &m);
// I think constants have to be unique, so this will return an existing constant (for simple cases
// like integers or NULL) if it exists