mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Add support for shader model 6.6 bindless resources.
This commit is contained in:
committed by
Baldur Karlsson
parent
c122b41155
commit
dfd00b1e38
@@ -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;
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user