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)