From 1137c4694cb975241d50dc0c6d837994feb3414d Mon Sep 17 00:00:00 2001 From: Steve Karolewics Date: Sat, 4 Apr 2020 13:01:01 -0700 Subject: [PATCH] Make D3D12Pipe root element centric instead of shader centric D3D12Pipe now stores an array of root elements, each one corresponding to a root element or range in the root signature. Migrated usage in the D3D12 pipeline state viewer and PipeState retrieval of resources. Restricted number of resource array textures displayed in the texture viewer to prevent app hangs. --- qrenderdoc/Code/pyrenderdoc/renderdoc.i | 2 +- .../D3D12PipelineStateViewer.cpp | 1151 +++++++++-------- .../PipelineState/D3D12PipelineStateViewer.h | 6 +- qrenderdoc/Windows/TextureViewer.cpp | 6 +- renderdoc/api/replay/d3d12_pipestate.h | 153 ++- renderdoc/api/replay/pipestate.inl | 124 +- renderdoc/api/replay/renderdoc_tostr.inl | 2 + renderdoc/api/replay/replay_enums.h | 10 + renderdoc/driver/d3d12/d3d12_replay.cpp | 390 +++--- renderdoc/driver/d3d12/d3d12_replay.h | 7 +- renderdoc/replay/renderdoc_serialise.inl | 50 +- 11 files changed, 934 insertions(+), 967 deletions(-) diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index a554e9f6c..b22a8e397 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -358,9 +358,9 @@ TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D11Pipe, VertexBuffer) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D11Pipe, View) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, ConstantBuffer) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, Layout) -TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, RegisterSpace) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, ResourceData) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, ResourceState) +TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, RootSignatureRange) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, Sampler) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, StreamOutBind) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, VertexBuffer) diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 0bf1d50dd..ebf24e103 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -57,22 +57,23 @@ struct D3D12CBufTag D3D12CBufTag() { idx = ~0U; - space = reg = arrayIdx = 0; + space = reg = rootElement = arrayIdx = 0; } - D3D12CBufTag(uint32_t s, uint32_t r) + D3D12CBufTag(uint32_t s, uint32_t r, uint32_t el) { idx = ~0U; space = s; reg = r; + rootElement = el; arrayIdx = 0; } D3D12CBufTag(uint32_t i) { idx = i; - space = reg = arrayIdx = 0; + space = reg = rootElement = arrayIdx = 0; } - uint32_t idx, space, reg, arrayIdx; + uint32_t idx, space, reg, rootElement, arrayIdx; }; Q_DECLARE_METATYPE(D3D12CBufTag); @@ -87,14 +88,15 @@ struct D3D12ViewTag OMDepth, }; - D3D12ViewTag() : type(SRV), space(0), reg(0) {} - D3D12ViewTag(ResType t, int s, int r, const D3D12Pipe::View &rs) - : type(t), space(s), reg(r), res(rs) + D3D12ViewTag() : type(SRV), space(0), rootElement(0), immediate(false) {} + D3D12ViewTag(ResType t, int s, int el, bool imm, const D3D12Pipe::View &rs) + : type(t), space(s), rootElement(el), immediate(imm), res(rs) { } ResType type; - int space, reg; + int space, rootElement; + bool immediate; D3D12Pipe::View res; }; @@ -637,10 +639,6 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, const D3D12Pipe::View &r = view.res; bool uav = view.type == D3D12ViewTag::UAV; - // consider this register to not exist - it's in a gap defined by sparse root signature elements - if(r.rootElement == ~0U) - return; - const Bindpoint *bind = NULL; const ShaderResource *shaderInput = NULL; @@ -654,12 +652,12 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, { const Bindpoint &b = binds[i]; - bool regMatch = b.bind == view.reg; + bool regMatch = (b.bind == (int)view.res.bind); // handle unbounded arrays specially. It's illegal to have an unbounded array with // anything after it - if(b.bind <= view.reg) - regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > view.reg); + if(b.bind <= (int)view.res.bind) + regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > (int)view.res.bind); if(b.bindset == view.space && regMatch) { @@ -679,7 +677,7 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, if(showNode(usedSlot, filledSlot)) { - QString regname = QString::number(view.reg); + QString regname = QString::number(view.res.bind); if(shaderInput && !shaderInput->name.empty()) regname += lit(": ") + shaderInput->name; @@ -762,7 +760,8 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, if(view.type == D3D12ViewTag::OMTarget) { - node = new RDTreeWidgetItem({view.reg, r.resourceId, typeName, w, h, d, a, format, QString()}); + node = new RDTreeWidgetItem( + {view.res.bind, r.resourceId, typeName, w, h, d, a, format, QString()}); } else if(view.type == D3D12ViewTag::OMDepth) { @@ -771,8 +770,8 @@ void D3D12PipelineStateViewer::addResourceRow(const D3D12ViewTag &view, } else { - QString rootel = r.immediate ? tr("#%1 Direct").arg(r.rootElement) - : tr("#%1 Table[%2]").arg(r.rootElement).arg(r.tableIndex); + QString rootel = view.immediate ? tr("#%1 Direct").arg(view.rootElement) + : tr("#%1 Table[%2]").arg(view.rootElement).arg(r.tableIndex); node = new RDTreeWidgetItem( {rootel, view.space, regname, r.resourceId, typeName, w, h, d, a, format, QString()}); @@ -954,10 +953,10 @@ void D3D12PipelineStateViewer::clearState() } } -void D3D12PipelineStateViewer::setShaderState(const D3D12Pipe::Shader &stage, RDLabel *shader, - RDLabel *rootSig, RDTreeWidget *resources, - RDTreeWidget *samplers, RDTreeWidget *cbuffers, - RDTreeWidget *uavs) +void D3D12PipelineStateViewer::setShaderState( + const rdcarray &rootElements, const D3D12Pipe::Shader &stage, + RDLabel *shader, RDLabel *rootSig, RDTreeWidget *resources, RDTreeWidget *samplers, + RDTreeWidget *cbuffers, RDTreeWidget *uavs) { ShaderReflection *shaderDetails = stage.reflection; const D3D12Pipe::State &state = *m_Ctx.CurD3D12PipelineState(); @@ -979,273 +978,282 @@ void D3D12PipelineStateViewer::setShaderState(const D3D12Pipe::Shader &stage, RD } shader->setText(shText); - int vs = 0; - - vs = resources->verticalScrollBar()->value(); + int resVs = resources->verticalScrollBar()->value(); resources->beginUpdate(); resources->clear(); - for(int space = 0; space < stage.spaces.count(); space++) - { - for(int reg = 0; reg < stage.spaces[space].srvs.count(); reg++) - { - addResourceRow(D3D12ViewTag(D3D12ViewTag::SRV, stage.spaces[space].spaceIndex, reg, - stage.spaces[space].srvs[reg]), - &stage, resources); - } - } - resources->clearSelection(); - resources->endUpdate(); - resources->verticalScrollBar()->setValue(vs); - - vs = uavs->verticalScrollBar()->value(); + int uavVs = uavs->verticalScrollBar()->value(); uavs->beginUpdate(); uavs->clear(); - for(int space = 0; space < stage.spaces.count(); space++) - { - for(int reg = 0; reg < stage.spaces[space].uavs.count(); reg++) - { - addResourceRow(D3D12ViewTag(D3D12ViewTag::UAV, stage.spaces[space].spaceIndex, reg, - stage.spaces[space].uavs[reg]), - &stage, uavs); - } - } - uavs->clearSelection(); - uavs->endUpdate(); - uavs->verticalScrollBar()->setValue(vs); - - vs = samplers->verticalScrollBar()->value(); + int sampVs = samplers->verticalScrollBar()->value(); samplers->beginUpdate(); samplers->clear(); - for(int space = 0; space < stage.spaces.count(); space++) + int cbVs = cbuffers->verticalScrollBar()->value(); + cbuffers->beginUpdate(); + cbuffers->clear(); + + for(size_t i = 0; i < rootElements.size(); ++i) { - for(int reg = 0; reg < stage.spaces[space].samplers.count(); reg++) + if((rootElements[i].visibility & MaskForStage(stage.stage)) == ShaderStageMask::Unknown) + continue; + + switch(rootElements[i].type) { - const D3D12Pipe::Sampler &s = stage.spaces[space].samplers[reg]; - - // consider this register to not exist - it's in a gap defined by sparse root signature - // elements - if(s.rootElement == ~0U) - continue; - - const Bindpoint *bind = NULL; - const ShaderSampler *shaderInput = NULL; - - if(stage.reflection) + case BindType::ReadOnlyResource: { - for(int i = 0; i < stage.bindpointMapping.samplers.count(); i++) + for(size_t j = 0; j < rootElements[i].views.size(); ++j) { - const Bindpoint &b = stage.bindpointMapping.samplers[i]; - const ShaderSampler &res = stage.reflection->samplers[i]; + addResourceRow(D3D12ViewTag(D3D12ViewTag::SRV, rootElements[i].registerSpace, (int)i, + rootElements[i].immediate, rootElements[i].views[j]), + &stage, resources); + } + break; + } + case BindType::ReadWriteResource: + { + for(size_t j = 0; j < rootElements[i].views.size(); ++j) + { + addResourceRow(D3D12ViewTag(D3D12ViewTag::UAV, rootElements[i].registerSpace, (int)i, + rootElements[i].immediate, rootElements[i].views[j]), + &stage, uavs); + } + break; + } + case BindType::Sampler: + { + for(size_t j = 0; j < rootElements[i].samplers.size(); ++j) + { + const D3D12Pipe::Sampler &s = rootElements[i].samplers[j]; - bool regMatch = b.bind == reg; + const Bindpoint *bind = NULL; + const ShaderSampler *shaderInput = NULL; - // handle unbounded arrays specially. It's illegal to have an unbounded array with - // anything after it - if(b.bind <= reg) - regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > reg); - - if(b.bindset == (int32_t)stage.spaces[space].spaceIndex && regMatch) + if(stage.reflection) { - bind = &b; - shaderInput = &res; - break; + for(int k = 0; k < stage.bindpointMapping.samplers.count(); ++k) + { + const Bindpoint &b = stage.bindpointMapping.samplers[k]; + const ShaderSampler &res = stage.reflection->samplers[k]; + + bool regMatch = (b.bind == (int)s.bind); + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if(b.bind <= (int)s.bind) + regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > (int)s.bind); + + if(b.bindset == (int)rootElements[i].registerSpace && regMatch) + { + bind = &b; + shaderInput = &res; + break; + } + } + } + + QString rootel = + rootElements[i].immediate + ? tr("#%1 Static").arg(rootElements[i].rootElement) + : tr("#%1 Table[%2]").arg(rootElements[i].rootElement).arg(s.tableIndex); + + bool filledSlot = s.filter.minify != FilterMode::NoFilter; + bool usedSlot = (bind && bind->used); + + if(showNode(usedSlot, filledSlot)) + { + QString regname = QString::number(s.bind); + + if(shaderInput && !shaderInput->name.empty()) + regname += lit(": ") + shaderInput->name; + + QString borderColor = QFormatStr("%1, %2, %3, %4") + .arg(s.borderColor[0]) + .arg(s.borderColor[1]) + .arg(s.borderColor[2]) + .arg(s.borderColor[3]); + + QString addressing; + + QString addPrefix; + QString addVal; + + QString addr[] = {ToQStr(s.addressU, GraphicsAPI::D3D12), + ToQStr(s.addressV, GraphicsAPI::D3D12), + ToQStr(s.addressW, GraphicsAPI::D3D12)}; + + // arrange like either UVW: WRAP or UV: WRAP, W: CLAMP + for(int a = 0; a < 3; a++) + { + const QString str[] = {lit("U"), lit("V"), lit("W")}; + QString prefix = str[a]; + + if(a == 0 || addr[a] == addr[a - 1]) + { + addPrefix += prefix; + } + else + { + addressing += QFormatStr("%1: %2, ").arg(addPrefix).arg(addVal); + + addPrefix = prefix; + } + addVal = addr[a]; + } + + addressing += addPrefix + lit(": ") + addVal; + + if(s.UseBorder()) + addressing += QFormatStr("<%1>").arg(borderColor); + + QString filter = ToQStr(s.filter); + + if(s.maxAnisotropy > 1) + filter += QFormatStr(" %1x").arg(s.maxAnisotropy); + + if(s.filter.filter == FilterFunction::Comparison) + filter += QFormatStr(" (%1)").arg(ToQStr(s.compareFunction)); + else if(s.filter.filter != FilterFunction::Normal) + filter += QFormatStr(" (%1)").arg(ToQStr(s.filter.filter)); + + RDTreeWidgetItem *node = new RDTreeWidgetItem( + {rootel, rootElements[i].registerSpace, 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)), + s.mipLODBias}); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + + samplers->addTopLevelItem(node); } } + break; } - - QString rootel = s.immediate ? tr("#%1 Static").arg(s.rootElement) - : tr("#%1 Table[%2]").arg(s.rootElement).arg(s.tableIndex); - - bool filledSlot = s.filter.minify != FilterMode::NoFilter; - bool usedSlot = (bind && bind->used); - - if(showNode(usedSlot, filledSlot)) + case BindType::ConstantBuffer: { - QString regname = QString::number(reg); - - if(shaderInput && !shaderInput->name.empty()) - regname += lit(": ") + shaderInput->name; - - QString borderColor = QFormatStr("%1, %2, %3, %4") - .arg(s.borderColor[0]) - .arg(s.borderColor[1]) - .arg(s.borderColor[2]) - .arg(s.borderColor[3]); - - QString addressing; - - QString addPrefix; - QString addVal; - - QString addr[] = {ToQStr(s.addressU, GraphicsAPI::D3D12), - ToQStr(s.addressV, GraphicsAPI::D3D12), - ToQStr(s.addressW, GraphicsAPI::D3D12)}; - - // arrange like either UVW: WRAP or UV: WRAP, W: CLAMP - for(int a = 0; a < 3; a++) + for(size_t j = 0; j < rootElements[i].constantBuffers.size(); ++j) { - const QString str[] = {lit("U"), lit("V"), lit("W")}; - QString prefix = str[a]; + const D3D12Pipe::ConstantBuffer &b = rootElements[i].constantBuffers[j]; - if(a == 0 || addr[a] == addr[a - 1]) + QVariant tag; + + const Bindpoint *bind = NULL; + const ConstantBlock *shaderCBuf = NULL; + + if(stage.reflection) { - addPrefix += prefix; + for(int k = 0; k < stage.bindpointMapping.constantBlocks.count(); ++k) + { + const Bindpoint &bm = stage.bindpointMapping.constantBlocks[k]; + const ConstantBlock &res = stage.reflection->constantBlocks[k]; + + bool regMatch = bm.bind == (int)b.bind; + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if(bm.bind <= (int)b.bind) + regMatch = (bm.arraySize == ~0U) || (bm.bind + (int)bm.arraySize > (int)b.bind); + + if(bm.bindset == (int)rootElements[i].registerSpace && regMatch) + { + bind = &bm; + shaderCBuf = &res; + D3D12CBufTag cbufTag((uint32_t)i); + cbufTag.arrayIdx = b.bind - bm.bind; + tag = QVariant::fromValue(cbufTag); + break; + } + } + } + + if(!tag.isValid()) + tag = QVariant::fromValue( + D3D12CBufTag(rootElements[i].registerSpace, b.bind, rootElements[i].rootElement)); + + QString rootel; + + if(rootElements[i].immediate) + { + if(!b.rootValues.empty()) + rootel = tr("#%1 Consts").arg(rootElements[i].rootElement); + else + rootel = tr("#%1 Direct").arg(rootElements[i].rootElement); } else { - addressing += QFormatStr("%1: %2, ").arg(addPrefix).arg(addVal); - - addPrefix = prefix; + rootel = tr("#%1 Table[%2]").arg(rootElements[i].rootElement).arg(b.tableIndex); + } + + bool filledSlot = (b.resourceId != ResourceId()); + if(rootElements[i].immediate && !b.rootValues.empty()) + filledSlot = true; + + bool usedSlot = (bind && bind->used); + + if(showNode(usedSlot, filledSlot)) + { + ulong length = b.byteSize; + uint64_t offset = b.byteOffset; + int numvars = shaderCBuf ? shaderCBuf->variables.count() : 0; + uint32_t bytesize = shaderCBuf ? shaderCBuf->byteSize : 0; + + if(rootElements[i].immediate && !b.rootValues.empty()) + bytesize = uint32_t(b.rootValues.count() * 4); + + 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); + + QString sizestr; + if(bytesize == (uint32_t)length) + sizestr = tr("%1 Variables, %2 bytes").arg(numvars).arg(length); + else + sizestr = + tr("%1 Variables, %2 bytes needed, %3 provided").arg(numvars).arg(bytesize).arg(length); + + if(length < bytesize) + filledSlot = false; + + RDTreeWidgetItem *node = new RDTreeWidgetItem( + {rootel, (qulonglong)rootElements[i].registerSpace, regname, b.resourceId, + QFormatStr("%1 - %2").arg(offset).arg(offset + bytesize), sizestr, QString()}); + + node->setTag(tag); + + if(!filledSlot) + setEmptyRow(node); + + if(!usedSlot) + setInactiveRow(node); + + cbuffers->addTopLevelItem(node); } - addVal = addr[a]; } - - addressing += addPrefix + lit(": ") + addVal; - - if(s.UseBorder()) - addressing += QFormatStr("<%1>").arg(borderColor); - - QString filter = ToQStr(s.filter); - - if(s.maxAnisotropy > 1) - filter += QFormatStr(" %1x").arg(s.maxAnisotropy); - - if(s.filter.filter == FilterFunction::Comparison) - filter += QFormatStr(" (%1)").arg(ToQStr(s.compareFunction)); - else if(s.filter.filter != FilterFunction::Normal) - filter += QFormatStr(" (%1)").arg(ToQStr(s.filter.filter)); - - RDTreeWidgetItem *node = new RDTreeWidgetItem( - {rootel, stage.spaces[space].spaceIndex, 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)), - s.mipLODBias}); - - if(!filledSlot) - setEmptyRow(node); - - if(!usedSlot) - setInactiveRow(node); - - samplers->addTopLevelItem(node); + break; } + default: qCritical() << "Unexpected BindType for D3D12 pipeline"; break; } } + + resources->clearSelection(); + resources->endUpdate(); + resources->verticalScrollBar()->setValue(resVs); + uavs->clearSelection(); + uavs->endUpdate(); + uavs->verticalScrollBar()->setValue(uavVs); samplers->clearSelection(); samplers->endUpdate(); - samplers->verticalScrollBar()->setValue(vs); - - vs = cbuffers->verticalScrollBar()->value(); - cbuffers->beginUpdate(); - cbuffers->clear(); - for(int space = 0; space < stage.spaces.count(); space++) - { - for(int reg = 0; reg < stage.spaces[space].constantBuffers.count(); reg++) - { - const D3D12Pipe::ConstantBuffer &b = stage.spaces[space].constantBuffers[reg]; - - QVariant tag; - - const Bindpoint *bind = NULL; - const ConstantBlock *shaderCBuf = NULL; - - if(stage.reflection) - { - for(int i = 0; i < stage.bindpointMapping.constantBlocks.count(); i++) - { - const Bindpoint &bm = stage.bindpointMapping.constantBlocks[i]; - const ConstantBlock &res = stage.reflection->constantBlocks[i]; - - bool regMatch = bm.bind == reg; - - // handle unbounded arrays specially. It's illegal to have an unbounded array with - // anything after it - if(bm.bind <= reg) - regMatch = (bm.arraySize == ~0U) || (bm.bind + (int)bm.arraySize > reg); - - if(bm.bindset == (int32_t)stage.spaces[space].spaceIndex && regMatch) - { - bind = &bm; - shaderCBuf = &res; - D3D12CBufTag cbufTag(i); - cbufTag.arrayIdx = reg - bm.bind; - tag = QVariant::fromValue(cbufTag); - break; - } - } - } - - if(!tag.isValid()) - tag = QVariant::fromValue(D3D12CBufTag(space, reg)); - - QString rootel; - - if(b.immediate) - { - if(!b.rootValues.empty()) - rootel = tr("#%1 Consts").arg(b.rootElement); - else - rootel = tr("#%1 Direct").arg(b.rootElement); - } - else - { - rootel = tr("#%1 Table[%2]").arg(b.rootElement).arg(b.tableIndex); - } - - bool filledSlot = (b.resourceId != ResourceId()); - if(b.immediate && !b.rootValues.empty()) - filledSlot = true; - - bool usedSlot = (bind && bind->used); - - if(showNode(usedSlot, filledSlot)) - { - ulong length = b.byteSize; - uint64_t offset = b.byteOffset; - int numvars = shaderCBuf ? shaderCBuf->variables.count() : 0; - uint32_t bytesize = shaderCBuf ? shaderCBuf->byteSize : 0; - - if(b.immediate && !b.rootValues.empty()) - bytesize = uint32_t(b.rootValues.count() * 4); - - QString regname = QString::number(reg); - - if(shaderCBuf && !shaderCBuf->name.empty()) - regname += lit(": ") + shaderCBuf->name; - - if(bind != NULL && bind->arraySize > 1) - regname += tr("[%1]").arg(reg - bind->bind); - - QString sizestr; - if(bytesize == (uint32_t)length) - sizestr = tr("%1 Variables, %2 bytes").arg(numvars).arg(length); - else - sizestr = - tr("%1 Variables, %2 bytes needed, %3 provided").arg(numvars).arg(bytesize).arg(length); - - if(length < bytesize) - filledSlot = false; - - RDTreeWidgetItem *node = new RDTreeWidgetItem( - {rootel, (qulonglong)stage.spaces[space].spaceIndex, regname, b.resourceId, - QFormatStr("%1 - %2").arg(offset).arg(offset + bytesize), sizestr, QString()}); - - node->setTag(tag); - - if(!filledSlot) - setEmptyRow(node); - - if(!usedSlot) - setInactiveRow(node); - - cbuffers->addTopLevelItem(node); - } - } - } + samplers->verticalScrollBar()->setValue(sampVs); cbuffers->clearSelection(); cbuffers->endUpdate(); - cbuffers->verticalScrollBar()->setValue(vs); + cbuffers->verticalScrollBar()->setValue(cbVs); } void D3D12PipelineStateViewer::setState() @@ -1537,18 +1545,18 @@ void D3D12PipelineStateViewer::setState() ui->iaBuffers->endUpdate(); ui->iaBuffers->verticalScrollBar()->setValue(vs); - setShaderState(state.vertexShader, ui->vsShader, ui->vsRootSig, ui->vsResources, ui->vsSamplers, - ui->vsCBuffers, ui->vsUAVs); - setShaderState(state.geometryShader, ui->gsShader, ui->gsRootSig, ui->gsResources, ui->gsSamplers, - ui->gsCBuffers, ui->gsUAVs); - setShaderState(state.hullShader, ui->hsShader, ui->hsRootSig, ui->hsResources, ui->hsSamplers, - ui->hsCBuffers, ui->hsUAVs); - setShaderState(state.domainShader, ui->dsShader, ui->dsRootSig, ui->dsResources, ui->dsSamplers, - ui->dsCBuffers, ui->dsUAVs); - setShaderState(state.pixelShader, ui->psShader, ui->psRootSig, ui->psResources, ui->psSamplers, - ui->psCBuffers, ui->psUAVs); - setShaderState(state.computeShader, ui->csShader, ui->csRootSig, ui->csResources, ui->csSamplers, - ui->csCBuffers, ui->csUAVs); + setShaderState(state.rootElements, state.vertexShader, ui->vsShader, ui->vsRootSig, + ui->vsResources, ui->vsSamplers, ui->vsCBuffers, ui->vsUAVs); + setShaderState(state.rootElements, state.geometryShader, ui->gsShader, ui->gsRootSig, + ui->gsResources, ui->gsSamplers, ui->gsCBuffers, ui->gsUAVs); + setShaderState(state.rootElements, state.hullShader, ui->hsShader, ui->hsRootSig, ui->hsResources, + ui->hsSamplers, ui->hsCBuffers, ui->hsUAVs); + setShaderState(state.rootElements, state.domainShader, ui->dsShader, ui->dsRootSig, + ui->dsResources, ui->dsSamplers, ui->dsCBuffers, ui->dsUAVs); + setShaderState(state.rootElements, state.pixelShader, ui->psShader, ui->psRootSig, + ui->psResources, ui->psSamplers, ui->psCBuffers, ui->psUAVs); + setShaderState(state.rootElements, state.computeShader, ui->csShader, ui->csRootSig, + ui->csResources, ui->csSamplers, ui->csCBuffers, ui->csUAVs); QToolButton *shaderButtons[] = { ui->vsShaderViewButton, ui->hsShaderViewButton, ui->dsShaderViewButton, @@ -1684,15 +1692,16 @@ void D3D12PipelineStateViewer::setState() { for(int i = 0; i < state.outputMerger.renderTargets.count(); i++) { - addResourceRow(D3D12ViewTag(D3D12ViewTag::OMTarget, 0, i, state.outputMerger.renderTargets[i]), - NULL, ui->targetOutputs); + addResourceRow( + D3D12ViewTag(D3D12ViewTag::OMTarget, 0, 0, false, state.outputMerger.renderTargets[i]), + NULL, ui->targetOutputs); if(state.outputMerger.renderTargets[i].resourceId != ResourceId()) targets[i] = true; } - addResourceRow(D3D12ViewTag(D3D12ViewTag::OMDepth, 0, 0, state.outputMerger.depthTarget), NULL, - ui->targetOutputs); + addResourceRow(D3D12ViewTag(D3D12ViewTag::OMDepth, 0, 0, false, state.outputMerger.depthTarget), + NULL, ui->targetOutputs); } ui->targetOutputs->clearSelection(); ui->targetOutputs->endUpdate(); @@ -1973,7 +1982,7 @@ void D3D12PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in for(int i = 0; i < bindArray.count(); i++) { - if(bindArray[i].bindset == view.space && bindArray[i].bind == view.reg) + if(bindArray[i].bindset == view.space && bindArray[i].bind == (int)view.res.bind) { shaderRes = &resArray[i]; break; @@ -2012,7 +2021,8 @@ void D3D12PipelineStateViewer::cbuffer_itemActivated(RDTreeWidgetItem *item, int if(cb.idx == ~0U) { // unused cbuffer, open regular buffer viewer - const D3D12Pipe::ConstantBuffer &buf = stage->spaces[cb.space].constantBuffers[cb.reg]; + const D3D12Pipe::ConstantBuffer &buf = + m_Ctx.CurD3D12PipelineState()->rootElements[cb.rootElement].constantBuffers[cb.reg]; IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.byteOffset, buf.byteSize, buf.resourceId); @@ -2206,6 +2216,7 @@ QVariantList D3D12PipelineStateViewer::exportViewHTML(const D3D12Pipe::View &vie { QString name = view.resourceId == ResourceId() ? tr("Empty") : QString(m_Ctx.GetResourceName(view.resourceId)); + QString viewType = tr("Unknown"); QString typeName = tr("Unknown"); QString format = tr("Unknown"); uint64_t w = 1; @@ -2227,6 +2238,7 @@ QVariantList D3D12PipelineStateViewer::exportViewHTML(const D3D12Pipe::View &vie d = tex->depth; a = tex->arraysize; format = tex->format.Name(); + viewType = ToQStr(view.type); typeName = ToQStr(tex->type); if(view.swizzle[0] != TextureSwizzle::Red || view.swizzle[1] != TextureSwizzle::Green || @@ -2265,6 +2277,7 @@ QVariantList D3D12PipelineStateViewer::exportViewHTML(const D3D12Pipe::View &vie d = 0; a = 0; format = view.viewFormat.Name(); + viewType = ToQStr(view.type); typeName = lit("Buffer"); if(view.bufferFlags & D3DBufferViewFlags::Raw) @@ -2317,8 +2330,8 @@ QVariantList D3D12PipelineStateViewer::exportViewHTML(const D3D12Pipe::View &vie else viewParams += lit(", ") + extraParams; - return {name, ToQStr(view.type), typeName, (qulonglong)w, h, d, - a, viewFormat, format, viewParams}; + return {view.bind, name, viewType, typeName, (qulonglong)w, h, + d, a, viewFormat, format, viewParams}; } void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::InputAssembly &ia) @@ -2423,7 +2436,8 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe {ToQStr(draw ? draw->topology : Topology::Unknown)}); } -void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::Shader &sh) +void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::Shader &sh, + const rdcarray &els) { ShaderReflection *shaderDetails = sh.reflection; @@ -2458,328 +2472,319 @@ void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe return; } + QList rowsRO; + QList rowsRW; + QList rowsSampler; + QList rowsCB; + for(size_t i = 0; i < els.size(); ++i) { - xml.writeStartElement(lit("h3")); - xml.writeCharacters(tr("Shader Resource Views")); - xml.writeEndElement(); + if((els[i].visibility & MaskForStage(sh.stage)) == ShaderStageMask::Unknown) + continue; - QList rows; - - for(int space = 0; space < sh.spaces.count(); space++) + switch(els[i].type) { - for(int reg = 0; reg < sh.spaces[space].srvs.count(); reg++) + case BindType::ReadOnlyResource: { - const D3D12Pipe::View &v = sh.spaces[space].srvs[reg]; - - // consider this register to not exist - it's in a gap defined by sparse root signature - // elements - if(v.rootElement == ~0U) - continue; - - const ShaderResource *shaderInput = NULL; - - if(sh.reflection) + for(size_t j = 0; j < els[i].views.size(); ++j) { - for(int i = 0; i < sh.bindpointMapping.readOnlyResources.count(); i++) + const D3D12Pipe::View &v = els[i].views[j]; + const ShaderResource *shaderInput = NULL; + + if(sh.reflection) { - const Bindpoint &b = sh.bindpointMapping.readOnlyResources[i]; - const ShaderResource &res = sh.reflection->readOnlyResources[i]; - - bool regMatch = b.bind == reg; - - // handle unbounded arrays specially. It's illegal to have an unbounded array with - // anything after it - if(b.bind <= reg) - regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > reg); - - if(b.bindset == (int32_t)sh.spaces[space].spaceIndex && regMatch) + for(int32_t k = 0; k < sh.bindpointMapping.readOnlyResources.count(); ++k) { - shaderInput = &res; - break; + const Bindpoint &b = sh.bindpointMapping.readOnlyResources[k]; + const ShaderResource &res = sh.reflection->readOnlyResources[k]; + + bool regMatch = b.bind == (int32_t)v.bind; + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if(b.bind <= (int32_t)v.bind) + { + regMatch = (b.arraySize == ~0U) || (b.bind + (int32_t)b.arraySize > (int32_t)v.bind); + } + + if(b.bindset == (int32_t)els[i].registerSpace && regMatch) + { + shaderInput = &res; + break; + } } } + + QString rootel = els[i].immediate + ? tr("#%1 Direct").arg(els[i].rootElement) + : tr("#%1 Table[%2]").arg(els[i].rootElement).arg(v.tableIndex); + + QVariantList row = exportViewHTML(v, false, shaderInput, QString()); + + row.push_front(els[i].registerSpace); + row.push_front(rootel); + + rowsRO.push_back(row); } - - QString rootel = v.immediate ? tr("#%1 Direct").arg(v.rootElement) - : tr("#%1 Table[%2]").arg(v.rootElement).arg(v.tableIndex); - - QVariantList row = exportViewHTML(v, false, shaderInput, QString()); - - row.push_front(reg); - row.push_front(sh.spaces[space].spaceIndex); - row.push_front(rootel); - - rows.push_back(row); + break; } - } - - m_Common.exportHTMLTable( - xml, {tr("Root Sig El"), tr("Space"), tr("Register"), tr("Resource"), tr("View Type"), - tr("Resource Type"), tr("Width"), tr("Height"), tr("Depth"), tr("Array Size"), - tr("View Format"), tr("Resource Format"), tr("View Parameters")}, - rows); - } - - { - xml.writeStartElement(lit("h3")); - xml.writeCharacters(tr("Unordered Access Views")); - xml.writeEndElement(); - - QList rows; - - for(int space = 0; space < sh.spaces.count(); space++) - { - for(int reg = 0; reg < sh.spaces[space].uavs.count(); reg++) + case BindType::ReadWriteResource: { - const D3D12Pipe::View &v = sh.spaces[space].uavs[reg]; - - // consider this register to not exist - it's in a gap defined by sparse root signature - // elements - if(v.rootElement == ~0U) - continue; - - const ShaderResource *shaderInput = NULL; - - if(sh.reflection) + for(size_t j = 0; j < els[i].views.size(); ++j) { - for(int i = 0; i < sh.bindpointMapping.readWriteResources.count(); i++) + const D3D12Pipe::View &v = els[i].views[j]; + const ShaderResource *shaderInput = NULL; + + if(sh.reflection) { - const Bindpoint &b = sh.bindpointMapping.readWriteResources[i]; - const ShaderResource &res = sh.reflection->readWriteResources[i]; - - bool regMatch = b.bind == reg; - - // handle unbounded arrays specially. It's illegal to have an unbounded array with - // anything after it - if(b.bind <= reg) - regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > reg); - - if(b.bindset == (int32_t)sh.spaces[space].spaceIndex && regMatch) + for(int32_t k = 0; k < sh.bindpointMapping.readWriteResources.count(); ++k) { - shaderInput = &res; - break; + const Bindpoint &b = sh.bindpointMapping.readWriteResources[k]; + const ShaderResource &res = sh.reflection->readWriteResources[k]; + + bool regMatch = b.bind == (int32_t)v.bind; + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if(b.bind <= (int32_t)v.bind) + { + regMatch = (b.arraySize == ~0U) || (b.bind + (int32_t)b.arraySize > (int32_t)v.bind); + } + + if(b.bindset == (int32_t)els[i].registerSpace && regMatch) + { + shaderInput = &res; + break; + } } } + + QString rootel = els[i].immediate + ? tr("#%1 Direct").arg(els[i].rootElement) + : tr("#%1 Table[%2]").arg(els[i].rootElement).arg(v.tableIndex); + + QVariantList row = exportViewHTML(v, true, shaderInput, QString()); + + row.push_front(els[i].registerSpace); + row.push_front(rootel); + + rowsRW.push_back(row); } - - QString rootel = v.immediate ? tr("#%1 Direct").arg(v.rootElement) - : tr("#%1 Table[%2]").arg(v.rootElement).arg(v.tableIndex); - - QVariantList row = exportViewHTML(v, true, shaderInput, QString()); - - row.push_front(reg); - row.push_front(sh.spaces[space].spaceIndex); - row.push_front(rootel); - - rows.push_back(row); + break; } - } - - m_Common.exportHTMLTable( - xml, {tr("Root Sig El"), tr("Space"), tr("Register"), tr("Resource"), tr("View Type"), - tr("Resource Type"), tr("Width"), tr("Height"), tr("Depth"), tr("Array Size"), - tr("View Format"), tr("Resource Format"), tr("View Parameters")}, - rows); - } - - { - xml.writeStartElement(lit("h3")); - xml.writeCharacters(tr("Samplers")); - xml.writeEndElement(); - - QList rows; - - for(int space = 0; space < sh.spaces.count(); space++) - { - for(int reg = 0; reg < sh.spaces[space].samplers.count(); reg++) + case BindType::Sampler: { - const D3D12Pipe::Sampler &s = sh.spaces[space].samplers[reg]; - - // consider this register to not exist - it's in a gap defined by sparse root signature - // elements - if(s.rootElement == ~0U) - continue; - - const ShaderSampler *shaderInput = NULL; - - if(sh.reflection) + for(size_t j = 0; j < els[i].samplers.size(); ++j) { - for(int i = 0; i < sh.bindpointMapping.samplers.count(); i++) + const D3D12Pipe::Sampler &s = els[i].samplers[j]; + const ShaderSampler *shaderInput = NULL; + + if(sh.reflection) { - const Bindpoint &b = sh.bindpointMapping.samplers[i]; - const ShaderSampler &res = sh.reflection->samplers[i]; - - bool regMatch = b.bind == reg; - - // handle unbounded arrays specially. It's illegal to have an unbounded array with - // anything after it - if(b.bind <= reg) - regMatch = (b.arraySize == ~0U) || (b.bind + (int)b.arraySize > reg); - - if(b.bindset == (int32_t)sh.spaces[space].spaceIndex && regMatch) + for(int32_t k = 0; k < sh.bindpointMapping.samplers.count(); ++k) { - shaderInput = &res; - break; + const Bindpoint &b = sh.bindpointMapping.samplers[k]; + const ShaderSampler &res = sh.reflection->samplers[k]; + + bool regMatch = b.bind == (int32_t)s.bind; + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if(b.bind <= (int32_t)s.bind) + { + regMatch = (b.arraySize == ~0U) || (b.bind + (int32_t)b.arraySize > (int32_t)s.bind); + } + + if(b.bindset == (int32_t)els[i].registerSpace && regMatch) + { + shaderInput = &res; + break; + } } } - } - QString rootel = s.immediate ? tr("#%1 Static").arg(s.rootElement) - : tr("#%1 Table[%2]").arg(s.rootElement).arg(s.tableIndex); + QString rootel = els[i].immediate + ? tr("#%1 Static").arg(els[i].rootElement) + : tr("#%1 Table[%2]").arg(els[i].rootElement).arg(s.tableIndex); - { - QString regname = QString::number(reg); - - if(shaderInput && !shaderInput->name.empty()) - regname += lit(": ") + shaderInput->name; - - QString borderColor = QFormatStr("%1, %2, %3, %4") - .arg(s.borderColor[0]) - .arg(s.borderColor[1]) - .arg(s.borderColor[2]) - .arg(s.borderColor[3]); - - QString addressing; - - QString addPrefix; - QString addVal; - - QString addr[] = {ToQStr(s.addressU, GraphicsAPI::D3D12), - ToQStr(s.addressV, GraphicsAPI::D3D12), - ToQStr(s.addressW, GraphicsAPI::D3D12)}; - - // arrange like either UVW: WRAP or UV: WRAP, W: CLAMP - for(int a = 0; a < 3; a++) { - const QString str[] = {lit("U"), lit("V"), lit("W")}; - QString prefix = str[a]; + QString regname = QString::number(s.bind); - if(a == 0 || addr[a] == addr[a - 1]) + if(shaderInput && !shaderInput->name.empty()) + regname += lit(": ") + shaderInput->name; + + QString borderColor = QFormatStr("%1, %2, %3, %4") + .arg(s.borderColor[0]) + .arg(s.borderColor[1]) + .arg(s.borderColor[2]) + .arg(s.borderColor[3]); + + QString addressing; + + QString addPrefix; + QString addVal; + + QString addr[] = {ToQStr(s.addressU, GraphicsAPI::D3D12), + ToQStr(s.addressV, GraphicsAPI::D3D12), + ToQStr(s.addressW, GraphicsAPI::D3D12)}; + + // arrange like either UVW: WRAP or UV: WRAP, W: CLAMP + for(int a = 0; a < 3; a++) { - addPrefix += prefix; + const QString str[] = {lit("U"), lit("V"), lit("W")}; + QString prefix = str[a]; + + if(a == 0 || addr[a] == addr[a - 1]) + { + addPrefix += prefix; + } + else + { + addressing += QFormatStr("%1: %2, ").arg(addPrefix).arg(addVal); + + addPrefix = prefix; + } + addVal = addr[a]; } + + addressing += addPrefix + lit(": ") + addVal; + + if(s.UseBorder()) + addressing += QFormatStr("<%1>").arg(borderColor); + + QString filter = ToQStr(s.filter); + + if(s.maxAnisotropy > 1) + filter += QFormatStr(" %1x").arg(s.maxAnisotropy); + + if(s.filter.filter == FilterFunction::Comparison) + filter += QFormatStr(" (%1)").arg(ToQStr(s.compareFunction)); + else if(s.filter.filter != FilterFunction::Normal) + filter += QFormatStr(" (%1)").arg(ToQStr(s.filter.filter)); + + rowsSampler.push_back( + {rootel, els[i].registerSpace, 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)), + s.mipLODBias}); + } + } + break; + } + case BindType::ConstantBuffer: + { + for(size_t j = 0; j < els[i].constantBuffers.size(); ++j) + { + const D3D12Pipe::ConstantBuffer &b = els[i].constantBuffers[j]; + const ConstantBlock *shaderCBuf = NULL; + + if(sh.reflection) + { + for(int32_t k = 0; k < sh.bindpointMapping.constantBlocks.count(); ++k) + { + const Bindpoint &bm = sh.bindpointMapping.constantBlocks[k]; + const ConstantBlock &res = sh.reflection->constantBlocks[k]; + + bool regMatch = bm.bind == (int32_t)b.bind; + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if(bm.bind <= (int32_t)b.bind) + { + regMatch = + (bm.arraySize == ~0U) || (bm.bind + (int32_t)bm.arraySize > (int32_t)b.bind); + } + + if(bm.bindset == (int32_t)els[i].registerSpace && regMatch) + { + shaderCBuf = &res; + break; + } + } + } + + QString rootel; + + if(els[i].immediate) + { + if(!b.rootValues.empty()) + rootel = tr("#%1 Consts").arg(els[i].rootElement); else - { - addressing += QFormatStr("%1: %2, ").arg(addPrefix).arg(addVal); - - addPrefix = prefix; - } - addVal = addr[a]; + rootel = tr("#%1 Direct").arg(els[i].rootElement); } - - addressing += addPrefix + lit(": ") + addVal; - - if(s.UseBorder()) - addressing += QFormatStr("<%1>").arg(borderColor); - - QString filter = ToQStr(s.filter); - - if(s.maxAnisotropy > 1) - filter += QFormatStr(" %1x").arg(s.maxAnisotropy); - - if(s.filter.filter == FilterFunction::Comparison) - filter += QFormatStr(" (%1)").arg(ToQStr(s.compareFunction)); - else if(s.filter.filter != FilterFunction::Normal) - filter += QFormatStr(" (%1)").arg(ToQStr(s.filter.filter)); - - rows.push_back({rootel, sh.spaces[space].spaceIndex, 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)), - s.mipLODBias}); - } - } - } - - m_Common.exportHTMLTable(xml, {tr("Root Sig El"), tr("Space"), tr("Register"), tr("Addressing"), - tr("Filter"), tr("LOD Clamp"), tr("LOD Bias")}, - rows); - } - - { - xml.writeStartElement(lit("h3")); - xml.writeCharacters(tr("Constant Buffers")); - xml.writeEndElement(); - - QList rows; - - for(int space = 0; space < sh.spaces.count(); space++) - { - for(int reg = 0; reg < sh.spaces[space].constantBuffers.count(); reg++) - { - const D3D12Pipe::ConstantBuffer &b = sh.spaces[space].constantBuffers[reg]; - - const ConstantBlock *shaderCBuf = NULL; - - if(sh.reflection) - { - for(int i = 0; i < sh.bindpointMapping.constantBlocks.count(); i++) + else { - const Bindpoint &bm = sh.bindpointMapping.constantBlocks[i]; - const ConstantBlock &res = sh.reflection->constantBlocks[i]; + rootel = tr("#%1 Table[%2]").arg(els[i].rootElement).arg(b.tableIndex); + } - bool regMatch = bm.bind == reg; + { + QString name = tr("Constant Buffer %1").arg(ToQStr(b.resourceId)); + uint64_t length = b.byteSize; + uint64_t offset = b.byteOffset; + int numvars = shaderCBuf ? shaderCBuf->variables.count() : 0; + uint32_t bytesize = shaderCBuf ? shaderCBuf->byteSize : 0; - // handle unbounded arrays specially. It's illegal to have an unbounded array with - // anything after it - if(bm.bind <= reg) - regMatch = (bm.arraySize == ~0U) || (bm.bind + (int)bm.arraySize > reg); + if(els[i].immediate && !b.rootValues.empty()) + bytesize = uint32_t(b.rootValues.count() * 4); - if(bm.bindset == (int32_t)sh.spaces[space].spaceIndex && regMatch) - { - shaderCBuf = &res; - break; - } + if(b.resourceId != ResourceId()) + name = m_Ctx.GetResourceName(b.resourceId); + else + name = tr("Empty"); + + QString 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}); } } - - QString rootel; - - if(b.immediate) - { - if(!b.rootValues.empty()) - rootel = tr("#%1 Consts").arg(b.rootElement); - else - rootel = tr("#%1 Direct").arg(b.rootElement); - } - else - { - rootel = tr("#%1 Table[%2]").arg(b.rootElement).arg(b.tableIndex); - } - - { - QString name = tr("Constant Buffer %1").arg(ToQStr(b.resourceId)); - uint64_t length = b.byteSize; - uint64_t offset = b.byteOffset; - int numvars = shaderCBuf ? shaderCBuf->variables.count() : 0; - uint32_t bytesize = shaderCBuf ? shaderCBuf->byteSize : 0; - - if(b.immediate && !b.rootValues.empty()) - bytesize = uint32_t(b.rootValues.count() * 4); - - if(b.resourceId != ResourceId()) - name = m_Ctx.GetResourceName(b.resourceId); - else - name = tr("Empty"); - - QString regname = QString::number(reg); - - if(shaderCBuf && !shaderCBuf->name.empty()) - regname += lit(": ") + shaderCBuf->name; - - length = qMin(length, (uint64_t)bytesize); - - rows.push_back({rootel, sh.spaces[space].spaceIndex, regname, name, (qulonglong)offset, - (qulonglong)length, numvars}); - } + break; } + default: qCritical() << "Unexpected BindType for D3D12 pipeline"; break; } - - m_Common.exportHTMLTable(xml, - {tr("Root Signature Index"), tr("Space"), tr("Register"), tr("Buffer"), - tr("Byte Offset"), tr("Byte Size"), tr("Number of Variables")}, - rows); } + + xml.writeStartElement(lit("h3")); + xml.writeCharacters(tr("Shader Resource Views")); + xml.writeEndElement(); + + m_Common.exportHTMLTable( + xml, {tr("Root Sig El"), tr("Space"), tr("Register"), tr("Resource"), tr("View Type"), + tr("Resource Type"), tr("Width"), tr("Height"), tr("Depth"), tr("Array Size"), + tr("View Format"), tr("Resource Format"), tr("View Parameters")}, + rowsRO); + + xml.writeStartElement(lit("h3")); + xml.writeCharacters(tr("Unordered Access Views")); + xml.writeEndElement(); + + m_Common.exportHTMLTable( + xml, {tr("Root Sig El"), tr("Space"), tr("Register"), tr("Resource"), tr("View Type"), + tr("Resource Type"), tr("Width"), tr("Height"), tr("Depth"), tr("Array Size"), + tr("View Format"), tr("Resource Format"), tr("View Parameters")}, + rowsRW); + + xml.writeStartElement(lit("h3")); + xml.writeCharacters(tr("Samplers")); + xml.writeEndElement(); + + m_Common.exportHTMLTable(xml, {tr("Root Sig El"), tr("Space"), tr("Register"), tr("Addressing"), + tr("Filter"), tr("LOD Clamp"), tr("LOD Bias")}, + rowsSampler); + + xml.writeStartElement(lit("h3")); + xml.writeCharacters(tr("Constant Buffers")); + xml.writeEndElement(); + + m_Common.exportHTMLTable(xml, + {tr("Root Signature Index"), tr("Space"), tr("Register"), tr("Buffer"), + tr("Byte Offset"), tr("Byte Size"), tr("Number of Variables")}, + rowsCB); } void D3D12PipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::StreamOut &so) @@ -3099,17 +3104,33 @@ void D3D12PipelineStateViewer::on_exportHTML_clicked() switch(stage) { case 0: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->inputAssembly); break; - case 1: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->vertexShader); break; - case 2: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->hullShader); break; - case 3: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->domainShader); break; + case 1: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->vertexShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; + case 2: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->hullShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; + case 3: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->domainShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; case 4: - exportHTML(xml, m_Ctx.CurD3D12PipelineState()->geometryShader); + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->geometryShader, + m_Ctx.CurD3D12PipelineState()->rootElements); exportHTML(xml, m_Ctx.CurD3D12PipelineState()->streamOut); break; case 5: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->rasterizer); break; - case 6: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->pixelShader); break; + case 6: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->pixelShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; case 7: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->outputMerger); break; - case 8: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->computeShader); break; + case 8: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->computeShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; } xml.writeEndElement(); diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h index 8707f0a5e..e1c143033 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h @@ -81,7 +81,8 @@ private: ICaptureContext &m_Ctx; PipelineStateViewer &m_Common; - void setShaderState(const D3D12Pipe::Shader &stage, RDLabel *shader, RDLabel *rootSig, + void setShaderState(const rdcarray &rootElements, + const D3D12Pipe::Shader &stage, RDLabel *shader, RDLabel *rootSig, RDTreeWidget *tex, RDTreeWidget *samp, RDTreeWidget *cbuffer, RDTreeWidget *uavs); @@ -107,7 +108,8 @@ private: QVariantList exportViewHTML(const D3D12Pipe::View &view, bool rw, const ShaderResource *shaderInput, const QString &extraParams); void exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::InputAssembly &ia); - void exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::Shader &sh); + void exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::Shader &sh, + const rdcarray &els); void exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::StreamOut &so); void exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::Rasterizer &rs); void exportHTML(QXmlStreamWriter &xml, const D3D12Pipe::OM &om); diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 2f6fdcd49..e01875df9 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -2264,7 +2264,11 @@ void TextureViewer::InitStageResourcePreviews(ShaderStage stage, const bool collapseArray = dynamicallyUsedResCount > 20; - const int arrayLen = resArray != NULL ? resArray->count() : 1; + int arrayLen = resArray != NULL ? resArray->count() : 1; + + // Too many resources to draw can cause a full-OS hang. + // For now, limit the number displayed per resource array. + arrayLen = qMin(arrayLen, 8); for(int arrayIdx = 0; arrayIdx < arrayLen; arrayIdx++) { diff --git a/renderdoc/api/replay/d3d12_pipestate.h b/renderdoc/api/replay/d3d12_pipestate.h index 67c60082f..5265440a3 100644 --- a/renderdoc/api/replay/d3d12_pipestate.h +++ b/renderdoc/api/replay/d3d12_pipestate.h @@ -187,22 +187,27 @@ struct View { DOCUMENT(""); View() = default; + View(uint32_t binding) : bind(binding) {} View(const View &) = default; View &operator=(const View &) = default; bool operator==(const View &o) const { - return resourceId == o.resourceId && type == o.type && viewFormat == o.viewFormat && - swizzle[0] == o.swizzle[0] && swizzle[1] == o.swizzle[1] && swizzle[2] == o.swizzle[2] && - swizzle[3] == o.swizzle[3] && bufferFlags == o.bufferFlags && - bufferStructCount == o.bufferStructCount && elementByteSize == o.elementByteSize && - firstElement == o.firstElement && numElements == o.numElements && - counterResourceId == o.counterResourceId && counterByteOffset == o.counterByteOffset && - firstMip == o.firstMip && numMips == o.numMips && numSlices == o.numSlices && - firstSlice == o.firstSlice; + return bind == o.bind && tableIndex == o.tableIndex && resourceId == o.resourceId && + type == o.type && viewFormat == o.viewFormat && swizzle[0] == o.swizzle[0] && + swizzle[1] == o.swizzle[1] && swizzle[2] == o.swizzle[2] && swizzle[3] == o.swizzle[3] && + bufferFlags == o.bufferFlags && bufferStructCount == o.bufferStructCount && + elementByteSize == o.elementByteSize && firstElement == o.firstElement && + numElements == o.numElements && counterResourceId == o.counterResourceId && + counterByteOffset == o.counterByteOffset && firstMip == o.firstMip && + numMips == o.numMips && numSlices == o.numSlices && firstSlice == o.firstSlice; } bool operator<(const View &o) const { + if(!(bind == o.bind)) + return bind < o.bind; + if(!(tableIndex == o.tableIndex)) + return tableIndex < o.tableIndex; if(!(resourceId == o.resourceId)) return resourceId < o.resourceId; if(!(type == o.type)) @@ -241,10 +246,8 @@ struct View return firstSlice < o.firstSlice; return false; } - DOCUMENT("``True`` if this view is a root parameter (i.e. not in a table)."); - bool immediate = false; - DOCUMENT("The index in the original root signature that this descriptor came from."); - uint32_t rootElement = ~0U; + DOCUMENT("The shader register that this view is bound to."); + uint32_t bind = ~0U; DOCUMENT("The index in the the parent descriptor table where this descriptor came from."); uint32_t tableIndex = ~0U; @@ -295,25 +298,23 @@ struct Sampler { DOCUMENT(""); Sampler() = default; + Sampler(uint32_t binding) : bind(binding) {} Sampler(const Sampler &) = default; Sampler &operator=(const Sampler &) = default; bool operator==(const Sampler &o) const { - return immediate == o.immediate && rootElement == o.rootElement && tableIndex == o.tableIndex && - addressU == o.addressU && addressV == o.addressV && addressW == o.addressW && - borderColor[0] == o.borderColor[0] && borderColor[1] == o.borderColor[1] && - borderColor[2] == o.borderColor[2] && borderColor[3] == o.borderColor[3] && - compareFunction == o.compareFunction && filter == o.filter && - maxAnisotropy == o.maxAnisotropy && maxLOD == o.maxLOD && minLOD == o.minLOD && - mipLODBias == o.mipLODBias; + return bind == o.bind && tableIndex == o.tableIndex && addressU == o.addressU && + addressV == o.addressV && addressW == o.addressW && borderColor[0] == o.borderColor[0] && + borderColor[1] == o.borderColor[1] && borderColor[2] == o.borderColor[2] && + borderColor[3] == o.borderColor[3] && compareFunction == o.compareFunction && + filter == o.filter && maxAnisotropy == o.maxAnisotropy && maxLOD == o.maxLOD && + minLOD == o.minLOD && mipLODBias == o.mipLODBias; } bool operator<(const Sampler &o) const { - if(!(immediate == o.immediate)) - return immediate < o.immediate; - if(!(rootElement == o.rootElement)) - return rootElement < o.rootElement; + if(!(bind == o.bind)) + return bind < o.bind; if(!(tableIndex == o.tableIndex)) return tableIndex < o.tableIndex; if(!(addressU == o.addressU)) @@ -344,10 +345,8 @@ struct Sampler return mipLODBias < o.mipLODBias; return false; } - DOCUMENT("``True`` if this view is a static sampler (i.e. not in a table)."); - bool immediate = 0; - DOCUMENT("The index in the original root signature that this descriptor came from."); - uint32_t rootElement = ~0U; + DOCUMENT("The shader register that this sampler is bound to."); + uint32_t bind = ~0U; DOCUMENT("The index in the the parent descriptor table where this descriptor came from."); uint32_t tableIndex = ~0U; @@ -389,21 +388,19 @@ struct ConstantBuffer { DOCUMENT(""); ConstantBuffer() = default; + ConstantBuffer(uint32_t binding) : bind(binding) {} ConstantBuffer(const ConstantBuffer &) = default; ConstantBuffer &operator=(const ConstantBuffer &) = default; bool operator==(const ConstantBuffer &o) const { - return immediate == o.immediate && rootElement == o.rootElement && tableIndex == o.tableIndex && - resourceId == o.resourceId && byteOffset == o.byteOffset && byteSize == o.byteSize && - rootValues == o.rootValues; + return bind == o.bind && tableIndex == o.tableIndex && resourceId == o.resourceId && + byteOffset == o.byteOffset && byteSize == o.byteSize && rootValues == o.rootValues; } bool operator<(const ConstantBuffer &o) const { - if(!(immediate == o.immediate)) - return immediate < o.immediate; - if(!(rootElement == o.rootElement)) - return rootElement < o.rootElement; + if(!(bind == o.bind)) + return bind < o.bind; if(!(tableIndex == o.tableIndex)) return tableIndex < o.tableIndex; if(!(resourceId == o.resourceId)) @@ -416,10 +413,8 @@ struct ConstantBuffer return rootValues < o.rootValues; return false; } - DOCUMENT("``True`` if this view is a root constant (i.e. not in a table)."); - bool immediate = false; - DOCUMENT("The index in the original root signature that this descriptor came from."); - uint32_t rootElement = ~0U; + DOCUMENT("The shader register that this constant buffer is bound to."); + uint32_t bind = ~0U; DOCUMENT("The index in the the parent descriptor table where this descriptor came from."); uint32_t tableIndex = ~0U; @@ -436,43 +431,55 @@ struct ConstantBuffer rdcarray rootValues; }; -DOCUMENT("Contains all of the registers in a single register space mapped to by a root signature."); -struct RegisterSpace +DOCUMENT("Contains information for a single root signature element range"); +struct RootSignatureRange { DOCUMENT(""); - RegisterSpace() = default; - RegisterSpace(const RegisterSpace &) = default; - RegisterSpace &operator=(const RegisterSpace &) = default; + RootSignatureRange() = default; + RootSignatureRange(const RootSignatureRange &) = default; + RootSignatureRange &operator=(const RootSignatureRange &) = default; - bool operator==(const RegisterSpace &o) const + bool operator==(const RootSignatureRange &o) const { - return spaceIndex == o.spaceIndex && constantBuffers == o.constantBuffers && - samplers == o.samplers && srvs == o.srvs && uavs == o.uavs; + return immediate == o.immediate && rootElement == o.rootElement && visibility == o.visibility && + registerSpace == o.registerSpace && constantBuffers == o.constantBuffers && + samplers == o.samplers && views == o.views; } - bool operator<(const RegisterSpace &o) const + bool operator<(const RootSignatureRange &o) const { - if(!(spaceIndex == o.spaceIndex)) - return spaceIndex < o.spaceIndex; + if(!(immediate == o.immediate)) + return immediate < o.immediate; + if(!(rootElement == o.rootElement)) + return rootElement < o.rootElement; + if(!(visibility == o.visibility)) + return visibility < o.visibility; + if(!(registerSpace == o.registerSpace)) + return registerSpace < o.registerSpace; if(!(constantBuffers == o.constantBuffers)) return constantBuffers < o.constantBuffers; if(!(samplers == o.samplers)) return samplers < o.samplers; - if(!(srvs == o.srvs)) - return srvs < o.srvs; - if(!(uavs == o.uavs)) - return uavs < o.uavs; + if(!(views == o.views)) + return views < o.views; return false; } - DOCUMENT("The index of this space, since space indices can be sparse"); - uint32_t spaceIndex; - DOCUMENT("List of :class:`D3D12ConstantBuffer` containing the constant buffers."); + + DOCUMENT("``True`` if this root element is a root constant (i.e. not in a table)."); + bool immediate = false; + DOCUMENT("The index in the original root signature that this descriptor came from."); + uint32_t rootElement = ~0U; + DOCUMENT("The :class:`BindType` contained by this element."); + BindType type = BindType::Unknown; + DOCUMENT("The :class:`ShaderStageMask` of this element."); + ShaderStageMask visibility = ShaderStageMask::All; + DOCUMENT("The register space of this element."); + uint32_t registerSpace; + DOCUMENT("List of :class:`ConstantBuffer` containing the constant buffers."); rdcarray constantBuffers; - DOCUMENT("List of :class:`D3D12Sampler` containing the samplers."); + DOCUMENT("List of :class:`Sampler` containing the samplers."); rdcarray samplers; - DOCUMENT("List of :class:`D3D12View` containing the SRVs."); - rdcarray srvs; - DOCUMENT("List of :class:`D3D12View` containing the UAVs."); - rdcarray uavs; + DOCUMENT("List of :class:`View` containing the SRVs or UAVs."); + rdcarray views; }; DOCUMENT("Describes a D3D12 shader stage."); @@ -495,23 +502,6 @@ mapping data. DOCUMENT("A :class:`ShaderStage` identifying which stage this shader is bound to."); ShaderStage stage = ShaderStage::Vertex; - - DOCUMENT("A list of :class:`D3D12RegisterSpace` with the register spaces for this stage."); - rdcarray spaces; - - DOCUMENT(R"(Return the index in the :data:`spaces` array of a given register space. - -:return: The index if the space exists, or ``-1`` if it doesn't. -:rtype: ``int`` -)"); - int32_t FindSpace(uint32_t spaceIndex) const - { - for(int32_t i = 0; i < spaces.count(); i++) - if(spaces[i].spaceIndex == spaceIndex) - return i; - - return -1; - } }; DOCUMENT("Describes a binding on the D3D12 stream-out stage."); @@ -702,7 +692,7 @@ struct OM rdcarray renderTargets; DOCUMENT("A :class:`D3D12View` with details of the bound depth-stencil target."); - View depthTarget; + View depthTarget = D3D12Pipe::View(0); DOCUMENT("``True`` if depth access to the depth-stencil target is read-only."); bool depthReadOnly = false; DOCUMENT("``True`` if stenncil access to the depth-stencil target is read-only."); @@ -775,6 +765,9 @@ struct State DOCUMENT("The :class:`ResourceId` of the root signature object."); ResourceId rootSignatureResourceId; + DOCUMENT("A list of :class:`RootSignatureRange` entries comprising the root signature."); + rdcarray rootElements; + DOCUMENT("A :class:`D3D12InputAssembly` describing the input assembly pipeline stage."); InputAssembly inputAssembly; @@ -813,7 +806,7 @@ DECLARE_REFLECTION_STRUCT(D3D12Pipe::InputAssembly); DECLARE_REFLECTION_STRUCT(D3D12Pipe::View); DECLARE_REFLECTION_STRUCT(D3D12Pipe::Sampler); DECLARE_REFLECTION_STRUCT(D3D12Pipe::ConstantBuffer); -DECLARE_REFLECTION_STRUCT(D3D12Pipe::RegisterSpace); +DECLARE_REFLECTION_STRUCT(D3D12Pipe::RootSignatureRange); DECLARE_REFLECTION_STRUCT(D3D12Pipe::Shader); DECLARE_REFLECTION_STRUCT(D3D12Pipe::StreamOutBind); DECLARE_REFLECTION_STRUCT(D3D12Pipe::StreamOut); diff --git a/renderdoc/api/replay/pipestate.inl b/renderdoc/api/replay/pipestate.inl index 2bf1c8de5..14fab0d22 100644 --- a/renderdoc/api/replay/pipestate.inl +++ b/renderdoc/api/replay/pipestate.inl @@ -923,20 +923,32 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui const Bindpoint &bind = s.bindpointMapping.constantBlocks[s.reflection->constantBlocks[BufIdx].bindPoint]; - int32_t space = s.FindSpace(bind.bindset); - - if(space == -1) - return BoundCBuffer(); - int32_t shaderReg = bind.bind + (int32_t)ArrayIdx; - if(space >= s.spaces.count() || shaderReg >= s.spaces[space].constantBuffers.count()) - return BoundCBuffer(); - const D3D12Pipe::ConstantBuffer &descriptor = s.spaces[space].constantBuffers[shaderReg]; + bool found = false; + for(size_t i = 0; i < m_D3D12->rootElements.size() && !found; ++i) + { + const D3D12Pipe::RootSignatureRange &element = m_D3D12->rootElements[i]; + if((element.visibility & MaskForStage(stage)) == ShaderStageMask::Unknown) + continue; - buf = descriptor.resourceId; - ByteOffset = descriptor.byteOffset; - ByteSize = descriptor.byteSize; + if(element.type == BindType::ConstantBuffer && + element.registerSpace == (uint32_t)bind.bindset) + { + for(size_t j = 0; j < element.constantBuffers.size(); ++j) + { + const D3D12Pipe::ConstantBuffer &cb = element.constantBuffers[j]; + if(cb.bind == (uint32_t)shaderReg) + { + buf = cb.resourceId; + ByteOffset = cb.byteOffset; + ByteSize = cb.byteSize; + found = true; + break; + } + } + } + } } } else if(IsCaptureGL()) @@ -1043,29 +1055,35 @@ rdcarray PipeState::GetReadOnlyResources(ShaderStage stage) ret.push_back(BoundResourceArray()); ret.back().bindPoint = bind; - uint32_t count = bind.arraySize == ~0U ? 1 : bind.arraySize; + uint32_t start = bind.bind; + uint32_t end = (bind.arraySize == ~0U) ? bind.arraySize : bind.bind + bind.arraySize; + rdcarray &val = ret.back().resources; - val.resize(count); - int spaceIndex = 0; - for(int space = 0; space < s.spaces.count(); space++) + for(size_t i = 0; i < m_D3D12->rootElements.size(); ++i) { - if(s.spaces[space].spaceIndex == (uint32_t)bind.bindset) + const D3D12Pipe::RootSignatureRange &element = m_D3D12->rootElements[i]; + if((element.visibility & MaskForStage(stage)) == ShaderStageMask::Unknown) + continue; + + if(element.type == BindType::ReadOnlyResource && + element.registerSpace == (uint32_t)bind.bindset) { - spaceIndex = space; - break; + for(size_t j = 0; j < element.views.size(); ++j) + { + const D3D12Pipe::View &view = element.views[j]; + if(view.bind >= start && view.bind <= end) + { + val.push_back(BoundResource()); + BoundResource &b = val.back(); + b.resourceId = view.resourceId; + b.firstMip = (int)view.firstMip; + b.firstSlice = (int)view.firstSlice; + b.typeCast = view.viewFormat.compType; + } + } } } - - for(uint32_t i = 0; i < count; i++) - { - const D3D12Pipe::View &view = s.spaces[spaceIndex].srvs[bind.bind + i]; - - val[i].resourceId = view.resourceId; - val[i].firstMip = (int)view.firstMip; - val[i].firstSlice = (int)view.firstSlice; - val[i].typeCast = view.viewFormat.compType; - } } return ret; @@ -1198,31 +1216,43 @@ rdcarray PipeState::GetReadWriteResources(ShaderStage stage) { const D3D12Pipe::Shader &s = GetD3D12Stage(stage); - size_t size = 0; - for(int space = 0; space < s.spaces.count(); space++) - size += s.spaces[space].uavs.size(); - + size_t size = s.bindpointMapping.readWriteResources.size(); ret.reserve(size); - for(int space = 0; space < s.spaces.count(); space++) + for(size_t bp = 0; bp < size; bp++) { - for(int reg = 0; reg < s.spaces[space].uavs.count(); reg++) - { - const D3D12Pipe::View &bind = s.spaces[space].uavs[reg]; - Bindpoint key(s.spaces[space].spaceIndex, reg); - BoundResource val; + const Bindpoint &bind = s.bindpointMapping.readWriteResources[bp]; + ret.push_back(BoundResourceArray()); + ret.back().bindPoint = bind; - // consider this register to not exist - it's in a gap defined by sparse root signature - // elements - if(bind.rootElement == ~0U) + uint32_t start = bind.bind; + uint32_t end = (bind.arraySize == ~0U) ? bind.arraySize : bind.bind + bind.arraySize; + + rdcarray &val = ret.back().resources; + + for(size_t i = 0; i < m_D3D12->rootElements.size(); ++i) + { + const D3D12Pipe::RootSignatureRange &element = m_D3D12->rootElements[i]; + if((element.visibility & MaskForStage(stage)) == ShaderStageMask::Unknown) continue; - val.resourceId = bind.resourceId; - val.firstMip = (int)bind.firstMip; - val.firstSlice = (int)bind.firstSlice; - val.typeCast = bind.viewFormat.compType; - - ret.push_back(BoundResourceArray(key, {val})); + if(element.type == BindType::ReadWriteResource && + element.registerSpace == (uint32_t)bind.bindset) + { + for(size_t j = 0; j < element.views.size(); ++j) + { + const D3D12Pipe::View &view = element.views[j]; + if(view.bind >= start && view.bind <= end) + { + val.push_back(BoundResource()); + BoundResource &b = val.back(); + b.resourceId = view.resourceId; + b.firstMip = (int)view.firstMip; + b.firstSlice = (int)view.firstSlice; + b.typeCast = view.viewFormat.compType; + } + } + } } } } diff --git a/renderdoc/api/replay/renderdoc_tostr.inl b/renderdoc/api/replay/renderdoc_tostr.inl index 2d4c8b198..c790114a9 100644 --- a/renderdoc/api/replay/renderdoc_tostr.inl +++ b/renderdoc/api/replay/renderdoc_tostr.inl @@ -679,6 +679,8 @@ rdcstr DoStringise(const BindType &el) STRINGISE_ENUM_CLASS_NAMED(ReadWriteTBuffer, "RW TexBuffer"); STRINGISE_ENUM_CLASS_NAMED(ReadOnlyBuffer, "Buffer"); STRINGISE_ENUM_CLASS_NAMED(ReadWriteBuffer, "RW Buffer"); + STRINGISE_ENUM_CLASS_NAMED(ReadOnlyResource, "Resource"); + STRINGISE_ENUM_CLASS_NAMED(ReadWriteResource, "RW Resource"); STRINGISE_ENUM_CLASS_NAMED(InputAttachment, "Input"); } END_ENUM_STRINGISE(); diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index edc404524..72a60d786 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -659,6 +659,14 @@ DOCUMENT(R"(The type of a shader resource bind. A buffer that can be read from and written to arbitrarily. +.. data:: ReadOnlyResource + + A resource that can only be read from + +.. data:: ReadWriteResource + + A resource that can be read from and written to arbitrarily. + .. data:: InputAttachment An input attachment for reading from the target currently being written. @@ -675,6 +683,8 @@ enum class BindType : uint32_t ReadWriteTBuffer, ReadOnlyBuffer, ReadWriteBuffer, + ReadOnlyResource, + ReadWriteResource, InputAttachment, }; diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index f0bf9a676..2b89fd4b1 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -54,41 +54,6 @@ ID3DDevice *GetD3D12DeviceIfAlloc(IUnknown *dev); static const char *DXBCDisassemblyTarget = "DXBC"; -template -T &resize_and_add(rdcarray &vec, size_t idx) -{ - if(idx >= vec.size()) - vec.resize(idx + 1); - - return vec[idx]; -} - -D3D12Pipe::RegisterSpace &get_space(rdcarray &dstSpaces, - uint32_t RegisterSpace) -{ - // look to see if we've already added this space, if so then return it - for(D3D12Pipe::RegisterSpace &space : dstSpaces) - if(space.spaceIndex == RegisterSpace) - return space; - - // otherwise look for the right place to insert it - for(size_t i = 0; i < dstSpaces.size(); i++) - { - if(RegisterSpace < dstSpaces[i].spaceIndex) - { - dstSpaces.insert(i, D3D12Pipe::RegisterSpace()); - dstSpaces[i].spaceIndex = RegisterSpace; - return dstSpaces[i]; - } - } - - // if we got here, we didn't find an existing space nor a place to insert a new one, so we append - // it - dstSpaces.push_back(D3D12Pipe::RegisterSpace()); - dstSpaces.back().spaceIndex = RegisterSpace; - return dstSpaces.back(); -} - D3D12Replay::D3D12Replay(WrappedID3D12Device *d) { m_pDevice = d; @@ -900,34 +865,51 @@ void D3D12Replay::FillResourceView(D3D12Pipe::View &view, const D3D12Descriptor } } -void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &rootSig, - const ShaderBindpointMapping &mapping, - rdcarray &dstSpaces, - D3D12_SHADER_VISIBILITY visibility) +ShaderStageMask ToShaderStageMask(D3D12_SHADER_VISIBILITY vis) { + switch(vis) + { + case D3D12_SHADER_VISIBILITY_ALL: return ShaderStageMask::All; + case D3D12_SHADER_VISIBILITY_VERTEX: return ShaderStageMask::Vertex; + case D3D12_SHADER_VISIBILITY_HULL: return ShaderStageMask::Hull; + case D3D12_SHADER_VISIBILITY_DOMAIN: return ShaderStageMask::Domain; + case D3D12_SHADER_VISIBILITY_GEOMETRY: return ShaderStageMask::Geometry; + case D3D12_SHADER_VISIBILITY_PIXEL: return ShaderStageMask::Pixel; + default: return ShaderStageMask::Unknown; + } +} + +void D3D12Replay::FillRootElements(const D3D12RenderState::RootSignature &rootSig, + const ShaderBindpointMapping *mappings[(uint32_t)ShaderStage::Count], + rdcarray &rootElements) +{ + if(rootSig.rootsig == ResourceId()) + return; + D3D12ResourceManager *rm = m_pDevice->GetResourceManager(); WrappedID3D12RootSignature *sig = m_pDevice->GetResourceManager()->GetCurrentAs(rootSig.rootsig); - // clear first to ensure the spaces are default-initialised - dstSpaces.clear(); - dstSpaces.reserve(8); + rootElements.clear(); + rootElements.reserve(sig->sig.Parameters.size() + sig->sig.StaticSamplers.size()); for(size_t rootEl = 0; rootEl < sig->sig.Parameters.size(); rootEl++) { const D3D12RootSignatureParameter &p = sig->sig.Parameters[rootEl]; - if(p.ShaderVisibility != D3D12_SHADER_VISIBILITY_ALL && p.ShaderVisibility != visibility) - continue; - if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS) { - D3D12Pipe::ConstantBuffer &cb = - resize_and_add(get_space(dstSpaces, p.Constants.RegisterSpace).constantBuffers, - p.Constants.ShaderRegister); - cb.immediate = true; - cb.rootElement = (uint32_t)rootEl; + rootElements.push_back(D3D12Pipe::RootSignatureRange()); + D3D12Pipe::RootSignatureRange &element = rootElements.back(); + element.immediate = true; + element.rootElement = (uint32_t)rootEl; + element.type = BindType::ConstantBuffer; + element.registerSpace = p.Constants.RegisterSpace; + element.visibility = ToShaderStageMask(p.ShaderVisibility); + + element.constantBuffers.push_back(D3D12Pipe::ConstantBuffer(p.Constants.ShaderRegister)); + D3D12Pipe::ConstantBuffer &cb = element.constantBuffers.back(); cb.byteSize = uint32_t(sizeof(uint32_t) * p.Constants.Num32BitValues); if(rootEl < rootSig.sigelems.size()) @@ -943,11 +925,16 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root } else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV) { - D3D12Pipe::ConstantBuffer &cb = - resize_and_add(get_space(dstSpaces, p.Descriptor.RegisterSpace).constantBuffers, - p.Descriptor.ShaderRegister); - cb.immediate = true; - cb.rootElement = (uint32_t)rootEl; + rootElements.push_back(D3D12Pipe::RootSignatureRange()); + D3D12Pipe::RootSignatureRange &element = rootElements.back(); + element.immediate = true; + element.rootElement = (uint32_t)rootEl; + element.type = BindType::ConstantBuffer; + element.registerSpace = p.Descriptor.RegisterSpace; + element.visibility = ToShaderStageMask(p.ShaderVisibility); + + element.constantBuffers.push_back(D3D12Pipe::ConstantBuffer(p.Descriptor.ShaderRegister)); + D3D12Pipe::ConstantBuffer &cb = element.constantBuffers.back(); if(rootEl < rootSig.sigelems.size()) { @@ -967,10 +954,16 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root } else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_SRV) { - D3D12Pipe::View &view = resize_and_add(get_space(dstSpaces, p.Descriptor.RegisterSpace).srvs, - p.Descriptor.ShaderRegister); - view.immediate = true; - view.rootElement = (uint32_t)rootEl; + rootElements.push_back(D3D12Pipe::RootSignatureRange()); + D3D12Pipe::RootSignatureRange &element = rootElements.back(); + element.immediate = true; + element.rootElement = (uint32_t)rootEl; + element.type = BindType::ReadOnlyResource; + element.registerSpace = p.Descriptor.RegisterSpace; + element.visibility = ToShaderStageMask(p.ShaderVisibility); + + element.views.push_back(D3D12Pipe::View(p.Descriptor.ShaderRegister)); + D3D12Pipe::View &view = element.views.back(); if(rootEl < rootSig.sigelems.size()) { @@ -995,10 +988,16 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root } else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV) { - D3D12Pipe::View &view = resize_and_add(get_space(dstSpaces, p.Descriptor.RegisterSpace).uavs, - p.Descriptor.ShaderRegister); - view.immediate = true; - view.rootElement = (uint32_t)rootEl; + rootElements.push_back(D3D12Pipe::RootSignatureRange()); + D3D12Pipe::RootSignatureRange &element = rootElements.back(); + element.immediate = true; + element.rootElement = (uint32_t)rootEl; + element.type = BindType::ReadWriteResource; + element.registerSpace = p.Descriptor.RegisterSpace; + element.visibility = ToShaderStageMask(p.ShaderVisibility); + + element.views.push_back(D3D12Pipe::View(p.Descriptor.ShaderRegister)); + D3D12Pipe::View &view = element.views.back(); if(rootEl < rootSig.sigelems.size()) { @@ -1039,8 +1038,17 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root { const D3D12_DESCRIPTOR_RANGE1 &range = p.ranges[r]; + // Here we diverge slightly from how root signatures store data. A descriptor table can + // contain multiple ranges which can each contain different types. D3D12Pipe treats + // each range as a separate RootElement + rootElements.push_back(D3D12Pipe::RootSignatureRange()); + D3D12Pipe::RootSignatureRange &element = rootElements.back(); + + element.rootElement = (uint32_t)rootEl; + element.registerSpace = range.RegisterSpace; + element.visibility = ToShaderStageMask(p.ShaderVisibility); + UINT shaderReg = range.BaseShaderRegister; - D3D12Pipe::RegisterSpace ®Space = get_space(dstSpaces, range.RegisterSpace); D3D12Descriptor *desc = NULL; @@ -1059,38 +1067,38 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root if(num == UINT_MAX) { - // find out how many descriptors are left after UINT availDescriptors = heap->GetNumDescriptors() - offset - UINT(e->offset); - // if this is an unbounded size table, find the matching bindpoint to try and - // upper-bound its size. - // due to D3D12's messed up resource matching, an array of descriptors in the root - // signature might match multiple bindings in the HLSL. So we just need to pick the - // highest-register item in the space and use its size. + const Bindpoint *highestBind = NULL; + UINT maxBindReg = shaderReg + availDescriptors; - const Bindpoint *bind = NULL; - - // find the - for(const Bindpoint &b : mapping.readOnlyResources) + // Find shader binds that map any or all of this range to see if we can trim it + for(ShaderStage stage = ShaderStage::Vertex; stage < ShaderStage::Count; ++stage) { - if(b.bindset == (int32_t)range.RegisterSpace && (bind == NULL || bind->bind < b.bind)) - bind = &b; + if((element.visibility & MaskForStage(stage)) != ShaderStageMask::Unknown) + { + // This range is visible to this shader stage, check its mappings + const rdcarray &bps = mappings[(uint32_t)stage]->readOnlyResources; + for(size_t b = 0; b < bps.size(); ++b) + { + if(bps[b].bindset == (int32_t)element.registerSpace && + bps[b].bind >= (int32_t)shaderReg) + { + UINT bindEnd = bps[b].arraySize == ~0U ? ~0U : bps[b].bind + bps[b].arraySize; + if(highestBind == NULL || bindEnd > maxBindReg) + { + highestBind = &bps[b]; + maxBindReg = bindEnd; + } + } + } + } } - // the size is however many registers are between the base of this range and that last - // bind, plus the size of the bind (at least 1 if it's not arrayed). - // If we didn't find any bind, clamp to 128 instead to prevent massive descriptor heaps - // from being passed through. - if(bind) - { - uint32_t arraySize = bind->arraySize == UINT_MAX ? 0U : bind->arraySize; - num = RDCMIN(availDescriptors, - bind->bind - range.BaseShaderRegister + RDCMAX(1U, arraySize)); - } - else - { - num = RDCMIN(availDescriptors, 128U); - } + // If we didn't find a bindpoint, this will evaluate to simply availDescriptors - the + // number of remaining entries in the heap. If we did find a bind in this range, it + // will trim to the max register used by bindings in the range. + num = RDCMIN(availDescriptors, maxBindReg - shaderReg); } } else if(num == UINT_MAX) @@ -1105,15 +1113,12 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) { - UINT maxReg = shaderReg + num - 1; - if(maxReg >= regSpace.samplers.size()) - regSpace.samplers.resize(maxReg + 1); + element.type = BindType::Sampler; for(UINT i = 0; i < num; i++, shaderReg++) { - D3D12Pipe::Sampler &samp = regSpace.samplers[shaderReg]; - samp.immediate = false; - samp.rootElement = (uint32_t)rootEl; + element.samplers.push_back(D3D12Pipe::Sampler(shaderReg)); + D3D12Pipe::Sampler &samp = element.samplers.back(); samp.tableIndex = offset + i; if(desc) @@ -1141,15 +1146,12 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root } else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV) { - UINT maxReg = shaderReg + num - 1; - if(maxReg >= regSpace.constantBuffers.size()) - regSpace.constantBuffers.resize(maxReg + 1); + element.type = BindType::ConstantBuffer; for(UINT i = 0; i < num; i++, shaderReg++) { - D3D12Pipe::ConstantBuffer &cb = regSpace.constantBuffers[shaderReg]; - cb.immediate = false; - cb.rootElement = (uint32_t)rootEl; + element.constantBuffers.push_back(D3D12Pipe::ConstantBuffer(shaderReg)); + D3D12Pipe::ConstantBuffer &cb = element.constantBuffers.back(); cb.tableIndex = offset + i; if(desc) @@ -1166,42 +1168,34 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root } else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV) { - UINT maxReg = shaderReg + num - 1; - if(maxReg >= regSpace.srvs.size()) - regSpace.srvs.resize(maxReg + 1); + element.type = BindType::ReadOnlyResource; for(UINT i = 0; i < num; i++, shaderReg++) { - D3D12Pipe::View &view = regSpace.srvs[shaderReg]; - view.immediate = false; - view.rootElement = (uint32_t)rootEl; + element.views.push_back(D3D12Pipe::View(shaderReg)); + D3D12Pipe::View &view = element.views.back(); view.tableIndex = offset + i; if(desc) { FillResourceView(view, desc); - desc++; } } } else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV) { - UINT maxReg = shaderReg + num - 1; - if(maxReg >= regSpace.uavs.size()) - regSpace.uavs.resize(maxReg + 1); + element.type = BindType::ReadWriteResource; for(UINT i = 0; i < num; i++, shaderReg++) { - D3D12Pipe::View &view = regSpace.uavs[shaderReg]; - view.immediate = false; - view.rootElement = (uint32_t)rootEl; + element.views.push_back(D3D12Pipe::View(shaderReg)); + D3D12Pipe::View &view = element.views.back(); view.tableIndex = offset + i; if(desc) { FillResourceView(view, desc); - desc++; } } @@ -1210,18 +1204,21 @@ void D3D12Replay::FillRegisterSpaces(const D3D12RenderState::RootSignature &root } } + // Each static sampler gets its own RootElement for(size_t i = 0; i < sig->sig.StaticSamplers.size(); i++) { D3D12_STATIC_SAMPLER_DESC &sampDesc = sig->sig.StaticSamplers[i]; - if(sampDesc.ShaderVisibility != D3D12_SHADER_VISIBILITY_ALL && - sampDesc.ShaderVisibility != visibility) - continue; + rootElements.push_back(D3D12Pipe::RootSignatureRange()); + D3D12Pipe::RootSignatureRange &element = rootElements.back(); + element.immediate = true; + element.rootElement = (uint32_t)i; + element.type = BindType::Sampler; + element.registerSpace = sampDesc.RegisterSpace; + element.visibility = ToShaderStageMask(sampDesc.ShaderVisibility); - D3D12Pipe::Sampler &samp = resize_and_add(get_space(dstSpaces, sampDesc.RegisterSpace).samplers, - sampDesc.ShaderRegister); - samp.immediate = true; - samp.rootElement = (uint32_t)i; + element.samplers.push_back(D3D12Pipe::Sampler(sampDesc.ShaderRegister)); + D3D12Pipe::Sampler &samp = element.samplers.back(); samp.addressU = MakeAddressMode(sampDesc.AddressU); samp.addressV = MakeAddressMode(sampDesc.AddressV); @@ -1342,12 +1339,6 @@ void D3D12Replay::SavePipelineState(uint32_t eventId) state.computeShader.stage = ShaderStage::Compute; state.computeShader.reflection = &sh->GetDetails(); state.computeShader.bindpointMapping = sh->GetMapping(); - - state.rootSignatureResourceId = rm->GetOriginalID(rs.compute.rootsig); - - if(rs.compute.rootsig != ResourceId()) - FillRegisterSpaces(rs.compute, state.computeShader.bindpointMapping, - state.computeShader.spaces, D3D12_SHADER_VISIBILITY_ALL); } else if(pipe) { @@ -1382,12 +1373,31 @@ void D3D12Replay::SavePipelineState(uint32_t eventId) dst.bindpointMapping = ShaderBindpointMapping(); dst.reflection = NULL; } - - if(rs.graphics.rootsig != ResourceId()) - FillRegisterSpaces(rs.graphics, dst.bindpointMapping, dst.spaces, visibility[stage]); } + } - state.rootSignatureResourceId = rm->GetOriginalID(rs.graphics.rootsig); + ///////////////////////////////////////////////// + // Root Signature + ///////////////////////////////////////////////// + { + const ShaderBindpointMapping *mappings[(uint32_t)ShaderStage::Count]; + mappings[(uint32_t)ShaderStage::Vertex] = &state.vertexShader.bindpointMapping; + mappings[(uint32_t)ShaderStage::Hull] = &state.hullShader.bindpointMapping; + mappings[(uint32_t)ShaderStage::Domain] = &state.domainShader.bindpointMapping; + mappings[(uint32_t)ShaderStage::Geometry] = &state.geometryShader.bindpointMapping; + mappings[(uint32_t)ShaderStage::Pixel] = &state.pixelShader.bindpointMapping; + mappings[(uint32_t)ShaderStage::Compute] = &state.computeShader.bindpointMapping; + + if(pipe && pipe->IsCompute()) + { + FillRootElements(rs.compute, mappings, state.rootElements); + state.rootSignatureResourceId = rm->GetOriginalID(rs.compute.rootsig); + } + else if(pipe) + { + FillRootElements(rs.graphics, mappings, state.rootElements); + state.rootSignatureResourceId = rm->GetOriginalID(rs.graphics.rootsig); + } } if(pipe && pipe->IsGraphics()) @@ -1462,41 +1472,22 @@ void D3D12Replay::SavePipelineState(uint32_t eventId) // Output Merger ///////////////////////////////////////////////// - state.outputMerger.renderTargets.resize(rs.rts.size()); + state.outputMerger.renderTargets.reserve(rs.rts.size()); for(size_t i = 0; i < rs.rts.size(); i++) { - D3D12Pipe::View &view = state.outputMerger.renderTargets[i]; - const D3D12Descriptor &desc = rs.rts[i]; if(desc.GetResResourceId() != ResourceId()) { - view.rootElement = (uint32_t)i; - view.immediate = false; + state.outputMerger.renderTargets.push_back(D3D12Pipe::View((uint32_t)i)); + D3D12Pipe::View &view = state.outputMerger.renderTargets.back(); FillResourceView(view, &desc); } - else - { - view = D3D12Pipe::View(); - } } - { - D3D12Pipe::View &view = state.outputMerger.depthTarget; - - if(rs.dsv.GetResResourceId() != ResourceId()) - { - view.rootElement = 0; - view.immediate = false; - - FillResourceView(view, &rs.dsv); - } - else - { - view = D3D12Pipe::View(); - } - } + if(rs.dsv.GetResResourceId() != ResourceId()) + FillResourceView(state.outputMerger.depthTarget, &rs.dsv); memcpy(state.outputMerger.blendState.blendFactor, rs.blendFactor, sizeof(FLOAT) * 4); @@ -3958,88 +3949,3 @@ void D3D12_ProcessStructured(RDCFile *rdc, SDFile &output) static StructuredProcessRegistration D3D12ProcessRegistration(RDCDriver::D3D12, &D3D12_ProcessStructured); - -#if ENABLED(ENABLE_UNIT_TESTS) - -#undef None - -#include "catch/catch.hpp" - -TEST_CASE("Test get_space ensures sorted nature", "[d3d12]") -{ - D3D12Pipe::Shader shader; - rdcarray &spaces = shader.spaces; - - get_space(spaces, 0).samplers.resize(5); - - CHECK(spaces.size() == 1); - - REQUIRE(shader.FindSpace(0) == 0); - - CHECK(spaces[shader.FindSpace(0)].samplers.size() == 5); - - SECTION("Adding in sorted order") - { - get_space(spaces, 3).srvs.resize(7); - get_space(spaces, 4).uavs.resize(9); - get_space(spaces, 1000).constantBuffers.resize(2); - - CHECK(spaces.size() == 4); - - REQUIRE(shader.FindSpace(0) == 0); - REQUIRE(shader.FindSpace(3) == 1); - REQUIRE(shader.FindSpace(4) == 2); - REQUIRE(shader.FindSpace(1000) == 3); - REQUIRE(shader.FindSpace(99) == -1); - - CHECK(spaces[shader.FindSpace(0)].samplers.size() == 5); - CHECK(spaces[shader.FindSpace(3)].srvs.size() == 7); - CHECK(spaces[shader.FindSpace(4)].uavs.size() == 9); - CHECK(spaces[shader.FindSpace(1000)].constantBuffers.size() == 2); - } - - SECTION("Adding in reverse sorted order") - { - get_space(spaces, 1000).constantBuffers.resize(2); - get_space(spaces, 4).uavs.resize(9); - get_space(spaces, 3).srvs.resize(7); - - CHECK(spaces.size() == 4); - - REQUIRE(shader.FindSpace(0) == 0); - REQUIRE(shader.FindSpace(3) == 1); - REQUIRE(shader.FindSpace(4) == 2); - REQUIRE(shader.FindSpace(1000) == 3); - REQUIRE(shader.FindSpace(99) == -1); - - CHECK(spaces[shader.FindSpace(0)].samplers.size() == 5); - CHECK(spaces[shader.FindSpace(3)].srvs.size() == 7); - CHECK(spaces[shader.FindSpace(4)].uavs.size() == 9); - CHECK(spaces[shader.FindSpace(1000)].constantBuffers.size() == 2); - } - - SECTION("Adding in random order") - { - get_space(spaces, 4).uavs.resize(9); - get_space(spaces, 19).samplers.resize(100); - get_space(spaces, 3).srvs.resize(7); - get_space(spaces, 1000).constantBuffers.resize(2); - - CHECK(spaces.size() == 5); - - REQUIRE(shader.FindSpace(0) == 0); - REQUIRE(shader.FindSpace(3) == 1); - REQUIRE(shader.FindSpace(4) == 2); - REQUIRE(shader.FindSpace(19) == 3); - REQUIRE(shader.FindSpace(1000) == 4); - REQUIRE(shader.FindSpace(99) == -1); - - CHECK(spaces[shader.FindSpace(4)].uavs.size() == 9); - CHECK(spaces[shader.FindSpace(19)].samplers.size() == 100); - CHECK(spaces[shader.FindSpace(0)].samplers.size() == 5); - CHECK(spaces[shader.FindSpace(3)].srvs.size() == 7); - CHECK(spaces[shader.FindSpace(1000)].constantBuffers.size() == 2); - } -} - -#endif diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 073bdc1f5..c368f3192 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -211,10 +211,9 @@ public: void FileChanged() {} AMDCounters *GetAMDCounters() { return m_pAMDCounters; } private: - void FillRegisterSpaces(const D3D12RenderState::RootSignature &rootSig, - const ShaderBindpointMapping &mapping, - rdcarray &spaces, - D3D12_SHADER_VISIBILITY visibility); + void FillRootElements(const D3D12RenderState::RootSignature &rootSig, + const ShaderBindpointMapping *mappings[(uint32_t)ShaderStage::Count], + rdcarray &rootElements); void FillResourceView(D3D12Pipe::View &view, const D3D12Descriptor *desc); void ClearPostVSCache(); diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index cd3ce942b..3f5319124 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -1302,10 +1302,24 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::InputAssembly &el) } template -void DoSerialise(SerialiserType &ser, D3D12Pipe::View &el) +void DoSerialise(SerialiserType &ser, D3D12Pipe::RootSignatureRange &el) { SERIALISE_MEMBER(immediate); SERIALISE_MEMBER(rootElement); + SERIALISE_MEMBER(type); + SERIALISE_MEMBER(visibility); + SERIALISE_MEMBER(registerSpace); + SERIALISE_MEMBER(constantBuffers); + SERIALISE_MEMBER(samplers); + SERIALISE_MEMBER(views); + + SIZE_CHECK(96); +} + +template +void DoSerialise(SerialiserType &ser, D3D12Pipe::View &el) +{ + SERIALISE_MEMBER(bind); SERIALISE_MEMBER(tableIndex); SERIALISE_MEMBER(resourceId); SERIALISE_MEMBER(type); @@ -1328,14 +1342,13 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::View &el) SERIALISE_MEMBER(minLODClamp); - SIZE_CHECK(120); + SIZE_CHECK(112); } template void DoSerialise(SerialiserType &ser, D3D12Pipe::Sampler &el) { - SERIALISE_MEMBER(immediate); - SERIALISE_MEMBER(rootElement); + SERIALISE_MEMBER(bind); SERIALISE_MEMBER(tableIndex); SERIALISE_MEMBER(addressU); SERIALISE_MEMBER(addressV); @@ -1348,33 +1361,20 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::Sampler &el) SERIALISE_MEMBER(minLOD); SERIALISE_MEMBER(mipLODBias); - SIZE_CHECK(76); + SIZE_CHECK(72); } template void DoSerialise(SerialiserType &ser, D3D12Pipe::ConstantBuffer &el) { - SERIALISE_MEMBER(immediate); - SERIALISE_MEMBER(rootElement); + SERIALISE_MEMBER(bind); SERIALISE_MEMBER(tableIndex); SERIALISE_MEMBER(resourceId); SERIALISE_MEMBER(byteOffset); SERIALISE_MEMBER(byteSize); SERIALISE_MEMBER(rootValues); - SIZE_CHECK(64); -} - -template -void DoSerialise(SerialiserType &ser, D3D12Pipe::RegisterSpace &el) -{ - SERIALISE_MEMBER(spaceIndex); - SERIALISE_MEMBER(constantBuffers); - SERIALISE_MEMBER(samplers); - SERIALISE_MEMBER(srvs); - SERIALISE_MEMBER(uavs); - - SIZE_CHECK(104); + SIZE_CHECK(56); } template @@ -1385,9 +1385,8 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::Shader &el) SERIALISE_MEMBER_OPT_EMPTY(reflection); SERIALISE_MEMBER(bindpointMapping); SERIALISE_MEMBER(stage); - SERIALISE_MEMBER(spaces); - SIZE_CHECK(168); + SIZE_CHECK(144); } template @@ -1480,7 +1479,7 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::OM &el) SERIALISE_MEMBER(multiSampleCount); SERIALISE_MEMBER(multiSampleQuality); - SIZE_CHECK(288); + SIZE_CHECK(280); } template @@ -1505,6 +1504,7 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::State &el) { SERIALISE_MEMBER(pipelineResourceId); SERIALISE_MEMBER(rootSignatureResourceId); + SERIALISE_MEMBER(rootElements); SERIALISE_MEMBER(inputAssembly); @@ -1523,7 +1523,7 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::State &el) SERIALISE_MEMBER(resourceStates); - SIZE_CHECK(1536); + SIZE_CHECK(1408); } #pragma endregion D3D12 pipeline state @@ -2323,10 +2323,10 @@ INSTANTIATE_SERIALISE_TYPE(D3D11Pipe::OutputMerger) INSTANTIATE_SERIALISE_TYPE(D3D11Pipe::State) INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::Layout) INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::InputAssembly) +INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::RootSignatureRange) INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::ConstantBuffer) INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::Sampler) INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::View) -INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::RegisterSpace) INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::Shader) INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::Rasterizer) INSTANTIATE_SERIALISE_TYPE(D3D12Pipe::OM)