diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 6eee80584..d6dc79412 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -121,45 +121,51 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, const QIcon &action_hover = Icons::action_hover(); RDLabel *shaderLabels[] = { - ui->vsShader, ui->hsShader, ui->dsShader, ui->gsShader, ui->psShader, ui->csShader, + ui->vsShader, ui->hsShader, ui->dsShader, ui->gsShader, + ui->psShader, ui->csShader, ui->asShader, ui->msShader, }; RDLabel *rootsigLabels[] = { - ui->vsRootSig, ui->hsRootSig, ui->dsRootSig, ui->gsRootSig, ui->psRootSig, ui->csRootSig, + ui->vsRootSig, ui->hsRootSig, ui->dsRootSig, ui->gsRootSig, + ui->psRootSig, ui->csRootSig, ui->asRootSig, ui->msRootSig, }; QToolButton *viewButtons[] = { ui->vsShaderViewButton, ui->hsShaderViewButton, ui->dsShaderViewButton, ui->gsShaderViewButton, ui->psShaderViewButton, ui->csShaderViewButton, + ui->asShaderViewButton, ui->msShaderViewButton, }; QToolButton *editButtons[] = { ui->vsShaderEditButton, ui->hsShaderEditButton, ui->dsShaderEditButton, ui->gsShaderEditButton, ui->psShaderEditButton, ui->csShaderEditButton, + ui->asShaderEditButton, ui->msShaderEditButton, }; QToolButton *saveButtons[] = { ui->vsShaderSaveButton, ui->hsShaderSaveButton, ui->dsShaderSaveButton, ui->gsShaderSaveButton, ui->psShaderSaveButton, ui->csShaderSaveButton, + ui->asShaderSaveButton, ui->msShaderSaveButton, }; RDTreeWidget *resources[] = { - ui->vsResources, ui->hsResources, ui->dsResources, - ui->gsResources, ui->psResources, ui->csResources, + ui->vsResources, ui->hsResources, ui->dsResources, ui->gsResources, + ui->psResources, ui->csResources, ui->asResources, ui->msResources, }; RDTreeWidget *uavs[] = { - ui->vsUAVs, ui->hsUAVs, ui->dsUAVs, ui->gsUAVs, ui->psUAVs, ui->csUAVs, + ui->vsUAVs, ui->hsUAVs, ui->dsUAVs, ui->gsUAVs, + ui->psUAVs, ui->csUAVs, ui->asUAVs, ui->msUAVs, }; RDTreeWidget *samplers[] = { - ui->vsSamplers, ui->hsSamplers, ui->dsSamplers, - ui->gsSamplers, ui->psSamplers, ui->csSamplers, + ui->vsSamplers, ui->hsSamplers, ui->dsSamplers, ui->gsSamplers, + ui->psSamplers, ui->csSamplers, ui->asSamplers, ui->msSamplers, }; RDTreeWidget *cbuffers[] = { - ui->vsCBuffers, ui->hsCBuffers, ui->dsCBuffers, - ui->gsCBuffers, ui->psCBuffers, ui->csCBuffers, + ui->vsCBuffers, ui->hsCBuffers, ui->dsCBuffers, ui->gsCBuffers, + ui->psCBuffers, ui->csCBuffers, ui->asCBuffers, ui->msCBuffers, }; // setup FlowLayout for CS shader group, with debugging controls @@ -436,39 +442,23 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, ui->stagesTabs->tabBar()->setVisible(false); - ui->pipeFlow->setStages( - { - lit("IA"), - lit("VS"), - lit("HS"), - lit("DS"), - lit("GS"), - lit("RS"), - lit("PS"), - lit("OM"), - lit("CS"), - }, - { - tr("Input Assembler"), - tr("Vertex Shader"), - tr("Hull Shader"), - tr("Domain Shader"), - tr("Geometry Shader"), - tr("Rasterizer"), - tr("Pixel Shader"), - tr("Output Merger"), - tr("Compute Shader"), - }); - - ui->pipeFlow->setIsolatedStage(8); // compute shader isolated - - ui->pipeFlow->setStagesEnabled({true, true, true, true, true, true, true, true, true}); + setOldMeshPipeFlow(); m_Common.setMeshViewPixmap(ui->meshView); ui->iaLayouts->setFont(Formatter::PreferredFont()); ui->iaBuffers->setFont(Formatter::PreferredFont()); ui->gsStreamOut->setFont(Formatter::PreferredFont()); + ui->asShader->setFont(Formatter::PreferredFont()); + ui->asResources->setFont(Formatter::PreferredFont()); + ui->asSamplers->setFont(Formatter::PreferredFont()); + ui->asCBuffers->setFont(Formatter::PreferredFont()); + ui->asUAVs->setFont(Formatter::PreferredFont()); + ui->msShader->setFont(Formatter::PreferredFont()); + ui->msResources->setFont(Formatter::PreferredFont()); + ui->msSamplers->setFont(Formatter::PreferredFont()); + ui->msCBuffers->setFont(Formatter::PreferredFont()); + ui->msUAVs->setFont(Formatter::PreferredFont()); ui->vsShader->setFont(Formatter::PreferredFont()); ui->vsResources->setFont(Formatter::PreferredFont()); ui->vsSamplers->setFont(Formatter::PreferredFont()); @@ -521,7 +511,7 @@ void D3D12PipelineStateViewer::OnCaptureLoaded() void D3D12PipelineStateViewer::OnCaptureClosed() { - ui->pipeFlow->setStagesEnabled({true, true, true, true, true, true, true, true, true}); + setOldMeshPipeFlow(); clearState(); } @@ -935,6 +925,10 @@ const D3D12Pipe::Shader *D3D12PipelineStateViewer::stageForSender(QWidget *widge return &m_Ctx.CurD3D12PipelineState()->pixelShader; if(widget == ui->stagesTabs->widget(8)) return &m_Ctx.CurD3D12PipelineState()->computeShader; + if(widget == ui->stagesTabs->widget(9)) + return &m_Ctx.CurD3D12PipelineState()->ampShader; + if(widget == ui->stagesTabs->widget(10)) + return &m_Ctx.CurD3D12PipelineState()->meshShader; widget = widget->parentWidget(); } @@ -944,6 +938,62 @@ const D3D12Pipe::Shader *D3D12PipelineStateViewer::stageForSender(QWidget *widge return NULL; } +void D3D12PipelineStateViewer::setOldMeshPipeFlow() +{ + m_MeshPipe = false; + + ui->pipeFlow->setStages( + { + lit("IA"), + lit("VS"), + lit("HS"), + lit("DS"), + lit("GS"), + lit("RS"), + lit("PS"), + lit("OM"), + lit("CS"), + }, + { + tr("Input Assembler"), + tr("Vertex Shader"), + tr("Hull Shader"), + tr("Domain Shader"), + tr("Geometry Shader"), + tr("Rasterizer"), + tr("Pixel Shader"), + tr("Output Merger"), + tr("Compute Shader"), + }); + + ui->pipeFlow->setIsolatedStage(8); // compute shader isolated +} + +void D3D12PipelineStateViewer::setNewMeshPipeFlow() +{ + m_MeshPipe = true; + + ui->pipeFlow->setStages( + { + lit("AS"), + lit("MS"), + lit("RS"), + lit("PS"), + lit("OM"), + lit("CS"), + }, + { + tr("Amp. Shader"), + tr("Mesh Shader"), + tr("Rasterizer"), + tr("Pixel Shader"), + tr("Output Merger"), + tr("Compute Shader"), + }); + + ui->pipeFlow->setIsolatedStage(5); // compute shader isolated +} + void D3D12PipelineStateViewer::clearShaderState(RDLabel *shader, RDLabel *rootSig, RDTreeWidget *tex, RDTreeWidget *samp, RDTreeWidget *cbuffer, RDTreeWidget *sub) @@ -966,6 +1016,10 @@ void D3D12PipelineStateViewer::clearState() ui->topology->setText(QString()); ui->topologyDiagram->setPixmap(QPixmap()); + clearShaderState(ui->asShader, ui->asRootSig, ui->asResources, ui->asSamplers, ui->asCBuffers, + ui->asUAVs); + clearShaderState(ui->msShader, ui->msRootSig, ui->msResources, ui->msSamplers, ui->msCBuffers, + ui->msUAVs); clearShaderState(ui->vsShader, ui->vsRootSig, ui->vsResources, ui->vsSamplers, ui->vsCBuffers, ui->vsUAVs); clearShaderState(ui->gsShader, ui->gsRootSig, ui->gsResources, ui->gsSamplers, ui->gsCBuffers, @@ -982,12 +1036,33 @@ void D3D12PipelineStateViewer::clearState() ui->gsStreamOut->clear(); QToolButton *shaderButtons[] = { - ui->vsShaderViewButton, ui->hsShaderViewButton, ui->dsShaderViewButton, - ui->gsShaderViewButton, ui->psShaderViewButton, ui->csShaderViewButton, - ui->vsShaderEditButton, ui->hsShaderEditButton, ui->dsShaderEditButton, - ui->gsShaderEditButton, ui->psShaderEditButton, ui->csShaderEditButton, - ui->vsShaderSaveButton, ui->hsShaderSaveButton, ui->dsShaderSaveButton, - ui->gsShaderSaveButton, ui->psShaderSaveButton, ui->csShaderSaveButton, + // view buttons + ui->asShaderViewButton, + ui->msShaderViewButton, + ui->vsShaderViewButton, + ui->hsShaderViewButton, + ui->dsShaderViewButton, + ui->gsShaderViewButton, + ui->psShaderViewButton, + ui->csShaderViewButton, + // edit buttons + ui->asShaderEditButton, + ui->msShaderEditButton, + ui->vsShaderEditButton, + ui->hsShaderEditButton, + ui->dsShaderEditButton, + ui->gsShaderEditButton, + ui->psShaderEditButton, + ui->csShaderEditButton, + // save buttons + ui->asShaderSaveButton, + ui->msShaderSaveButton, + ui->vsShaderSaveButton, + ui->hsShaderSaveButton, + ui->dsShaderSaveButton, + ui->gsShaderSaveButton, + ui->psShaderSaveButton, + ui->csShaderSaveButton, }; for(QToolButton *b : shaderButtons) @@ -1558,6 +1633,53 @@ void D3D12PipelineStateViewer::setState() const QPixmap &tick = Pixmaps::tick(this); const QPixmap &cross = Pixmaps::cross(this); + // highlight the appropriate stages in the flowchart + if(action == NULL) + { + setOldMeshPipeFlow(); + ui->pipeFlow->setStagesEnabled({true, true, true, true, true, true, true, true, true}); + } + else if(action->flags & ActionFlags::Dispatch) + { + setOldMeshPipeFlow(); + ui->pipeFlow->setStagesEnabled({false, false, false, false, false, false, false, false, true}); + } + else if(action->flags & ActionFlags::MeshDispatch) + { + setNewMeshPipeFlow(); + ui->pipeFlow->setStagesEnabled( + {state.ampShader.resourceId != ResourceId(), true, true, true, true, false}); + } + else + { + bool streamOutActive = false; + + for(const D3D12Pipe::StreamOutBind &o : state.streamOut.outputs) + { + if(o.resourceId != ResourceId()) + { + streamOutActive = true; + break; + } + } + + if(state.geometryShader.resourceId == ResourceId() && streamOutActive) + { + ui->pipeFlow->setStageName(4, lit("SO"), tr("Stream Out")); + } + else + { + ui->pipeFlow->setStageName(4, lit("GS"), tr("Geometry Shader")); + } + + setOldMeshPipeFlow(); + ui->pipeFlow->setStagesEnabled( + {true, true, state.hullShader.resourceId != ResourceId(), + state.domainShader.resourceId != ResourceId(), + state.geometryShader.resourceId != ResourceId() || streamOutActive, true, + state.pixelShader.resourceId != ResourceId(), true, false}); + } + //////////////////////////////////////////////// // Vertex Input @@ -1566,209 +1688,273 @@ void D3D12PipelineStateViewer::setState() bool usedVBuffers[128] = {}; uint32_t layoutOffs[128] = {}; - vs = ui->iaLayouts->verticalScrollBar()->value(); - ui->iaLayouts->beginUpdate(); - ui->iaLayouts->clear(); + if(m_MeshPipe) { - int i = 0; - for(const D3D12Pipe::Layout &l : state.inputAssembly.layouts) + setShaderState(state.rootElements, state.ampShader, ui->asShader, ui->asRootSig, + ui->asResources, ui->asSamplers, ui->asCBuffers, ui->asUAVs); + setShaderState(state.rootElements, state.meshShader, ui->msShader, ui->msRootSig, + ui->msResources, ui->msSamplers, ui->msCBuffers, ui->msUAVs); + + ui->msTopology->setText(ToQStr(state.meshShader.reflection->outputTopology)); + } + else + { + vs = ui->iaLayouts->verticalScrollBar()->value(); + ui->iaLayouts->beginUpdate(); + ui->iaLayouts->clear(); { - QString byteOffs = QString::number(l.byteOffset); - - // D3D12 specific value - if(l.byteOffset == ~0U) + int i = 0; + for(const D3D12Pipe::Layout &l : state.inputAssembly.layouts) { - byteOffs = lit("APPEND_ALIGNED (%1)").arg(layoutOffs[l.inputSlot]); - } - else - { - layoutOffs[l.inputSlot] = l.byteOffset; - } + QString byteOffs = QString::number(l.byteOffset); - layoutOffs[l.inputSlot] += l.format.compByteWidth * l.format.compCount; - - bool filledSlot = true; - bool usedSlot = false; - - for(int ia = 0; state.vertexShader.reflection && - ia < state.vertexShader.reflection->inputSignature.count(); - ia++) - { - if(!QString(state.vertexShader.reflection->inputSignature[ia].semanticName) - .compare(l.semanticName, Qt::CaseInsensitive) && - state.vertexShader.reflection->inputSignature[ia].semanticIndex == l.semanticIndex) + // D3D12 specific value + if(l.byteOffset == ~0U) { - usedSlot = true; - break; + byteOffs = lit("APPEND_ALIGNED (%1)").arg(layoutOffs[l.inputSlot]); } + else + { + layoutOffs[l.inputSlot] = l.byteOffset; + } + + layoutOffs[l.inputSlot] += l.format.compByteWidth * l.format.compCount; + + bool filledSlot = true; + bool usedSlot = false; + + for(int ia = 0; state.vertexShader.reflection && + ia < state.vertexShader.reflection->inputSignature.count(); + ia++) + { + if(!QString(state.vertexShader.reflection->inputSignature[ia].semanticName) + .compare(l.semanticName, Qt::CaseInsensitive) && + state.vertexShader.reflection->inputSignature[ia].semanticIndex == l.semanticIndex) + { + usedSlot = true; + break; + } + } + + if(showNode(usedSlot, filledSlot)) + { + RDTreeWidgetItem *node = new RDTreeWidgetItem( + {i, l.semanticName, l.semanticIndex, l.format.Name(), l.inputSlot, byteOffs, + l.perInstance ? lit("PER_INSTANCE") : lit("PER_VERTEX"), l.instanceDataStepRate, + QString()}); + + node->setTag(i); + + if(usedSlot) + usedVBuffers[l.inputSlot] = true; + + if(!usedSlot) + setInactiveRow(node); + + ui->iaLayouts->addTopLevelItem(node); + } + + i++; } + } + ui->iaLayouts->clearSelection(); + ui->iaLayouts->endUpdate(); + ui->iaLayouts->verticalScrollBar()->setValue(vs); + + int numCPs = PatchList_Count(state.inputAssembly.topology); + if(numCPs > 0) + { + ui->topology->setText(tr("PatchList (%1 Control Points)").arg(numCPs)); + } + else + { + ui->topology->setText(ToQStr(state.inputAssembly.topology)); + } + + m_Common.setTopologyDiagram(ui->topologyDiagram, state.inputAssembly.topology); + + bool ibufferUsed = action && (action->flags & ActionFlags::Indexed); + + m_VBNodes.clear(); + m_EmptyNodes.clear(); + + vs = ui->iaBuffers->verticalScrollBar()->value(); + ui->iaBuffers->beginUpdate(); + ui->iaBuffers->clear(); + + if(state.inputAssembly.indexBuffer.resourceId != ResourceId()) + { + if(ibufferUsed || m_ShowUnused) + { + uint64_t length = state.inputAssembly.indexBuffer.byteSize; + + BufferDescription *buf = m_Ctx.GetBuffer(state.inputAssembly.indexBuffer.resourceId); + + RDTreeWidgetItem *node = new RDTreeWidgetItem( + {tr("Index"), state.inputAssembly.indexBuffer.resourceId, + (qulonglong)state.inputAssembly.indexBuffer.byteStride, + (qulonglong)state.inputAssembly.indexBuffer.byteOffset, (qulonglong)length, QString()}); + + QString iformat; + + if(state.inputAssembly.indexBuffer.byteStride == 1) + iformat = lit("ubyte"); + else if(state.inputAssembly.indexBuffer.byteStride == 2) + iformat = lit("ushort"); + else if(state.inputAssembly.indexBuffer.byteStride == 4) + iformat = lit("uint"); + + iformat += + lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(state.inputAssembly.topology)); + + uint32_t drawOffset = + (action ? action->indexOffset * state.inputAssembly.indexBuffer.byteStride : 0); + + node->setTag(QVariant::fromValue( + D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId, + state.inputAssembly.indexBuffer.byteOffset + drawOffset, + drawOffset > state.inputAssembly.indexBuffer.byteSize + ? 0 + : state.inputAssembly.indexBuffer.byteSize - drawOffset, + iformat))); + + for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) + { + if(res.resourceId == state.inputAssembly.indexBuffer.resourceId) + { + node->setToolTip(tr("Buffer is in the '%1' state").arg(res.states[0].name)); + break; + } + } + + if(!ibufferUsed) + setInactiveRow(node); + + if(state.inputAssembly.indexBuffer.resourceId == ResourceId()) + { + setEmptyRow(node); + m_EmptyNodes.push_back(node); + } + + ui->iaBuffers->addTopLevelItem(node); + } + } + else + { + if(ibufferUsed || m_ShowEmpty) + { + RDTreeWidgetItem *node = new RDTreeWidgetItem( + {tr("Index"), tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); + + QString iformat; + + if(state.inputAssembly.indexBuffer.byteStride == 1) + iformat = lit("ubyte"); + else if(state.inputAssembly.indexBuffer.byteStride == 2) + iformat = lit("ushort"); + else if(state.inputAssembly.indexBuffer.byteStride == 4) + iformat = lit("uint"); + + iformat += + lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(state.inputAssembly.topology)); + + uint32_t drawOffset = + (action ? action->indexOffset * state.inputAssembly.indexBuffer.byteStride : 0); + + node->setTag(QVariant::fromValue( + D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId, + state.inputAssembly.indexBuffer.byteOffset + drawOffset, + drawOffset > state.inputAssembly.indexBuffer.byteSize + ? 0 + : state.inputAssembly.indexBuffer.byteSize - drawOffset, + iformat))); + + for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) + { + if(res.resourceId == state.inputAssembly.indexBuffer.resourceId) + { + node->setToolTip(tr("Buffer is in the '%1' state").arg(res.states[0].name)); + break; + } + } + + setEmptyRow(node); + m_EmptyNodes.push_back(node); + + if(!ibufferUsed) + setInactiveRow(node); + + ui->iaBuffers->addTopLevelItem(node); + } + } + + for(int i = 0; i < 128; i++) + { + if(i >= state.inputAssembly.vertexBuffers.count()) + { + // for vbuffers that are referenced but not bound, make sure we add an empty row + if(usedVBuffers[i]) + { + RDTreeWidgetItem *node = + new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); + node->setTag(QVariant::fromValue(D3D12VBIBTag(ResourceId(), 0, 0))); + + setEmptyRow(node); + m_EmptyNodes.push_back(node); + + m_VBNodes.push_back(node); + + ui->iaBuffers->addTopLevelItem(node); + } + else + { + m_VBNodes.push_back(NULL); + } + + continue; + } + + const D3D12Pipe::VertexBuffer &v = state.inputAssembly.vertexBuffers[i]; + + bool filledSlot = (v.resourceId != ResourceId()); + bool usedSlot = (usedVBuffers[i]); if(showNode(usedSlot, filledSlot)) { - RDTreeWidgetItem *node = - new RDTreeWidgetItem({i, l.semanticName, l.semanticIndex, l.format.Name(), l.inputSlot, - byteOffs, l.perInstance ? lit("PER_INSTANCE") : lit("PER_VERTEX"), - l.instanceDataStepRate, QString()}); + qulonglong length = v.byteSize; - node->setTag(i); + BufferDescription *buf = m_Ctx.GetBuffer(v.resourceId); - if(usedSlot) - usedVBuffers[l.inputSlot] = true; + RDTreeWidgetItem *node = NULL; + + if(filledSlot) + node = new RDTreeWidgetItem( + {i, v.resourceId, v.byteStride, (qulonglong)v.byteOffset, length, QString()}); + else + node = + new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); + + node->setTag(QVariant::fromValue(D3D12VBIBTag(v.resourceId, v.byteOffset, v.byteSize, + m_Common.GetVBufferFormatString(i)))); + + for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) + { + if(res.resourceId == v.resourceId) + { + node->setToolTip(tr("Buffer is in the '%1' state").arg(res.states[0].name)); + break; + } + } + + if(!filledSlot) + { + setEmptyRow(node); + m_EmptyNodes.push_back(node); + } if(!usedSlot) setInactiveRow(node); - ui->iaLayouts->addTopLevelItem(node); - } - - i++; - } - } - ui->iaLayouts->clearSelection(); - ui->iaLayouts->endUpdate(); - ui->iaLayouts->verticalScrollBar()->setValue(vs); - - int numCPs = PatchList_Count(state.inputAssembly.topology); - if(numCPs > 0) - { - ui->topology->setText(tr("PatchList (%1 Control Points)").arg(numCPs)); - } - else - { - ui->topology->setText(ToQStr(state.inputAssembly.topology)); - } - - m_Common.setTopologyDiagram(ui->topologyDiagram, state.inputAssembly.topology); - - bool ibufferUsed = action && (action->flags & ActionFlags::Indexed); - - m_VBNodes.clear(); - m_EmptyNodes.clear(); - - vs = ui->iaBuffers->verticalScrollBar()->value(); - ui->iaBuffers->beginUpdate(); - ui->iaBuffers->clear(); - - if(state.inputAssembly.indexBuffer.resourceId != ResourceId()) - { - if(ibufferUsed || m_ShowUnused) - { - uint64_t length = state.inputAssembly.indexBuffer.byteSize; - - BufferDescription *buf = m_Ctx.GetBuffer(state.inputAssembly.indexBuffer.resourceId); - - RDTreeWidgetItem *node = new RDTreeWidgetItem( - {tr("Index"), state.inputAssembly.indexBuffer.resourceId, - (qulonglong)state.inputAssembly.indexBuffer.byteStride, - (qulonglong)state.inputAssembly.indexBuffer.byteOffset, (qulonglong)length, QString()}); - - QString iformat; - - if(state.inputAssembly.indexBuffer.byteStride == 1) - iformat = lit("ubyte"); - else if(state.inputAssembly.indexBuffer.byteStride == 2) - iformat = lit("ushort"); - else if(state.inputAssembly.indexBuffer.byteStride == 4) - iformat = lit("uint"); - - iformat += - lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(state.inputAssembly.topology)); - - uint32_t drawOffset = - (action ? action->indexOffset * state.inputAssembly.indexBuffer.byteStride : 0); - - node->setTag(QVariant::fromValue( - D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId, - state.inputAssembly.indexBuffer.byteOffset + drawOffset, - drawOffset > state.inputAssembly.indexBuffer.byteSize - ? 0 - : state.inputAssembly.indexBuffer.byteSize - drawOffset, - iformat))); - - for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) - { - if(res.resourceId == state.inputAssembly.indexBuffer.resourceId) - { - node->setToolTip(tr("Buffer is in the '%1' state").arg(res.states[0].name)); - break; - } - } - - if(!ibufferUsed) - setInactiveRow(node); - - if(state.inputAssembly.indexBuffer.resourceId == ResourceId()) - { - setEmptyRow(node); - m_EmptyNodes.push_back(node); - } - - ui->iaBuffers->addTopLevelItem(node); - } - } - else - { - if(ibufferUsed || m_ShowEmpty) - { - RDTreeWidgetItem *node = new RDTreeWidgetItem( - {tr("Index"), tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); - - QString iformat; - - if(state.inputAssembly.indexBuffer.byteStride == 1) - iformat = lit("ubyte"); - else if(state.inputAssembly.indexBuffer.byteStride == 2) - iformat = lit("ushort"); - else if(state.inputAssembly.indexBuffer.byteStride == 4) - iformat = lit("uint"); - - iformat += - lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(state.inputAssembly.topology)); - - uint32_t drawOffset = - (action ? action->indexOffset * state.inputAssembly.indexBuffer.byteStride : 0); - - node->setTag(QVariant::fromValue( - D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId, - state.inputAssembly.indexBuffer.byteOffset + drawOffset, - drawOffset > state.inputAssembly.indexBuffer.byteSize - ? 0 - : state.inputAssembly.indexBuffer.byteSize - drawOffset, - iformat))); - - for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) - { - if(res.resourceId == state.inputAssembly.indexBuffer.resourceId) - { - node->setToolTip(tr("Buffer is in the '%1' state").arg(res.states[0].name)); - break; - } - } - - setEmptyRow(node); - m_EmptyNodes.push_back(node); - - if(!ibufferUsed) - setInactiveRow(node); - - ui->iaBuffers->addTopLevelItem(node); - } - } - - for(int i = 0; i < 128; i++) - { - if(i >= state.inputAssembly.vertexBuffers.count()) - { - // for vbuffers that are referenced but not bound, make sure we add an empty row - if(usedVBuffers[i]) - { - RDTreeWidgetItem *node = - new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); - node->setTag(QVariant::fromValue(D3D12VBIBTag(ResourceId(), 0, 0))); - - setEmptyRow(node); - m_EmptyNodes.push_back(node); - m_VBNodes.push_back(node); ui->iaBuffers->addTopLevelItem(node); @@ -1777,84 +1963,54 @@ void D3D12PipelineStateViewer::setState() { m_VBNodes.push_back(NULL); } - - continue; } + ui->iaBuffers->clearSelection(); + ui->iaBuffers->endUpdate(); + ui->iaBuffers->verticalScrollBar()->setValue(vs); - const D3D12Pipe::VertexBuffer &v = state.inputAssembly.vertexBuffers[i]; - - bool filledSlot = (v.resourceId != ResourceId()); - bool usedSlot = (usedVBuffers[i]); - - if(showNode(usedSlot, filledSlot)) - { - qulonglong length = v.byteSize; - - BufferDescription *buf = m_Ctx.GetBuffer(v.resourceId); - - RDTreeWidgetItem *node = NULL; - - if(filledSlot) - node = new RDTreeWidgetItem( - {i, v.resourceId, v.byteStride, (qulonglong)v.byteOffset, length, QString()}); - else - node = - new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); - - node->setTag(QVariant::fromValue(D3D12VBIBTag(v.resourceId, v.byteOffset, v.byteSize, - m_Common.GetVBufferFormatString(i)))); - - for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) - { - if(res.resourceId == v.resourceId) - { - node->setToolTip(tr("Buffer is in the '%1' state").arg(res.states[0].name)); - break; - } - } - - if(!filledSlot) - { - setEmptyRow(node); - m_EmptyNodes.push_back(node); - } - - if(!usedSlot) - setInactiveRow(node); - - m_VBNodes.push_back(node); - - ui->iaBuffers->addTopLevelItem(node); - } - else - { - m_VBNodes.push_back(NULL); - } + 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); } - ui->iaBuffers->clearSelection(); - ui->iaBuffers->endUpdate(); - ui->iaBuffers->verticalScrollBar()->setValue(vs); - 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, - ui->gsShaderViewButton, ui->psShaderViewButton, ui->csShaderViewButton, - ui->vsShaderEditButton, ui->hsShaderEditButton, ui->dsShaderEditButton, - ui->gsShaderEditButton, ui->psShaderEditButton, ui->csShaderEditButton, - ui->vsShaderSaveButton, ui->hsShaderSaveButton, ui->dsShaderSaveButton, - ui->gsShaderSaveButton, ui->psShaderSaveButton, ui->csShaderSaveButton, + // view buttons + ui->asShaderViewButton, + ui->msShaderViewButton, + ui->vsShaderViewButton, + ui->hsShaderViewButton, + ui->dsShaderViewButton, + ui->gsShaderViewButton, + ui->psShaderViewButton, + ui->csShaderViewButton, + // edit buttons + ui->asShaderEditButton, + ui->msShaderEditButton, + ui->vsShaderEditButton, + ui->hsShaderEditButton, + ui->dsShaderEditButton, + ui->gsShaderEditButton, + ui->psShaderEditButton, + ui->csShaderEditButton, + // save buttons + ui->asShaderSaveButton, + ui->msShaderSaveButton, + ui->vsShaderSaveButton, + ui->hsShaderSaveButton, + ui->dsShaderSaveButton, + ui->gsShaderSaveButton, + ui->psShaderSaveButton, + ui->csShaderSaveButton, }; for(QToolButton *b : shaderButtons) @@ -2193,44 +2349,6 @@ void D3D12PipelineStateViewer::setState() else ui->computeDebugSelector->setToolTip(tr("Invalid dispatch/threadgroup dimensions.")); } - - // highlight the appropriate stages in the flowchart - if(action == NULL) - { - ui->pipeFlow->setStagesEnabled({true, true, true, true, true, true, true, true, true}); - } - else if(action->flags & ActionFlags::Dispatch) - { - ui->pipeFlow->setStagesEnabled({false, false, false, false, false, false, false, false, true}); - } - else - { - bool streamOutActive = false; - - for(const D3D12Pipe::StreamOutBind &o : state.streamOut.outputs) - { - if(o.resourceId != ResourceId()) - { - streamOutActive = true; - break; - } - } - - if(state.geometryShader.resourceId == ResourceId() && streamOutActive) - { - ui->pipeFlow->setStageName(4, lit("SO"), tr("Stream Out")); - } - else - { - ui->pipeFlow->setStageName(4, lit("GS"), tr("Geometry Shader")); - } - - ui->pipeFlow->setStagesEnabled( - {true, true, state.hullShader.resourceId != ResourceId(), - state.domainShader.resourceId != ResourceId(), - state.geometryShader.resourceId != ResourceId() || streamOutActive, true, - state.pixelShader.resourceId != ResourceId(), true, false}); - } } void D3D12PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, int column) @@ -2530,7 +2648,26 @@ void D3D12PipelineStateViewer::vertex_leave(QEvent *e) void D3D12PipelineStateViewer::on_pipeFlow_stageSelected(int index) { - ui->stagesTabs->setCurrentIndex(index); + if(m_MeshPipe) + { + // remap since AS/MS are the last tabs but appear first in the flow + switch(index) + { + // AS + case 0: ui->stagesTabs->setCurrentIndex(9); break; + // MS + case 1: ui->stagesTabs->setCurrentIndex(10); break; + // raster onwards are the same, just skipping VTX,VS,HS,DS,GS + case 2: ui->stagesTabs->setCurrentIndex(5); break; + case 3: ui->stagesTabs->setCurrentIndex(6); break; + case 4: ui->stagesTabs->setCurrentIndex(7); break; + case 5: ui->stagesTabs->setCurrentIndex(8); break; + } + } + else + { + ui->stagesTabs->setCurrentIndex(index); + } } void D3D12PipelineStateViewer::shaderView_clicked() @@ -3545,36 +3682,63 @@ void D3D12PipelineStateViewer::on_exportHTML_clicked() xml.writeCharacters(sn); xml.writeEndElement(); - switch(stage) + if(m_MeshPipe) { - case 0: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->inputAssembly); 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, - 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, - m_Ctx.CurD3D12PipelineState()->rootElements); - break; - case 7: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->outputMerger); break; - case 8: - exportHTML(xml, m_Ctx.CurD3D12PipelineState()->computeShader, - m_Ctx.CurD3D12PipelineState()->rootElements); - break; + switch(stage) + { + case 0: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->ampShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; + case 1: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->meshShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; + case 2: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->rasterizer); break; + case 3: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->pixelShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; + case 4: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->outputMerger); break; + case 5: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->computeShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; + } + } + else + { + switch(stage) + { + case 0: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->inputAssembly); 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, + 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, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; + case 7: exportHTML(xml, m_Ctx.CurD3D12PipelineState()->outputMerger); break; + case 8: + exportHTML(xml, m_Ctx.CurD3D12PipelineState()->computeShader, + m_Ctx.CurD3D12PipelineState()->rootElements); + break; + } } xml.writeEndElement(); @@ -3586,6 +3750,13 @@ void D3D12PipelineStateViewer::on_exportHTML_clicked() } } +void D3D12PipelineStateViewer::on_msMeshButton_clicked() +{ + if(!m_Ctx.HasMeshPreview()) + m_Ctx.ShowMeshPreview(); + ToolWindowManager::raiseToolWindow(m_Ctx.GetMeshPreview()->Widget()); +} + void D3D12PipelineStateViewer::on_meshView_clicked() { if(!m_Ctx.HasMeshPreview()) diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h index 20a22bddf..b95cd7c0b 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h @@ -65,6 +65,7 @@ private slots: void on_showEmpty_toggled(bool checked); void on_exportHTML_clicked(); void on_meshView_clicked(); + void on_msMeshButton_clicked(); void on_iaLayouts_itemActivated(RDTreeWidgetItem *item, int column); void on_iaBuffers_itemActivated(RDTreeWidgetItem *item, int column); void on_iaLayouts_mouseMove(QMouseEvent *event); @@ -88,6 +89,9 @@ private: PipelineStateViewer &m_Common; ComputeDebugSelector *m_ComputeDebugSelector; + void setOldMeshPipeFlow(); + void setNewMeshPipeFlow(); + void setShaderState(const rdcarray &rootElements, const D3D12Pipe::Shader &stage, RDLabel *shader, RDLabel *rootSig, RDTreeWidget *tex, RDTreeWidget *samp, RDTreeWidget *cbuffer, @@ -129,4 +133,6 @@ private: QList m_VBNodes; // list of empty VB nodes that shouldn't be highlighted on hover QList m_EmptyNodes; + + bool m_MeshPipe = false; }; diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.ui index d7f974b3a..c97e8d488 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.ui +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.ui @@ -4096,6 +4096,882 @@ + + + Amplification Shader + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Shader + + + + 0 + + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::Box + + + + + + + QFrame::Box + + + + + + + PointingHandCursor + + + Open Shader Source + + + View + + + + :/action.png:/action.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Edit Shader + + + Edit + + + + :/page_white_edit.png:/page_white_edit.png + + + QToolButton::MenuButtonPopup + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Save Shader DXBC + + + Save + + + + :/save.png:/save.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 868 + 452 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 1 + + + + Resources + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + true + + + false + + + + + + + + + + + 0 + 1 + + + + UAVs + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + true + + + false + + + + + + + + + + + 0 + 1 + + + + Samplers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + true + + + false + + + + + + + + + + + 0 + 1 + + + + Constant Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + true + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + + + + + + Mesh Shader + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Shader + + + + 0 + + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::Box + + + + + + + QFrame::Box + + + + + + + PointingHandCursor + + + Open Shader Source + + + View + + + + :/action.png:/action.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Edit Shader + + + Edit + + + + :/page_white_edit.png:/page_white_edit.png + + + QToolButton::MenuButtonPopup + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Save Shader DXBC + + + Save + + + + :/save.png:/save.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + + + View Mesh + + + View Mesh + + + + :/draw_vertex.png:/draw_vertex.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Output Topology: + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 868 + 452 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 1 + + + + Resources + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + true + + + false + + + + + + + + + + + 0 + 1 + + + + UAVs + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + true + + + false + + + + + + + + + + + 0 + 1 + + + + Samplers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + true + + + false + + + + + + + + + + + 0 + 1 + + + + Constant Buffers + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + true + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + + + diff --git a/renderdoc/api/replay/pipestate.inl b/renderdoc/api/replay/pipestate.inl index 2083ae8bf..993c86d5a 100644 --- a/renderdoc/api/replay/pipestate.inl +++ b/renderdoc/api/replay/pipestate.inl @@ -119,7 +119,9 @@ bool PipeState::IsD3D12Stage(ShaderStage stage) const case ShaderStage::Hull: case ShaderStage::Geometry: case ShaderStage::Pixel: - case ShaderStage::Compute: return true; + case ShaderStage::Compute: + case ShaderStage::Amplification: + case ShaderStage::Mesh: return true; default: return false; } } @@ -187,6 +189,10 @@ const D3D12Pipe::Shader &PipeState::GetD3D12Stage(ShaderStage stage) const return m_D3D12->pixelShader; if(stage == ShaderStage::Compute) return m_D3D12->computeShader; + if(stage == ShaderStage::Amplification) + return m_D3D12->ampShader; + if(stage == ShaderStage::Mesh) + return m_D3D12->meshShader; RENDERDOC_LogMessage(LogType::Error, "PIPE", __FILE__, __LINE__, "Error - invalid stage"); return m_D3D12->computeShader; @@ -315,6 +321,8 @@ const ShaderBindpointMapping &PipeState::GetBindpointMapping(ShaderStage stage) case ShaderStage::Geometry: return m_D3D12->geometryShader.bindpointMapping; case ShaderStage::Pixel: return m_D3D12->pixelShader.bindpointMapping; case ShaderStage::Compute: return m_D3D12->computeShader.bindpointMapping; + case ShaderStage::Amplification: return m_D3D12->ampShader.bindpointMapping; + case ShaderStage::Mesh: return m_D3D12->meshShader.bindpointMapping; default: break; } } @@ -380,6 +388,8 @@ const ShaderReflection *PipeState::GetShaderReflection(ShaderStage stage) const case ShaderStage::Geometry: return m_D3D12->geometryShader.reflection; case ShaderStage::Pixel: return m_D3D12->pixelShader.reflection; case ShaderStage::Compute: return m_D3D12->computeShader.reflection; + case ShaderStage::Amplification: return m_D3D12->ampShader.reflection; + case ShaderStage::Mesh: return m_D3D12->meshShader.reflection; default: break; } } @@ -502,6 +512,8 @@ ResourceId PipeState::GetShader(ShaderStage stage) const case ShaderStage::Geometry: return m_D3D12->geometryShader.resourceId; case ShaderStage::Pixel: return m_D3D12->pixelShader.resourceId; case ShaderStage::Compute: return m_D3D12->computeShader.resourceId; + case ShaderStage::Amplification: return m_D3D12->ampShader.resourceId; + case ShaderStage::Mesh: return m_D3D12->meshShader.resourceId; default: break; } } diff --git a/renderdoc/driver/d3d12/d3d12_command_list6_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list6_wrap.cpp index 5776ef88e..10ed31d91 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list6_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list6_wrap.cpp @@ -24,9 +24,90 @@ #include "d3d12_command_list.h" +template +bool WrappedID3D12GraphicsCommandList::Serialise_DispatchMesh(SerialiserType &ser, + UINT ThreadGroupCountX, + UINT ThreadGroupCountY, + UINT ThreadGroupCountZ) +{ + ID3D12GraphicsCommandList6 *pCommandList = this; + SERIALISE_ELEMENT(pCommandList); + SERIALISE_ELEMENT(ThreadGroupCountX).Important(); + SERIALISE_ELEMENT(ThreadGroupCountY).Important(); + SERIALISE_ELEMENT(ThreadGroupCountZ).Important(); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + if(GetWrapped(pCommandList)->GetReal6() == NULL) + { + SET_ERROR_RESULT(m_Cmd->m_FailedReplayResult, ResultCode::APIHardwareUnsupported, + "Capture requires ID3D12GraphicsCommandList6 which isn't available"); + return false; + } + + if(m_pDevice->GetOpts7().MeshShaderTier == D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) + { + SET_ERROR_RESULT(m_Cmd->m_FailedReplayResult, ResultCode::APIHardwareUnsupported, + "Capture requires mesh shading support which isn't available"); + return false; + } + + m_Cmd->m_LastCmdListID = GetResourceManager()->GetOriginalID(GetResID(pCommandList)); + + if(IsActiveReplaying(m_State)) + { + if(m_Cmd->InRerecordRange(m_Cmd->m_LastCmdListID)) + { + ID3D12GraphicsCommandListX *list = m_Cmd->RerecordCmdList(m_Cmd->m_LastCmdListID); + + uint32_t eventId = m_Cmd->HandlePreCallback(list, ActionFlags::MeshDispatch); + Unwrap6(list)->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); + if(eventId && m_Cmd->m_ActionCallback->PostDraw(eventId, list)) + { + Unwrap6(list)->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); + m_Cmd->m_ActionCallback->PostRedraw(eventId, list); + } + } + } + else + { + Unwrap6(pCommandList)->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); + + m_Cmd->AddEvent(); + + ActionDescription action; + action.dispatchDimension[0] = ThreadGroupCountX; + action.dispatchDimension[1] = ThreadGroupCountY; + action.dispatchDimension[2] = ThreadGroupCountZ; + + action.flags |= ActionFlags::MeshDispatch; + + m_Cmd->AddAction(action); + } + } + + return true; +} + void STDMETHODCALLTYPE WrappedID3D12GraphicsCommandList::DispatchMesh(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) { - RDCERR("DispatchMesh called but mesh shading is not supported!"); + SERIALISE_TIME_CALL(m_pList6->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ)); + + if(IsCaptureMode(m_State)) + { + CACHE_THREAD_SERIALISER(); + ser.SetActionChunk(); + SCOPED_SERIALISE_CHUNK(D3D12Chunk::List_DispatchMesh); + Serialise_DispatchMesh(ser, ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); + + m_ListRecord->AddChunk(scope.Get(m_ListRecord->cmdInfo->alloc)); + } } + +INSTANTIATE_FUNCTION_SERIALISED(void, WrappedID3D12GraphicsCommandList, DispatchMesh, + UINT ThreadGroupCountX, UINT ThreadGroupCountY, + UINT ThreadGroupCountZ); diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp index d29376f8a..a542aaf34 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp @@ -3753,6 +3753,37 @@ void WrappedID3D12GraphicsCommandList::FinaliseExecuteIndirectEvents(BakedCmdLis break; } + case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH: + { + D3D12_DISPATCH_MESH_ARGUMENTS *args = (D3D12_DISPATCH_MESH_ARGUMENTS *)data; + data += sizeof(D3D12_DISPATCH_MESH_ARGUMENTS); + + curAction.dispatchDimension[0] = args->ThreadGroupCountX; + curAction.dispatchDimension[1] = args->ThreadGroupCountY; + curAction.dispatchDimension[2] = args->ThreadGroupCountZ; + curAction.flags |= ActionFlags::MeshDispatch | ActionFlags::Indirect; + curAction.customName = + StringFormat::Fmt("[%u] arg%u: IndirectDispatchMesh(<%u, %u, %u>)", i, a, + curAction.dispatchDimension[0], curAction.dispatchDimension[1], + curAction.dispatchDimension[2]); + + fakeChunk->name = curAction.customName; + + structuriser.Serialise("ArgumentData"_lit, *args).Important(); + + // if this is the first action of the indirect, we could have picked up previous + // non-indirect events in this action, so the EID will be higher than we expect. Just + // assign the action's EID + eid = curAction.eventId; + + m_Cmd->AddUsage(state, actions[idx]); + + // advance + idx++; + eid++; + + break; + } case D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT: { size_t argSize = sizeof(uint32_t) * arg.Constant.Num32BitValuesToSet; @@ -4155,6 +4186,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_ExecuteIndirect( switch(arg.Type) { case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH: + case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH: case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED: case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW: { diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index a8bdf31c2..185b0a3cc 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -899,6 +899,9 @@ bool WrappedID3D12CommandQueue::ProcessChunk(ReadSerialiser &ser, D3D12Chunk chu ser, D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED); break; case D3D12Chunk::List_Barrier: ret = m_ReplayList->Serialise_Barrier(ser, 0, NULL); break; + case D3D12Chunk::List_DispatchMesh: + ret = m_ReplayList->Serialise_DispatchMesh(ser, 0, 0, 0); + break; case D3D12Chunk::PushMarker: ret = m_ReplayList->Serialise_BeginEvent(ser, 0, NULL, 0); break; case D3D12Chunk::PopMarker: ret = m_ReplayList->Serialise_EndEvent(ser); break; @@ -1761,6 +1764,7 @@ uint32_t D3D12CommandData::HandlePreCallback(ID3D12GraphicsCommandListX *list, A switch(type) { + case ActionFlags::MeshDispatch: case ActionFlags::Drawcall: { m_ActionCallback->PreDraw(eventId, list); @@ -2076,7 +2080,7 @@ void D3D12CommandData::AddUsage(const D3D12RenderState &state, D3D12ActionTreeNo uint32_t eid = a.eventId; - ActionFlags DrawMask = ActionFlags::Drawcall | ActionFlags::Dispatch; + ActionFlags DrawMask = ActionFlags::Drawcall | ActionFlags::MeshDispatch | ActionFlags::Dispatch; if(!(a.flags & DrawMask)) return; @@ -2108,11 +2112,22 @@ void D3D12CommandData::AddUsage(const D3D12RenderState &state, D3D12ActionTreeNo if(pipe && pipe->IsGraphics()) { - D3D12_SHADER_BYTECODE *srcArr[] = {&pipe->graphics->VS, &pipe->graphics->HS, - &pipe->graphics->DS, &pipe->graphics->GS, - &pipe->graphics->PS}; - for(size_t stage = 0; stage < 5; stage++) + D3D12_SHADER_BYTECODE *srcArr[] = { + &pipe->graphics->VS, + &pipe->graphics->HS, + &pipe->graphics->DS, + &pipe->graphics->GS, + &pipe->graphics->PS, + // compute + NULL, + &pipe->graphics->AS, + &pipe->graphics->MS, + }; + for(size_t stage = 0; stage < ARRAY_COUNT(srcArr); stage++) { + if(!srcArr[stage]) + continue; + WrappedID3D12Shader *sh = (WrappedID3D12Shader *)srcArr[stage]->pShaderBytecode; if(sh) @@ -2124,21 +2139,24 @@ void D3D12CommandData::AddUsage(const D3D12RenderState &state, D3D12ActionTreeNo actionNode.resourceUsage.push_back( make_rdcpair(state.ibuffer.buf, EventUsage(eid, ResourceUsage::IndexBuffer))); - for(size_t i = 0; i < state.vbuffers.size(); i++) + if(a.flags & ActionFlags::Drawcall) { - if(state.vbuffers[i].buf != ResourceId()) - actionNode.resourceUsage.push_back( - make_rdcpair(state.vbuffers[i].buf, EventUsage(eid, ResourceUsage::VertexBuffer))); - } + for(size_t i = 0; i < state.vbuffers.size(); i++) + { + if(state.vbuffers[i].buf != ResourceId()) + actionNode.resourceUsage.push_back( + make_rdcpair(state.vbuffers[i].buf, EventUsage(eid, ResourceUsage::VertexBuffer))); + } - for(size_t i = 0; i < state.streamouts.size(); i++) - { - if(state.streamouts[i].buf != ResourceId()) - actionNode.resourceUsage.push_back( - make_rdcpair(state.streamouts[i].buf, EventUsage(eid, ResourceUsage::StreamOut))); - if(state.streamouts[i].countbuf != ResourceId()) - actionNode.resourceUsage.push_back( - make_rdcpair(state.streamouts[i].countbuf, EventUsage(eid, ResourceUsage::StreamOut))); + for(size_t i = 0; i < state.streamouts.size(); i++) + { + if(state.streamouts[i].buf != ResourceId()) + actionNode.resourceUsage.push_back( + make_rdcpair(state.streamouts[i].buf, EventUsage(eid, ResourceUsage::StreamOut))); + if(state.streamouts[i].countbuf != ResourceId()) + actionNode.resourceUsage.push_back(make_rdcpair( + state.streamouts[i].countbuf, EventUsage(eid, ResourceUsage::StreamOut))); + } } rdcarray rts = state.GetRTVIDs(); diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index 1730cb50d..08b98429e 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -399,6 +399,10 @@ bool D3D12InitParams::IsSupportedVersion(uint64_t ver) if(ver == 0xF) return true; + // 0x10 -> 0x11 - Expanded PSO desc is serialised with amplification and mesh shader descs + if(ver == 0x10) + return true; + return false; } @@ -865,8 +869,8 @@ ShaderStageMask ConvertVisibility(D3D12_SHADER_VISIBILITY ShaderVisibility) case D3D12_SHADER_VISIBILITY_DOMAIN: return ShaderStageMask::Domain; case D3D12_SHADER_VISIBILITY_GEOMETRY: return ShaderStageMask::Geometry; case D3D12_SHADER_VISIBILITY_PIXEL: return ShaderStageMask::Pixel; - case D3D12_SHADER_VISIBILITY_AMPLIFICATION: - case D3D12_SHADER_VISIBILITY_MESH: + case D3D12_SHADER_VISIBILITY_AMPLIFICATION: return ShaderStageMask::Amplification; + case D3D12_SHADER_VISIBILITY_MESH: return ShaderStageMask::Mesh; default: RDCERR("Unexpected visibility %u", ShaderVisibility); break; } @@ -1263,6 +1267,8 @@ D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC::D3D12_EXPANDED_PIPELINE_STATE_STREAM_ RDCEraseEl(GS); RDCEraseEl(PS); RDCEraseEl(CS); + RDCEraseEl(AS); + RDCEraseEl(MS); NodeMask = 0; RDCEraseEl(CachedPSO); Flags = D3D12_PIPELINE_STATE_FLAG_NONE; @@ -1387,6 +1393,18 @@ D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC::D3D12_EXPANDED_PIPELINE_STATE_STREAM_ ITER_ADV(D3D12_SHADER_BYTECODE); break; } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS: + { + AS = ptr->data.shader; + ITER_ADV(D3D12_SHADER_BYTECODE); + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS: + { + MS = ptr->data.shader; + ITER_ADV(D3D12_SHADER_BYTECODE); + break; + } case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT: { StreamOutput = ptr->data.StreamOutput; @@ -1538,26 +1556,6 @@ D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC::D3D12_EXPANDED_PIPELINE_STATE_STREAM_ ITER_ADV(D3D12_VIEW_INSTANCING_DESC); break; } - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS: - { - if(ptr->data.shader.BytecodeLength > 0) - { - RDCERR("AS passed to D3D12_PIPELINE_STATE_STREAM_DESC but mesh shaders not supported"); - errored = true; - } - ITER_ADV(D3D12_SHADER_BYTECODE); - break; - } - case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS: - { - if(ptr->data.shader.BytecodeLength > 0) - { - RDCERR("MS passed to D3D12_PIPELINE_STATE_STREAM_DESC but mesh shaders not supported"); - errored = true; - } - ITER_ADV(D3D12_SHADER_BYTECODE); - break; - } default: { RDCERR("Unknown subobject type %d", obj->type); @@ -1606,6 +1604,8 @@ D3D12_PACKED_PIPELINE_STATE_STREAM_DESC &D3D12_PACKED_PIPELINE_STATE_STREAM_DESC m_GraphicsStreamData.CachedPSO = expanded.CachedPSO; m_GraphicsStreamData.Flags = expanded.Flags; m_GraphicsStreamData.ViewInstancing = expanded.ViewInstancing; + AS = expanded.AS; + MS = expanded.MS; byte *ptr = m_GraphicsStreamData.VariableVersionedData; const byte *start = ptr; @@ -1732,6 +1732,16 @@ D3D12_PACKED_PIPELINE_STATE_STREAM_DESC &D3D12_PACKED_PIPELINE_STATE_STREAM_DESC WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, desc1); } + if(expanded.AS.BytecodeLength > 0) + { + WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS, expanded.AS); + } + + if(expanded.MS.BytecodeLength > 0) + { + WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS, expanded.MS); + } + m_VariableVersionedDataLength = ptr - start; } diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index c7256b89c..215003ec2 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -567,6 +567,8 @@ struct D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC D3D12_SHADER_BYTECODE DS = {}; D3D12_SHADER_BYTECODE HS = {}; D3D12_SHADER_BYTECODE GS = {}; + D3D12_SHADER_BYTECODE AS = {}; + D3D12_SHADER_BYTECODE MS = {}; D3D12_STREAM_OUTPUT_DESC StreamOutput = {}; D3D12_BLEND_DESC BlendState = {}; UINT SampleMask = 0; @@ -630,12 +632,18 @@ public: } } - size_t GetStageCount() { return 6; } + size_t GetStageCount() { return 8; } D3D12_SHADER_BYTECODE &GetStage(size_t i) { D3D12_SHADER_BYTECODE *stages[] = { - &m_GraphicsStreamData.VS, &m_GraphicsStreamData.HS, &m_GraphicsStreamData.DS, - &m_GraphicsStreamData.GS, &m_GraphicsStreamData.PS, &m_ComputeStreamData.CS, + &m_GraphicsStreamData.VS, + &m_GraphicsStreamData.HS, + &m_GraphicsStreamData.DS, + &m_GraphicsStreamData.GS, + &m_GraphicsStreamData.PS, + &m_ComputeStreamData.CS, + &AS, + &MS, }; return *stages[i]; } @@ -694,9 +702,16 @@ private: // depth-stencil is versioned for separate stencil masks sizeof(D3D12_DEPTH_STENCIL_DESC2) + sizeof(void *) + // rasterization is versioned for line raster mode - sizeof(D3D12_RASTERIZER_DESC2) + sizeof(void *)]; + sizeof(D3D12_RASTERIZER_DESC2) + sizeof(void *) + + // AS ... + sizeof(D3D12_SHADER_BYTECODE) + sizeof(void *) + + // ... and MS are optional + sizeof(D3D12_SHADER_BYTECODE) + sizeof(void *)]; } m_GraphicsStreamData; + D3D12_SHADER_BYTECODE AS = {}; + D3D12_SHADER_BYTECODE MS = {}; + size_t m_VariableVersionedDataLength; struct @@ -885,6 +900,7 @@ DECLARE_REFLECTION_STRUCT(D3D12_WRITEBUFFERIMMEDIATE_PARAMETER); DECLARE_REFLECTION_STRUCT(D3D12_DRAW_ARGUMENTS); DECLARE_REFLECTION_STRUCT(D3D12_DRAW_INDEXED_ARGUMENTS); DECLARE_REFLECTION_STRUCT(D3D12_DISPATCH_ARGUMENTS); +DECLARE_REFLECTION_STRUCT(D3D12_DISPATCH_MESH_ARGUMENTS); DECLARE_REFLECTION_STRUCT(D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS); DECLARE_REFLECTION_STRUCT(D3D12_RENDER_PASS_BEGINNING_ACCESS); DECLARE_REFLECTION_STRUCT(D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS); @@ -1041,5 +1057,6 @@ enum class D3D12Chunk : uint32_t List_RSSetDepthBias, List_IASetIndexBufferStripCutValue, List_Barrier, + List_DispatchMesh, Max, }; diff --git a/renderdoc/driver/d3d12/d3d12_counters.cpp b/renderdoc/driver/d3d12/d3d12_counters.cpp index bbcefaea8..468a464da 100644 --- a/renderdoc/driver/d3d12/d3d12_counters.cpp +++ b/renderdoc/driver/d3d12/d3d12_counters.cpp @@ -52,6 +52,11 @@ rdcarray D3D12Replay::EnumerateCounters() ret.push_back(GPUCounter::GSInvocations); ret.push_back(GPUCounter::PSInvocations); ret.push_back(GPUCounter::CSInvocations); + if(m_pDevice->GetOpts9().MeshShaderPipelineStatsSupported) + { + ret.push_back(GPUCounter::ASInvocations); + ret.push_back(GPUCounter::MSInvocations); + } if(m_pAMDCounters) { @@ -192,6 +197,20 @@ CounterDescription D3D12Replay::DescribeCounter(GPUCounter counterID) desc.resultType = CompType::UInt; desc.unit = CounterUnit::Absolute; break; + case GPUCounter::ASInvocations: + desc.name = "AS Invocations"; + desc.description = "Number of times an amplification shader was invoked."; + desc.resultByteWidth = 8; + desc.resultType = CompType::UInt; + desc.unit = CounterUnit::Absolute; + break; + case GPUCounter::MSInvocations: + desc.name = "MS Invocations"; + desc.description = "Number of times a mesh shader was invoked."; + desc.resultByteWidth = 8; + desc.resultType = CompType::UInt; + desc.unit = CounterUnit::Absolute; + break; default: desc.name = "Unknown"; desc.description = "Unknown counter ID"; @@ -399,10 +418,11 @@ rdcarray D3D12Replay::FetchCountersAMD(const rdcarray struct D3D12GPUTimerCallback : public D3D12ActionCallback { - D3D12GPUTimerCallback(WrappedID3D12Device *dev, D3D12Replay *rp, ID3D12QueryHeap *tqh, - ID3D12QueryHeap *psqh, ID3D12QueryHeap *oqh) + D3D12GPUTimerCallback(WrappedID3D12Device *dev, D3D12Replay *rp, D3D12_QUERY_TYPE pipeQueryType, + ID3D12QueryHeap *tqh, ID3D12QueryHeap *psqh, ID3D12QueryHeap *oqh) : m_pDevice(dev), m_pReplay(rp), + m_PipeQueryType(pipeQueryType), m_TimerQueryHeap(tqh), m_PipeStatsQueryHeap(psqh), m_OcclusionQueryHeap(oqh), @@ -420,7 +440,7 @@ struct D3D12GPUTimerCallback : public D3D12ActionCallback if(cmd->GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT) { cmd->BeginQuery(m_OcclusionQueryHeap, D3D12_QUERY_TYPE_OCCLUSION, m_NumStatsQueries); - cmd->BeginQuery(m_PipeStatsQueryHeap, D3D12_QUERY_TYPE_PIPELINE_STATISTICS, m_NumStatsQueries); + cmd->BeginQuery(m_PipeStatsQueryHeap, m_PipeQueryType, m_NumStatsQueries); } cmd->EndQuery(m_TimerQueryHeap, D3D12_QUERY_TYPE_TIMESTAMP, m_NumTimestampQueries * 2 + 0); } @@ -436,7 +456,7 @@ struct D3D12GPUTimerCallback : public D3D12ActionCallback bool direct = (cmd->GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT); if(direct) { - cmd->EndQuery(m_PipeStatsQueryHeap, D3D12_QUERY_TYPE_PIPELINE_STATISTICS, m_NumStatsQueries); + cmd->EndQuery(m_PipeStatsQueryHeap, m_PipeQueryType, m_NumStatsQueries); cmd->EndQuery(m_OcclusionQueryHeap, D3D12_QUERY_TYPE_OCCLUSION, m_NumStatsQueries); m_NumStatsQueries++; @@ -483,6 +503,7 @@ struct D3D12GPUTimerCallback : public D3D12ActionCallback WrappedID3D12Device *m_pDevice; D3D12Replay *m_pReplay; + D3D12_QUERY_TYPE m_PipeQueryType; ID3D12QueryHeap *m_TimerQueryHeap; ID3D12QueryHeap *m_PipeStatsQueryHeap; ID3D12QueryHeap *m_OcclusionQueryHeap; @@ -556,7 +577,7 @@ rdcarray D3D12Replay::FetchCounters(const rdcarray &c D3D12_RESOURCE_DESC bufDesc; bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; bufDesc.Alignment = 0; - bufDesc.Width = (sizeof(uint64_t) * 3 + sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS)) * maxEID; + bufDesc.Width = (sizeof(uint64_t) * 3 + sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS1)) * maxEID; bufDesc.Height = 1; bufDesc.DepthOrArraySize = 1; bufDesc.MipLevels = 1; @@ -595,6 +616,17 @@ rdcarray D3D12Replay::FetchCounters(const rdcarray &c pipestatsQueryDesc.Count = maxEID; pipestatsQueryDesc.NodeMask = 1; pipestatsQueryDesc.Type = D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS; + D3D12_QUERY_TYPE pipeQueryType = D3D12_QUERY_TYPE_PIPELINE_STATISTICS; + + const bool meshQueries = d3dCounters.contains(GPUCounter::ASInvocations) || + d3dCounters.contains(GPUCounter::MSInvocations); + + if(meshQueries) + { + pipestatsQueryDesc.Type = D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS1; + pipeQueryType = D3D12_QUERY_TYPE_PIPELINE_STATISTICS1; + } + ID3D12QueryHeap *pipestatsQueryHeap = NULL; hr = m_pDevice->CreateQueryHeap(&pipestatsQueryDesc, __uuidof(pipestatsQueryHeap), (void **)&pipestatsQueryHeap); @@ -632,7 +664,8 @@ rdcarray D3D12Replay::FetchCounters(const rdcarray &c return ret; } - D3D12GPUTimerCallback cb(m_pDevice, this, timerQueryHeap, pipestatsQueryHeap, occlusionQueryHeap); + D3D12GPUTimerCallback cb(m_pDevice, this, pipeQueryType, timerQueryHeap, pipestatsQueryHeap, + occlusionQueryHeap); // replay the events to perform all the queries m_pDevice->ReplayLog(0, maxEID, eReplay_Full); @@ -658,10 +691,13 @@ rdcarray D3D12Replay::FetchCounters(const rdcarray &c bufferOffset += sizeof(uint64_t) * 2 * cb.m_NumTimestampQueries; - list->ResolveQueryData(pipestatsQueryHeap, D3D12_QUERY_TYPE_PIPELINE_STATISTICS, 0, - cb.m_NumStatsQueries, readbackBuf, bufferOffset); + list->ResolveQueryData(pipestatsQueryHeap, pipeQueryType, 0, cb.m_NumStatsQueries, readbackBuf, + bufferOffset); - bufferOffset += sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) * cb.m_NumStatsQueries; + if(meshQueries) + bufferOffset += sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS1) * cb.m_NumStatsQueries; + else + bufferOffset += sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) * cb.m_NumStatsQueries; list->ResolveQueryData(occlusionQueryHeap, D3D12_QUERY_TYPE_OCCLUSION, 0, cb.m_NumStatsQueries, readbackBuf, bufferOffset); @@ -692,7 +728,12 @@ rdcarray D3D12Replay::FetchCounters(const rdcarray &c uint64_t *timestamps = (uint64_t *)data; data += cb.m_NumTimestampQueries * 2 * sizeof(uint64_t); D3D12_QUERY_DATA_PIPELINE_STATISTICS *pipelinestats = (D3D12_QUERY_DATA_PIPELINE_STATISTICS *)data; - data += cb.m_NumStatsQueries * sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS); + D3D12_QUERY_DATA_PIPELINE_STATISTICS1 *pipelinestats1 = + (D3D12_QUERY_DATA_PIPELINE_STATISTICS1 *)data; + if(meshQueries) + data += cb.m_NumStatsQueries * sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS1); + else + data += cb.m_NumStatsQueries * sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS); uint64_t *occlusion = (uint64_t *)data; uint64_t freq; @@ -703,15 +744,25 @@ rdcarray D3D12Replay::FetchCounters(const rdcarray &c bool direct = cb.m_Results[i].second; D3D12_QUERY_DATA_PIPELINE_STATISTICS pipeStats = {}; + D3D12_QUERY_DATA_PIPELINE_STATISTICS1 pipeStats1 = {}; uint64_t occl = 0; // only events on direct lists recorded pipeline stats or occlusion queries if(direct) { - pipeStats = *pipelinestats; + if(meshQueries) + { + pipeStats1 = *pipelinestats1; + memcpy(&pipeStats, &pipeStats1, sizeof(pipeStats)); + } + else + { + pipeStats = *pipelinestats; + } occl = *occlusion; pipelinestats++; + pipelinestats1++; occlusion++; } @@ -742,6 +793,8 @@ rdcarray D3D12Replay::FetchCounters(const rdcarray &c case GPUCounter::GSInvocations: result.value.u64 = pipeStats.GSInvocations; break; case GPUCounter::PSInvocations: result.value.u64 = pipeStats.PSInvocations; break; case GPUCounter::CSInvocations: result.value.u64 = pipeStats.CSInvocations; break; + case GPUCounter::ASInvocations: result.value.u64 = pipeStats1.ASInvocations; break; + case GPUCounter::MSInvocations: result.value.u64 = pipeStats1.MSInvocations; break; default: break; } diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index faea56465..77aba239b 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -965,6 +965,11 @@ rdcpair D3D12DebugManager::PatchExecuteIndirect( offset += sizeof(D3D12_DISPATCH_ARGUMENTS); break; } + case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH: + { + offset += sizeof(D3D12_DISPATCH_MESH_ARGUMENTS); + break; + } case D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT: { offset += sizeof(uint32_t) * arg.Constant.Num32BitValuesToSet; diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index fead16aa4..d1ca23dbf 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -527,6 +527,8 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara RDCEraseEl(m_D3D12Opts2); RDCEraseEl(m_D3D12Opts3); RDCEraseEl(m_D3D12Opts6); + RDCEraseEl(m_D3D12Opts7); + RDCEraseEl(m_D3D12Opts9); RDCEraseEl(m_D3D12Opts12); RDCEraseEl(m_D3D12Opts14); RDCEraseEl(m_D3D12Opts15); @@ -597,6 +599,14 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara sizeof(m_D3D12Opts6)); if(hr != S_OK) RDCEraseEl(m_D3D12Opts6); + hr = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &m_D3D12Opts7, + sizeof(m_D3D12Opts7)); + if(hr != S_OK) + RDCEraseEl(m_D3D12Opts7); + hr = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS9, &m_D3D12Opts9, + sizeof(m_D3D12Opts9)); + if(hr != S_OK) + RDCEraseEl(m_D3D12Opts9); hr = m_pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &m_D3D12Opts12, sizeof(m_D3D12Opts12)); if(hr != S_OK) @@ -3121,6 +3131,10 @@ HRESULT WrappedID3D12Device::CreatePipeState(D3D12_EXPANDED_PIPELINE_STATE_STREA graphicsDesc.BlendState = desc.BlendState; graphicsDesc.SampleMask = desc.SampleMask; + // can't create mesh shaders with old function, so we should not be trying + RDCASSERT(desc.AS.BytecodeLength == 0); + RDCASSERT(desc.MS.BytecodeLength == 0); + // graphicsDesc.RasterizerState = desc.RasterizerState; { graphicsDesc.RasterizerState.FillMode = desc.RasterizerState.FillMode; @@ -4296,6 +4310,7 @@ bool WrappedID3D12Device::ProcessChunk(ReadSerialiser &ser, D3D12Chunk context) case D3D12Chunk::List_RSSetDepthBias: case D3D12Chunk::List_IASetIndexBufferStripCutValue: case D3D12Chunk::List_Barrier: + case D3D12Chunk::List_DispatchMesh: RDCERR("Unexpected chunk while processing initialisation: %s", ToStr(context).c_str()); return false; diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index cc5812dcf..058e41d01 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -54,7 +54,7 @@ struct D3D12InitParams UINT SDKVersion = 0; // check if a frame capture section version is supported - static const uint64_t CurrentVersion = 0x10; + static const uint64_t CurrentVersion = 0x11; static bool IsSupportedVersion(uint64_t ver); }; @@ -790,6 +790,8 @@ private: D3D12_FEATURE_DATA_D3D12_OPTIONS2 m_D3D12Opts2; D3D12_FEATURE_DATA_D3D12_OPTIONS3 m_D3D12Opts3; D3D12_FEATURE_DATA_D3D12_OPTIONS6 m_D3D12Opts6; + D3D12_FEATURE_DATA_D3D12_OPTIONS7 m_D3D12Opts7; + D3D12_FEATURE_DATA_D3D12_OPTIONS9 m_D3D12Opts9; D3D12_FEATURE_DATA_D3D12_OPTIONS12 m_D3D12Opts12; D3D12_FEATURE_DATA_D3D12_OPTIONS14 m_D3D12Opts14; D3D12_FEATURE_DATA_D3D12_OPTIONS15 m_D3D12Opts15; @@ -825,6 +827,8 @@ public: const D3D12_FEATURE_DATA_D3D12_OPTIONS2 &GetOpts2() { return m_D3D12Opts2; } const D3D12_FEATURE_DATA_D3D12_OPTIONS3 &GetOpts3() { return m_D3D12Opts3; } const D3D12_FEATURE_DATA_D3D12_OPTIONS6 &GetOpts6() { return m_D3D12Opts6; } + const D3D12_FEATURE_DATA_D3D12_OPTIONS7 &GetOpts7() { return m_D3D12Opts7; } + const D3D12_FEATURE_DATA_D3D12_OPTIONS9 &GetOpts9() { return m_D3D12Opts9; } const D3D12_FEATURE_DATA_D3D12_OPTIONS12 &GetOpts12() { return m_D3D12Opts12; } const D3D12_FEATURE_DATA_D3D12_OPTIONS14 &GetOpts14() { return m_D3D12Opts14; } const D3D12_FEATURE_DATA_D3D12_OPTIONS15 &GetOpts15() { return m_D3D12Opts15; } diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp index 2eea82663..f68a241ee 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp @@ -634,7 +634,8 @@ void WrappedID3D12Device::ProcessCreatedGraphicsPSO(ID3D12PipelineState *real, D3D12_SHADER_BYTECODE *shaders[] = { &wrapped->graphics->VS, &wrapped->graphics->HS, &wrapped->graphics->DS, - &wrapped->graphics->GS, &wrapped->graphics->PS, + &wrapped->graphics->GS, &wrapped->graphics->PS, &wrapped->graphics->AS, + &wrapped->graphics->MS, }; for(size_t i = 0; i < ARRAY_COUNT(shaders); i++) @@ -1799,6 +1800,11 @@ bool WrappedID3D12Device::Serialise_CreateCommandSignature(SerialiserType &ser, wrapped->sig.graphics = false; break; } + case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH: + { + wrapped->sig.PackedByteSize += sizeof(D3D12_DISPATCH_MESH_ARGUMENTS); + break; + } case D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT: { wrapped->sig.PackedByteSize += @@ -2327,8 +2333,7 @@ HRESULT WrappedID3D12Device::CheckFeatureSupport(D3D12_FEATURE Feature, void *pF if(FeatureSupportDataSize != sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)) return E_INVALIDARG; - // don't support mesh shading or sampler feedback - opts->MeshShaderTier = D3D12_MESH_SHADER_TIER_NOT_SUPPORTED; + // don't support sampler feedback opts->SamplerFeedbackTier = D3D12_SAMPLER_FEEDBACK_TIER_NOT_SUPPORTED; if(dolog) diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap2.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap2.cpp index 9fcfd7276..134234dd9 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap2.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap2.cpp @@ -64,6 +64,8 @@ bool WrappedID3D12Device::Serialise_CreatePipelineState(SerialiserType &ser, if(!DXBC::DXBCContainer::IsHashedContainer(sh.pShaderBytecode, sh.BytecodeLength)) DXBC::DXBCContainer::HashContainer((void *)sh.pShaderBytecode, sh.BytecodeLength); + if(DXBC::DXBCContainer::CheckForDXIL(sh.pShaderBytecode, sh.BytecodeLength)) + m_UsedDXIL = true; } if(m_pDevice2) @@ -93,8 +95,8 @@ bool WrappedID3D12Device::Serialise_CreatePipelineState(SerialiserType &ser, new D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC(Descriptor); D3D12_SHADER_BYTECODE *shaders[] = { - &storedDesc->VS, &storedDesc->HS, &storedDesc->DS, - &storedDesc->GS, &storedDesc->PS, &storedDesc->CS, + &storedDesc->VS, &storedDesc->HS, &storedDesc->DS, &storedDesc->GS, + &storedDesc->PS, &storedDesc->CS, &storedDesc->AS, &storedDesc->MS, }; AddResource(pPipelineState, ResourceType::PipelineState, "Pipeline State"); @@ -246,7 +248,9 @@ HRESULT WrappedID3D12Device::CreatePipelineState(const D3D12_PIPELINE_STATE_STRE UsesExtensionUAV(expandedDesc.DS, reg, space) || UsesExtensionUAV(expandedDesc.GS, reg, space) || UsesExtensionUAV(expandedDesc.PS, reg, space) || - UsesExtensionUAV(expandedDesc.CS, reg, space)) + UsesExtensionUAV(expandedDesc.CS, reg, space) || + UsesExtensionUAV(expandedDesc.AS, reg, space) || + UsesExtensionUAV(expandedDesc.MS, reg, space)) { // don't set initparams until we've seen at least one shader actually created using the // extensions. @@ -260,6 +264,17 @@ HRESULT WrappedID3D12Device::CreatePipelineState(const D3D12_PIPELINE_STATE_STRE } } + for(const D3D12_SHADER_BYTECODE &sh : + {expandedDesc.VS, expandedDesc.HS, expandedDesc.DS, expandedDesc.GS, expandedDesc.PS, + expandedDesc.CS, expandedDesc.AS, expandedDesc.MS}) + { + if(sh.BytecodeLength == 0 || sh.pShaderBytecode == NULL) + continue; + + if(DXBC::DXBCContainer::CheckForDXIL(sh.pShaderBytecode, sh.BytecodeLength)) + m_UsedDXIL = true; + } + SCOPED_SERIALISE_CHUNK(D3D12Chunk::Device_CreatePipelineState); Serialise_CreatePipelineState(ser, pDesc, riid, (void **)&wrapped); @@ -283,8 +298,8 @@ HRESULT WrappedID3D12Device::CreatePipelineState(const D3D12_PIPELINE_STATE_STRE new D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC(expandedDesc); D3D12_SHADER_BYTECODE *shaders[] = { - &storedDesc->VS, &storedDesc->HS, &storedDesc->DS, - &storedDesc->GS, &storedDesc->PS, &storedDesc->CS, + &storedDesc->VS, &storedDesc->HS, &storedDesc->DS, &storedDesc->GS, + &storedDesc->PS, &storedDesc->CS, &storedDesc->AS, &storedDesc->MS, }; for(size_t i = 0; i < ARRAY_COUNT(shaders); i++) diff --git a/renderdoc/driver/d3d12/d3d12_overlay.cpp b/renderdoc/driver/d3d12/d3d12_overlay.cpp index 469dd80f5..c74356019 100644 --- a/renderdoc/driver/d3d12/d3d12_overlay.cpp +++ b/renderdoc/driver/d3d12/d3d12_overlay.cpp @@ -150,6 +150,7 @@ struct D3D12QuadOverdrawCallback : public D3D12ActionCallback pipeDesc.SampleDesc.Quality = 0; bool dxil = + pipeDesc.MS.BytecodeLength > 0 || DXBC::DXBCContainer::CheckForDXIL(pipeDesc.VS.pShaderBytecode, pipeDesc.VS.BytecodeLength); // dxil is stricter about pipeline signatures matching. On D3D11 there's an error but all @@ -345,6 +346,8 @@ void D3D12Replay::PatchQuadWritePS(D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &pi rastFeeding = &pipeDesc.DS; if(pipeDesc.GS.BytecodeLength > 0) rastFeeding = &pipeDesc.GS; + if(pipeDesc.MS.BytecodeLength > 0) + rastFeeding = &pipeDesc.MS; uint32_t hash[4]; DXBC::DXBCContainer::GetHash(hash, rastFeeding->pShaderBytecode, rastFeeding->BytecodeLength); @@ -1170,6 +1173,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De pipe->Fill(psoDesc); bool dxil = + psoDesc.MS.BytecodeLength > 0 || DXBC::DXBCContainer::CheckForDXIL(psoDesc.VS.pShaderBytecode, psoDesc.VS.BytecodeLength); ID3DBlob *ps = @@ -1259,6 +1263,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De BOOL origFrontCCW = psoDesc.RasterizerState.FrontCounterClockwise; bool dxil = + psoDesc.MS.BytecodeLength > 0 || DXBC::DXBCContainer::CheckForDXIL(psoDesc.VS.pShaderBytecode, psoDesc.VS.BytecodeLength); ID3DBlob *red = m_pDevice->GetShaderCache()->MakeFixedColShader(D3D12ShaderCache::RED, dxil); @@ -1367,6 +1372,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De pipe->Fill(psoDesc); bool dxil = + psoDesc.MS.BytecodeLength > 0 || DXBC::DXBCContainer::CheckForDXIL(psoDesc.VS.pShaderBytecode, psoDesc.VS.BytecodeLength); ID3DBlob *ps = @@ -1522,6 +1528,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De pipe->Fill(psoDesc); bool dxil = + psoDesc.MS.BytecodeLength > 0 || DXBC::DXBCContainer::CheckForDXIL(psoDesc.VS.pShaderBytecode, psoDesc.VS.BytecodeLength); ID3DBlob *red = m_pDevice->GetShaderCache()->MakeFixedColShader(D3D12ShaderCache::RED, dxil); @@ -1706,7 +1713,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De const ActionDescription *action = m_pDevice->GetAction(events[0]); // remove any non-drawcalls, like the pass boundary. - if(!(action->flags & ActionFlags::Drawcall)) + if(!(action->flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall))) events.erase(0); else break; @@ -1758,6 +1765,8 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De pipeDesc.VS.pShaderBytecode = m_Overlay.MeshVS->GetBufferPointer(); RDCEraseEl(pipeDesc.HS); RDCEraseEl(pipeDesc.DS); + RDCEraseEl(pipeDesc.AS); + RDCEraseEl(pipeDesc.MS); pipeDesc.GS.BytecodeLength = m_Overlay.TriangleSizeGS->GetBufferSize(); pipeDesc.GS.pShaderBytecode = m_Overlay.TriangleSizeGS->GetBufferPointer(); pipeDesc.PS.BytecodeLength = m_Overlay.TriangleSizePS->GetBufferSize(); @@ -2231,6 +2240,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De pipe->Fill(psoDesc); bool dxil = + psoDesc.MS.BytecodeLength > 0 || DXBC::DXBCContainer::CheckForDXIL(psoDesc.VS.pShaderBytecode, psoDesc.VS.BytecodeLength); ID3DBlob *red = m_pDevice->GetShaderCache()->MakeFixedColShader(D3D12ShaderCache::RED, dxil); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index eeebb25a7..b70a8b3ef 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -624,6 +624,8 @@ rdcstr D3D12Replay::DisassembleShader(ResourceId pipeline, const ShaderReflectio case ShaderStage::Geometry: search = "stage=\"GS\""; break; case ShaderStage::Pixel: search = "stage=\"PS\""; break; case ShaderStage::Compute: search = "stage=\"CS\""; break; + case ShaderStage::Amplification: search = "stage=\"AS\""; break; + case ShaderStage::Mesh: search = "stage=\"MS\""; break; default: return "; Unknown shader stage in shader reflection\n"; } @@ -1030,12 +1032,14 @@ ShaderStageMask ToShaderStageMask(D3D12_SHADER_VISIBILITY vis) case D3D12_SHADER_VISIBILITY_DOMAIN: return ShaderStageMask::Domain; case D3D12_SHADER_VISIBILITY_GEOMETRY: return ShaderStageMask::Geometry; case D3D12_SHADER_VISIBILITY_PIXEL: return ShaderStageMask::Pixel; + case D3D12_SHADER_VISIBILITY_AMPLIFICATION: return ShaderStageMask::Amplification; + case D3D12_SHADER_VISIBILITY_MESH: return ShaderStageMask::Mesh; default: return ShaderStageMask::Unknown; } } void D3D12Replay::FillRootElements(uint32_t eventId, const D3D12RenderState::RootSignature &rootSig, - const ShaderBindpointMapping *mappings[(uint32_t)ShaderStage::Count], + const ShaderBindpointMapping *mappings[NumShaderStages], rdcarray &rootElements) { if(rootSig.rootsig == ResourceId()) @@ -1730,14 +1734,35 @@ void D3D12Replay::SavePipelineState(uint32_t eventId) } else if(pipe) { - D3D12Pipe::Shader *dstArr[] = {&state.vertexShader, &state.hullShader, &state.domainShader, - &state.geometryShader, &state.pixelShader}; + D3D12Pipe::Shader *dstArr[] = { + &state.vertexShader, + &state.hullShader, + &state.domainShader, + &state.geometryShader, + &state.pixelShader, + // compute + NULL, + &state.ampShader, + &state.meshShader, + }; - D3D12_SHADER_BYTECODE *srcArr[] = {&pipe->graphics->VS, &pipe->graphics->HS, &pipe->graphics->DS, - &pipe->graphics->GS, &pipe->graphics->PS}; + D3D12_SHADER_BYTECODE *srcArr[] = { + &pipe->graphics->VS, + &pipe->graphics->HS, + &pipe->graphics->DS, + &pipe->graphics->GS, + &pipe->graphics->PS, + // compute + NULL, + &pipe->graphics->AS, + &pipe->graphics->MS, + }; - for(size_t stage = 0; stage < 5; stage++) + for(size_t stage = 0; stage < ARRAY_COUNT(dstArr); stage++) { + if(!dstArr[stage]) + continue; + D3D12Pipe::Shader &dst = *dstArr[stage]; D3D12_SHADER_BYTECODE &src = *srcArr[stage]; @@ -1764,13 +1789,15 @@ void D3D12Replay::SavePipelineState(uint32_t eventId) // Root Signature ///////////////////////////////////////////////// { - const ShaderBindpointMapping *mappings[(uint32_t)ShaderStage::Count]; + const ShaderBindpointMapping *mappings[NumShaderStages]; 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; + mappings[(uint32_t)ShaderStage::Amplification] = &state.ampShader.bindpointMapping; + mappings[(uint32_t)ShaderStage::Mesh] = &state.meshShader.bindpointMapping; if(pipe && pipe->IsCompute()) { @@ -3211,7 +3238,7 @@ rdcarray D3D12Replay::GetPassEvents(uint32_t eventId) // so we don't actually do anything (init postvs/action overlay) // but it's useful to have the first part of the pass as part // of the list - if(start->flags & (ActionFlags::Drawcall | ActionFlags::PassBoundary)) + if(start->flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall | ActionFlags::PassBoundary)) passEvents.push_back(start->eventId); start = start->next; @@ -3362,6 +3389,8 @@ void D3D12Replay::BuildShader(ShaderEncoding sourceEncoding, const bytebuf &sour case ShaderStage::Geometry: profile = "gs_5_1"; break; case ShaderStage::Pixel: profile = "ps_5_1"; break; case ShaderStage::Compute: profile = "cs_5_1"; break; + case ShaderStage::Amplification: profile = "as_6_5"; break; + case ShaderStage::Mesh: profile = "ms_6_5"; break; default: RDCERR("Unexpected type in BuildShader!"); id = ResourceId(); @@ -3488,7 +3517,7 @@ void D3D12Replay::RefreshDerivedReplacements() if(pipe->IsGraphics()) { - ResourceId shaders[5]; + ResourceId shaders[NumShaderStages]; if(pipe->VS()) shaders[0] = rm->GetOriginalID(pipe->VS()->GetResourceID()); @@ -3500,6 +3529,10 @@ void D3D12Replay::RefreshDerivedReplacements() shaders[3] = rm->GetOriginalID(pipe->GS()->GetResourceID()); if(pipe->PS()) shaders[4] = rm->GetOriginalID(pipe->PS()->GetResourceID()); + if(pipe->AS()) + shaders[6] = rm->GetOriginalID(pipe->AS()->GetResourceID()); + if(pipe->MS()) + shaders[7] = rm->GetOriginalID(pipe->MS()->GetResourceID()); for(size_t i = 0; i < ARRAY_COUNT(shaders); i++) { @@ -3526,7 +3559,7 @@ void D3D12Replay::RefreshDerivedReplacements() D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC desc = *pipe->graphics; D3D12_SHADER_BYTECODE *shaders[] = { - &desc.VS, &desc.HS, &desc.DS, &desc.GS, &desc.PS, + &desc.VS, &desc.HS, &desc.DS, &desc.GS, &desc.PS, &desc.AS, &desc.MS, }; for(size_t s = 0; s < ARRAY_COUNT(shaders); s++) diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 347e803dd..aaab224e7 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -261,7 +261,7 @@ public: private: void FillRootElements(uint32_t eventId, const D3D12RenderState::RootSignature &rootSig, - const ShaderBindpointMapping *mappings[(uint32_t)ShaderStage::Count], + const ShaderBindpointMapping *mappings[NumShaderStages], rdcarray &rootElements); void FillResourceView(D3D12Pipe::View &view, const D3D12Descriptor *desc); void FillSampler(D3D12Pipe::Sampler &view, const D3D12_SAMPLER_DESC2 &desc); diff --git a/renderdoc/driver/d3d12/d3d12_resources.h b/renderdoc/driver/d3d12/d3d12_resources.h index 6692b9faa..373d163eb 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.h +++ b/renderdoc/driver/d3d12/d3d12_resources.h @@ -641,6 +641,10 @@ public: desc.GS = GS()->GetDesc(); if(PS()) desc.PS = PS()->GetDesc(); + if(AS()) + desc.AS = AS()->GetDesc(); + if(MS()) + desc.MS = MS()->GetDesc(); } else { @@ -854,6 +858,8 @@ public: ShaderEntry *DS() { return (ShaderEntry *)graphics->DS.pShaderBytecode; } ShaderEntry *GS() { return (ShaderEntry *)graphics->GS.pShaderBytecode; } ShaderEntry *PS() { return (ShaderEntry *)graphics->PS.pShaderBytecode; } + ShaderEntry *AS() { return (ShaderEntry *)graphics->AS.pShaderBytecode; } + ShaderEntry *MS() { return (ShaderEntry *)graphics->MS.pShaderBytecode; } ShaderEntry *CS() { return (ShaderEntry *)compute->CS.pShaderBytecode; } WrappedID3D12PipelineState(ID3D12PipelineState *real, WrappedID3D12Device *device) : WrappedDeviceChild12(real, device) @@ -875,6 +881,8 @@ public: ShaderEntry::ReleaseShader(DS()); ShaderEntry::ReleaseShader(GS()); ShaderEntry::ReleaseShader(PS()); + ShaderEntry::ReleaseShader(AS()); + ShaderEntry::ReleaseShader(MS()); SAFE_DELETE_ARRAY(graphics->InputLayout.pInputElementDescs); SAFE_DELETE_ARRAY(graphics->StreamOutput.pSODeclaration); diff --git a/renderdoc/driver/d3d12/d3d12_sdk_select.cpp b/renderdoc/driver/d3d12/d3d12_sdk_select.cpp index fcdff72fc..95e197a0b 100644 --- a/renderdoc/driver/d3d12/d3d12_sdk_select.cpp +++ b/renderdoc/driver/d3d12/d3d12_sdk_select.cpp @@ -394,7 +394,9 @@ void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, byteb // similarly, if the system version is enough then the user didn't use a new runtime (or they used // what was at the time a new runtime but is now available in the system...), so also abort. // That means we'll only do the interception & patching when we think it's really needed. - if(SDKVersion <= SystemCoreVersion) + // The only exception is if the user has configured a force override, in which case we always use + // it. + if(SDKVersion <= SystemCoreVersion && D3D12_D3D12CoreDirPath().empty()) return; // finally we're at a point where we will hook to force the library we want. diff --git a/renderdoc/driver/d3d12/d3d12_serialise.cpp b/renderdoc/driver/d3d12/d3d12_serialise.cpp index 32cef7b5e..cc5c659a4 100644 --- a/renderdoc/driver/d3d12/d3d12_serialise.cpp +++ b/renderdoc/driver/d3d12/d3d12_serialise.cpp @@ -503,6 +503,13 @@ void DoSerialise(SerialiserType &ser, D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC SERIALISE_MEMBER(DS); SERIALISE_MEMBER(HS); SERIALISE_MEMBER(GS); + + if(ser.VersionAtLeast(0x11)) + { + SERIALISE_MEMBER(AS); + SERIALISE_MEMBER(MS); + } + SERIALISE_MEMBER(StreamOutput); SERIALISE_MEMBER(BlendState); SERIALISE_MEMBER(SampleMask); @@ -557,6 +564,8 @@ void Deserialise(const D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &el) FreeAlignedBuffer((byte *)(el.DS.pShaderBytecode)); FreeAlignedBuffer((byte *)(el.HS.pShaderBytecode)); FreeAlignedBuffer((byte *)(el.GS.pShaderBytecode)); + FreeAlignedBuffer((byte *)(el.AS.pShaderBytecode)); + FreeAlignedBuffer((byte *)(el.MS.pShaderBytecode)); FreeAlignedBuffer((byte *)(el.CS.pShaderBytecode)); } @@ -818,6 +827,7 @@ void DoSerialise(SerialiserType &ser, D3D12_INDIRECT_ARGUMENT_DESC &el) case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW: case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED: case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH: + case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH: case D3D12_INDIRECT_ARGUMENT_TYPE_INDEX_BUFFER_VIEW: // nothing to serialise break; @@ -1718,6 +1728,14 @@ void DoSerialise(SerialiserType &ser, D3D12_DISPATCH_ARGUMENTS &el) SERIALISE_MEMBER(ThreadGroupCountZ).Important(); } +template +void DoSerialise(SerialiserType &ser, D3D12_DISPATCH_MESH_ARGUMENTS &el) +{ + SERIALISE_MEMBER(ThreadGroupCountX).Important(); + SERIALISE_MEMBER(ThreadGroupCountY).Important(); + SERIALISE_MEMBER(ThreadGroupCountZ).Important(); +} + template void DoSerialise(SerialiserType &ser, D3D12ResourceLayout &el) { @@ -1881,3 +1899,4 @@ INSTANTIATE_SERIALISE_TYPE(D3D12ResourceLayout); INSTANTIATE_SERIALISE_TYPE(D3D12_DRAW_ARGUMENTS); INSTANTIATE_SERIALISE_TYPE(D3D12_DRAW_INDEXED_ARGUMENTS); INSTANTIATE_SERIALISE_TYPE(D3D12_DISPATCH_ARGUMENTS); +INSTANTIATE_SERIALISE_TYPE(D3D12_DISPATCH_MESH_ARGUMENTS); diff --git a/renderdoc/driver/d3d12/d3d12_shader_feedback.cpp b/renderdoc/driver/d3d12/d3d12_shader_feedback.cpp index 7c9fe9ea6..4fbdb1950 100644 --- a/renderdoc/driver/d3d12/d3d12_shader_feedback.cpp +++ b/renderdoc/driver/d3d12/d3d12_shader_feedback.cpp @@ -1103,7 +1103,8 @@ bool D3D12Replay::FetchShaderFeedback(uint32_t eventId) const ActionDescription *action = m_pDevice->GetAction(eventId); - if(action == NULL || !(action->flags & (ActionFlags::Dispatch | ActionFlags::Drawcall))) + if(action == NULL || + !(action->flags & (ActionFlags::Dispatch | ActionFlags::MeshDispatch | ActionFlags::Drawcall))) { // deliberately show no bindings as used for non-draws result.valid = true; @@ -1207,6 +1208,12 @@ bool D3D12Replay::FetchShaderFeedback(uint32_t eventId) dynamicAccessPerStage[4] = AddArraySlots( pipe->PS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Pixel], numSlots, editedBlob[uint32_t(ShaderStage::Pixel)], pipeDesc.PS, directHeapAccess); + dynamicAccessPerStage[6] = AddArraySlots( + pipe->AS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Amplification], numSlots, + editedBlob[uint32_t(ShaderStage::Amplification)], pipeDesc.AS, directHeapAccess); + dynamicAccessPerStage[7] = AddArraySlots( + pipe->MS(), space, maxDescriptors, slots[(uint32_t)ShaderStage::Mesh], numSlots, + editedBlob[uint32_t(ShaderStage::Mesh)], pipeDesc.MS, directHeapAccess); } // if numSlots wasn't increased, none of the resources were arrayed so we have nothing to do. @@ -1453,6 +1460,10 @@ bool D3D12Replay::FetchShaderFeedback(uint32_t eventId) visMask = (uint32_t)ShaderStageMask::Geometry; break; case D3D12_SHADER_VISIBILITY_PIXEL: visMask = uint32_t(ShaderStageMask::Pixel); break; + case D3D12_SHADER_VISIBILITY_AMPLIFICATION: + visMask = uint32_t(ShaderStageMask::Amplification); + break; + case D3D12_SHADER_VISIBILITY_MESH: visMask = uint32_t(ShaderStageMask::Mesh); break; default: RDCERR("Unexpected shader visibility %d", p.ShaderVisibility); return true; } diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index f7c18dafa..e7b10accb 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -60,6 +60,13 @@ static bool IsShaderParameterVisible(DXBC::ShaderType shaderType, if(shaderType == DXBC::ShaderType::Pixel && shaderVisibility == D3D12_SHADER_VISIBILITY_PIXEL) return true; + if(shaderType == DXBC::ShaderType::Amplification && + shaderVisibility == D3D12_SHADER_VISIBILITY_AMPLIFICATION) + return true; + + if(shaderType == DXBC::ShaderType::Mesh && shaderVisibility == D3D12_SHADER_VISIBILITY_MESH) + return true; + return false; } diff --git a/renderdoc/driver/d3d12/d3d12_state.cpp b/renderdoc/driver/d3d12/d3d12_state.cpp index 8286dd621..e455e527a 100644 --- a/renderdoc/driver/d3d12/d3d12_state.cpp +++ b/renderdoc/driver/d3d12/d3d12_state.cpp @@ -91,7 +91,8 @@ void D3D12RenderState::ResolvePendingIndirectState(WrappedID3D12Device *device) { case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW: case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED: - case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH: break; + case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH: + case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH: break; case D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT: { size_t argSize = sizeof(uint32_t) * arg.Constant.Num32BitValuesToSet; diff --git a/renderdoc/driver/d3d12/d3d12_stringise.cpp b/renderdoc/driver/d3d12/d3d12_stringise.cpp index c4b72f094..a70a50abf 100644 --- a/renderdoc/driver/d3d12/d3d12_stringise.cpp +++ b/renderdoc/driver/d3d12/d3d12_stringise.cpp @@ -28,7 +28,7 @@ template <> rdcstr DoStringise(const D3D12Chunk &el) { - RDCCOMPILE_ASSERT((uint32_t)D3D12Chunk::Max == 1123, "Chunks changed without updating names"); + RDCCOMPILE_ASSERT((uint32_t)D3D12Chunk::Max == 1124, "Chunks changed without updating names"); BEGIN_ENUM_STRINGISE(D3D12Chunk) { @@ -220,6 +220,7 @@ rdcstr DoStringise(const D3D12Chunk &el) STRINGISE_ENUM_CLASS_NAMED(List_IASetIndexBufferStripCutValue, "ID3D12GraphicsCommandList9::IASetIndexBufferStripCutValue"); STRINGISE_ENUM_CLASS_NAMED(List_Barrier, "ID3D12GraphicsCommandList7::Barrier"); + STRINGISE_ENUM_CLASS_NAMED(List_DispatchMesh, "ID3D12GraphicsCommandList6::DispatchMesh"); STRINGISE_ENUM_CLASS_NAMED(Max, "Max Chunk"); } END_ENUM_STRINGISE() @@ -732,6 +733,7 @@ rdcstr DoStringise(const D3D12_INDIRECT_ARGUMENT_TYPE &el) STRINGISE_ENUM(D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW) STRINGISE_ENUM(D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW) STRINGISE_ENUM(D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW) + STRINGISE_ENUM(D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH) } END_ENUM_STRINGISE(); }