diff --git a/qrenderdoc/Widgets/Extended/RDTreeView.cpp b/qrenderdoc/Widgets/Extended/RDTreeView.cpp index a3f9a7482..cef17ef06 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeView.cpp +++ b/qrenderdoc/Widgets/Extended/RDTreeView.cpp @@ -270,21 +270,24 @@ void RDTreeView::contextMenuEvent(QContextMenuEvent *event) QObject::connect(&collapseAllAction, &QAction::triggered, [this, index]() { collapseAll(index); }); - QObject::connect(©, &QAction::triggered, [this, index, pos]() { - bool clearsel = false; - if(selectionModel()->selectedRows().empty()) - { - setSelection(QRect(pos, QSize(1, 1)), selectionCommand(index)); - clearsel = true; - } - copySelection(); - if(clearsel) - selectionModel()->clear(); - }); + QObject::connect(©, &QAction::triggered, [this, index, pos]() { copyIndex(pos, index); }); RDDialog::show(&contextMenu, viewport()->mapToGlobal(pos)); } +void RDTreeView::copyIndex(QPoint pos, QModelIndex index) +{ + bool clearsel = false; + if(selectionModel()->selectedRows().empty()) + { + setSelection(QRect(pos, QSize(1, 1)), selectionCommand(index)); + clearsel = true; + } + copySelection(); + if(clearsel) + selectionModel()->clear(); +} + void RDTreeView::expandAll(QModelIndex index) { expand(index); diff --git a/qrenderdoc/Widgets/Extended/RDTreeView.h b/qrenderdoc/Widgets/Extended/RDTreeView.h index 2f9a66aaf..662ebcdec 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeView.h +++ b/qrenderdoc/Widgets/Extended/RDTreeView.h @@ -133,6 +133,8 @@ public: void clearInternalExpansions() { m_Expansions.clear(); } virtual void copySelection(); + void copyIndex(QPoint pos, QModelIndex index); + void expandAll(QModelIndex index); void collapseAll(QModelIndex index); using QTreeView::expandAll; diff --git a/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp b/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp index da04c5088..bfc1315a5 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp +++ b/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp @@ -668,6 +668,12 @@ QAbstractItemDelegate *RDTreeWidget::itemDelegate() const { return m_userDelegate; } + +void RDTreeWidget::copyItem(QPoint pos, RDTreeWidgetItem *item) +{ + copyIndex(pos, m_model->indexForItem(item, 0)); +} + void RDTreeWidget::setColumns(const QStringList &columns) { m_headers = columns; diff --git a/qrenderdoc/Widgets/Extended/RDTreeWidget.h b/qrenderdoc/Widgets/Extended/RDTreeWidget.h index 119cc1f43..426456d92 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeWidget.h +++ b/qrenderdoc/Widgets/Extended/RDTreeWidget.h @@ -241,6 +241,8 @@ public: void setItemDelegate(QAbstractItemDelegate *delegate); QAbstractItemDelegate *itemDelegate() const; + void copyItem(QPoint pos, RDTreeWidgetItem *item); + void setColumns(const QStringList &columns); const QStringList &getHeaders() const { return m_headers; } QString headerText(int column) const { return m_headers[column]; } diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index b6a7cfd58..79b55356e 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -224,6 +224,8 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, ui->iaBuffers->setClearSelectionOnFocusLoss(true); ui->iaBuffers->setInstantTooltips(true); ui->iaBuffers->setHoverIconColumn(5, action, action_hover); + + m_Common.SetupResourceView(ui->iaBuffers); } for(RDTreeWidget *tex : resources) @@ -238,6 +240,8 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, tex->setHoverIconColumn(8, action, action_hover); tex->setClearSelectionOnFocusLoss(true); tex->setInstantTooltips(true); + + m_Common.SetupResourceView(tex); } for(RDTreeWidget *samp : samplers) @@ -251,6 +255,8 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, samp->setClearSelectionOnFocusLoss(true); samp->setInstantTooltips(true); + + m_Common.SetupResourceView(samp); } for(RDTreeWidget *cbuffer : cbuffers) @@ -264,6 +270,8 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, cbuffer->setHoverIconColumn(4, action, action_hover); cbuffer->setClearSelectionOnFocusLoss(true); cbuffer->setInstantTooltips(true); + + m_Common.SetupResourceView(cbuffer); } for(RDTreeWidget *cl : classes) @@ -276,6 +284,8 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, cl->setClearSelectionOnFocusLoss(true); cl->setInstantTooltips(true); + + m_Common.SetupResourceView(cl); } { @@ -290,6 +300,8 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, ui->gsStreamOut->setHoverIconColumn(4, action, action_hover); ui->gsStreamOut->setClearSelectionOnFocusLoss(true); ui->gsStreamOut->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->gsStreamOut); } { @@ -329,6 +341,8 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, ui->targetOutputs->setHoverIconColumn(8, action, action_hover); ui->targetOutputs->setClearSelectionOnFocusLoss(true); ui->targetOutputs->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->targetOutputs); } { @@ -367,6 +381,8 @@ D3D11PipelineStateViewer::D3D11PipelineStateViewer(ICaptureContext &ctx, ui->csUAVs->setHoverIconColumn(8, action, action_hover); ui->csUAVs->setClearSelectionOnFocusLoss(true); ui->csUAVs->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->csUAVs); } // this is often changed just because we're changing some tab in the designer. @@ -475,6 +491,66 @@ void D3D11PipelineStateViewer::SelectPipelineStage(PipelineStage stage) ui->pipeFlow->setSelectedStage((int)stage); } +ResourceId D3D11PipelineStateViewer::GetResource(RDTreeWidgetItem *item) +{ + QVariant tag = item->tag(); + + const rdcarray cbuffers = { + ui->vsCBuffers, ui->hsCBuffers, ui->dsCBuffers, + ui->gsCBuffers, ui->psCBuffers, ui->csCBuffers, + }; + + if(tag.canConvert()) + { + return tag.value(); + } + else if(tag.canConvert()) + { + D3D11ViewTag viewTag = tag.value(); + return viewTag.res.resourceResourceId; + } + else if(tag.canConvert()) + { + D3D11VBIBTag buf = tag.value(); + return buf.id; + } + else if(cbuffers.contains(item->treeWidget())) + { + const D3D11Pipe::Shader *stage = stageForSender(item->treeWidget()); + + if(stage == NULL) + return ResourceId(); + + int cb = tag.value(); + + int cbufIdx = -1; + + for(int i = 0; i < stage->bindpointMapping.constantBlocks.count(); i++) + { + if(stage->bindpointMapping.constantBlocks[i].bind == cb) + { + cbufIdx = i; + break; + } + } + + if(cbufIdx == -1) + { + // unused cbuffer, open regular buffer viewer + if(cb >= stage->constantBuffers.count()) + return ResourceId(); + + const D3D11Pipe::ConstantBuffer &bind = stage->constantBuffers[cb]; + + return bind.resourceId; + } + + return m_Ctx.CurPipelineState().GetConstantBuffer(stage->stage, cbufIdx, 0).resourceId; + } + + return ResourceId(); +} + void D3D11PipelineStateViewer::on_showUnused_toggled(bool checked) { setState(); diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.h index 76e313a8a..77d93e324 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.h @@ -55,6 +55,7 @@ public: void OnEventChanged(uint32_t eventId) override; void SelectPipelineStage(PipelineStage stage); + ResourceId GetResource(RDTreeWidgetItem *item); private slots: // automatic slots diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 9bce01ea6..e32ea4bc8 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -261,6 +261,8 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, ui->iaBuffers->setClearSelectionOnFocusLoss(true); ui->iaBuffers->setInstantTooltips(true); ui->iaBuffers->setHoverIconColumn(5, action, action_hover); + + m_Common.SetupResourceView(ui->iaBuffers); } for(RDTreeWidget *res : resources) @@ -278,6 +280,8 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, res->setHoverIconColumn(10, action, action_hover); res->setClearSelectionOnFocusLoss(true); res->setInstantTooltips(true); + + m_Common.SetupResourceView(res); } for(RDTreeWidget *uav : uavs) @@ -295,6 +299,8 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, uav->setHoverIconColumn(10, action, action_hover); uav->setClearSelectionOnFocusLoss(true); uav->setInstantTooltips(true); + + m_Common.SetupResourceView(uav); } for(RDTreeWidget *samp : samplers) @@ -310,6 +316,8 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, samp->setClearSelectionOnFocusLoss(true); samp->setInstantTooltips(true); + + m_Common.SetupResourceView(samp); } for(RDTreeWidget *cbuffer : cbuffers) @@ -326,6 +334,8 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, cbuffer->setHoverIconColumn(6, action, action_hover); cbuffer->setClearSelectionOnFocusLoss(true); cbuffer->setInstantTooltips(true); + + m_Common.SetupResourceView(cbuffer); } { @@ -340,6 +350,8 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, ui->gsStreamOut->setHoverIconColumn(6, action, action_hover); ui->gsStreamOut->setClearSelectionOnFocusLoss(true); ui->gsStreamOut->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->gsStreamOut); } { @@ -379,6 +391,8 @@ D3D12PipelineStateViewer::D3D12PipelineStateViewer(ICaptureContext &ctx, ui->targetOutputs->setHoverIconColumn(8, action, action_hover); ui->targetOutputs->setClearSelectionOnFocusLoss(true); ui->targetOutputs->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->targetOutputs); } { @@ -509,6 +523,48 @@ void D3D12PipelineStateViewer::SelectPipelineStage(PipelineStage stage) ui->pipeFlow->setSelectedStage((int)stage); } +ResourceId D3D12PipelineStateViewer::GetResource(RDTreeWidgetItem *item) +{ + QVariant tag = item->tag(); + + if(tag.canConvert()) + { + return tag.value(); + } + else if(tag.canConvert()) + { + D3D12ViewTag viewTag = tag.value(); + return viewTag.res.resourceId; + } + else if(tag.canConvert()) + { + D3D12VBIBTag buf = tag.value(); + return buf.id; + } + else if(tag.canConvert()) + { + const D3D12Pipe::Shader *stage = stageForSender(item->treeWidget()); + + if(stage == NULL) + return ResourceId(); + + D3D12CBufTag cb = tag.value(); + + if(cb.idx == ~0U) + { + // unused cbuffer, open regular buffer viewer + const D3D12Pipe::ConstantBuffer &buf = + m_Ctx.CurD3D12PipelineState()->rootElements[cb.rootElement].constantBuffers[cb.reg]; + + return buf.resourceId; + } + + return m_Ctx.CurPipelineState().GetConstantBuffer(stage->stage, cb.idx, cb.arrayIdx).resourceId; + } + + return ResourceId(); +} + void D3D12PipelineStateViewer::on_showUnused_toggled(bool checked) { setState(); diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h index f8ffa8a9c..aadf96b00 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.h @@ -56,6 +56,7 @@ public: void OnEventChanged(uint32_t eventId) override; void SelectPipelineStage(PipelineStage stage); + ResourceId GetResource(RDTreeWidgetItem *item); private slots: // automatic slots diff --git a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp index 57694b14d..95565fb8b 100644 --- a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp @@ -211,6 +211,8 @@ GLPipelineStateViewer::GLPipelineStateViewer(ICaptureContext &ctx, PipelineState ui->viBuffers->setClearSelectionOnFocusLoss(true); ui->viBuffers->setInstantTooltips(true); ui->viBuffers->setHoverIconColumn(6, action, action_hover); + + m_Common.SetupResourceView(ui->viBuffers); } for(RDTreeWidget *tex : textures) @@ -225,6 +227,8 @@ GLPipelineStateViewer::GLPipelineStateViewer(ICaptureContext &ctx, PipelineState tex->setHoverIconColumn(8, action, action_hover); tex->setClearSelectionOnFocusLoss(true); tex->setInstantTooltips(true); + + m_Common.SetupResourceView(tex); } for(RDTreeWidget *samp : samplers) @@ -238,6 +242,8 @@ GLPipelineStateViewer::GLPipelineStateViewer(ICaptureContext &ctx, PipelineState samp->setClearSelectionOnFocusLoss(true); samp->setInstantTooltips(true); + + m_Common.SetupResourceView(samp); } for(RDTreeWidget *ubo : ubos) @@ -251,6 +257,8 @@ GLPipelineStateViewer::GLPipelineStateViewer(ICaptureContext &ctx, PipelineState ubo->setHoverIconColumn(4, action, action_hover); ubo->setClearSelectionOnFocusLoss(true); ubo->setInstantTooltips(true); + + m_Common.SetupResourceView(ubo); } for(RDTreeWidget *sub : subroutines) @@ -265,18 +273,20 @@ GLPipelineStateViewer::GLPipelineStateViewer(ICaptureContext &ctx, PipelineState sub->setInstantTooltips(true); } - for(RDTreeWidget *ubo : readwrites) + for(RDTreeWidget *rw : readwrites) { RDHeaderView *header = new RDHeaderView(Qt::Horizontal, this); - ubo->setHeader(header); + rw->setHeader(header); - ubo->setColumns({tr("Binding"), tr("Slot"), tr("Resource"), tr("Dimensions"), tr("Format"), - tr("Access"), tr("Go")}); + rw->setColumns({tr("Binding"), tr("Slot"), tr("Resource"), tr("Dimensions"), tr("Format"), + tr("Access"), tr("Go")}); header->setColumnStretchHints({1, 1, 2, 3, 3, 1, -1}); - ubo->setHoverIconColumn(6, action, action_hover); - ubo->setClearSelectionOnFocusLoss(true); - ubo->setInstantTooltips(true); + rw->setHoverIconColumn(6, action, action_hover); + rw->setClearSelectionOnFocusLoss(true); + rw->setInstantTooltips(true); + + m_Common.SetupResourceView(rw); } { @@ -292,6 +302,8 @@ GLPipelineStateViewer::GLPipelineStateViewer(ICaptureContext &ctx, PipelineState ui->xfbBuffers->setClearSelectionOnFocusLoss(true); ui->xfbBuffers->setInstantTooltips(true); ui->xfbBuffers->setHoverIconColumn(4, action, action_hover); + + m_Common.SetupResourceView(ui->xfbBuffers); } { @@ -331,6 +343,8 @@ GLPipelineStateViewer::GLPipelineStateViewer(ICaptureContext &ctx, PipelineState ui->framebuffer->setHoverIconColumn(8, action, action_hover); ui->framebuffer->setClearSelectionOnFocusLoss(true); ui->framebuffer->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->framebuffer); } { @@ -458,6 +472,46 @@ void GLPipelineStateViewer::SelectPipelineStage(PipelineStage stage) ui->pipeFlow->setSelectedStage((int)stage); } +ResourceId GLPipelineStateViewer::GetResource(RDTreeWidgetItem *item) +{ + QVariant tag = item->tag(); + + const rdcarray ubos = { + ui->vsUBOs, ui->tcsUBOs, ui->tesUBOs, ui->gsUBOs, ui->fsUBOs, ui->csUBOs, + }; + + if(tag.canConvert()) + { + return tag.value(); + } + else if(tag.canConvert()) + { + GLVBIBTag buf = tag.value(); + return buf.id; + } + else if(tag.canConvert()) + { + GLReadWriteTag rw = tag.value(); + return rw.ID; + } + else if(ubos.contains(item->treeWidget())) + { + const GLPipe::Shader *stage = stageForSender(item->treeWidget()); + + if(stage == NULL) + return ResourceId(); + + if(!tag.canConvert()) + return ResourceId(); + + int cb = tag.value(); + + return m_Ctx.CurPipelineState().GetConstantBuffer(stage->stage, cb, 0).resourceId; + } + + return ResourceId(); +} + void GLPipelineStateViewer::on_showUnused_toggled(bool checked) { setState(); diff --git a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.h index ea8f0a654..07fd0651d 100644 --- a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.h @@ -55,6 +55,7 @@ public: void OnEventChanged(uint32_t eventId) override; void SelectPipelineStage(PipelineStage stage); + ResourceId GetResource(RDTreeWidgetItem *item); private slots: // automatic slots diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp index 7d43e3314..98b823fea 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp @@ -999,6 +999,100 @@ void PipelineStateViewer::SetupShaderEditButton(QToolButton *button, ResourceId button->setMenu(menu); } +void PipelineStateViewer::AddResourceUsageEntry(QMenu &menu, uint32_t start, uint32_t end, + ResourceUsage usage) +{ + QAction *item = NULL; + + if(start == end) + item = new QAction( + QFormatStr("EID %1: %2").arg(start).arg(ToQStr(usage, m_Ctx.APIProps().pipelineType)), this); + else + item = new QAction( + QFormatStr("EID %1-%2: %3").arg(start).arg(end).arg(ToQStr(usage, m_Ctx.APIProps().pipelineType)), + this); + + QObject::connect(item, &QAction::triggered, [this, end]() { m_Ctx.SetEventID({}, end, end); }); + + menu.addAction(item); +} + +void PipelineStateViewer::ShowResourceContextMenu(RDTreeWidget *widget, const QPoint &pos, + ResourceId id, const rdcarray &usage) +{ + RDTreeWidgetItem *item = widget->itemAt(pos); + + QMenu contextMenu(this); + + QAction copy(tr("&Copy"), this); + + contextMenu.addAction(©); + + copy.setIcon(Icons::copy()); + + QObject::connect(©, &QAction::triggered, + [widget, pos, item]() { widget->copyItem(pos, item); }); + + QAction usageTitle(tr("Used:"), this); + QAction openResourceInspector(tr("Open in Resource Inspector"), this); + + if(id != ResourceId()) + { + contextMenu.addSeparator(); + contextMenu.addAction(&openResourceInspector); + contextMenu.addAction(&usageTitle); + + QObject::connect(&openResourceInspector, &QAction::triggered, [this, id]() { + m_Ctx.ShowResourceInspector(); + + m_Ctx.GetResourceInspector()->Inspect(id); + }); + + CombineUsageEvents(m_Ctx, usage, + [this, &contextMenu](uint32_t start, uint32_t end, ResourceUsage use) { + AddResourceUsageEntry(contextMenu, start, end, use); + }); + } + + RDDialog::show(&contextMenu, widget->viewport()->mapToGlobal(pos)); +} + +void PipelineStateViewer::SetupResourceView(RDTreeWidget *widget) +{ + auto handler = [this, widget](const QPoint &pos) { + RDTreeWidgetItem *item = widget->itemAt(pos); + + ResourceId id; + + if(m_D3D11) + id = m_D3D11->GetResource(item); + else if(m_D3D12) + id = m_D3D12->GetResource(item); + else if(m_GL) + id = m_GL->GetResource(item); + else if(m_Vulkan) + id = m_Vulkan->GetResource(item); + + if(id != ResourceId()) + { + m_Ctx.Replay().AsyncInvoke([this, widget, pos, id](IReplayController *r) { + rdcarray usage = r->GetUsage(id); + + GUIInvoke::call(this, [this, widget, pos, id, usage]() { + ShowResourceContextMenu(widget, pos, id, usage); + }); + }); + } + else + { + ShowResourceContextMenu(widget, pos, id, {}); + } + }; + + widget->setContextMenuPolicy(Qt::CustomContextMenu); + QObject::connect(widget, &RDTreeWidget::customContextMenuRequested, handler); +} + QString PipelineStateViewer::GetVBufferFormatString(uint32_t slot) { rdcarray vbs = m_Ctx.CurPipelineState().GetVBuffers(); diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h index 73cc69f9c..d82dfc391 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h @@ -39,6 +39,7 @@ class QToolButton; class QMenu; class RDLabel; class RDTreeWidgetItem; +class RDTreeWidget; class D3D11PipelineStateViewer; class D3D12PipelineStateViewer; @@ -76,6 +77,8 @@ public: const ShaderBindpointMapping &bindpointMapping, const ShaderReflection *shaderDetails); + void SetupResourceView(RDTreeWidget *view); + QString GetVBufferFormatString(uint32_t slot); void setTopologyDiagram(QLabel *diagram, Topology topo); @@ -98,6 +101,10 @@ private: QMenu *editMenus[6] = {}; + void AddResourceUsageEntry(QMenu &menu, uint32_t start, uint32_t end, ResourceUsage usage); + void ShowResourceContextMenu(RDTreeWidget *widget, const QPoint &pos, ResourceId id, + const rdcarray &usage); + QString GenerateHLSLStub(const ShaderBindpointMapping &bindpointMapping, const ShaderReflection *shaderDetails, const QString &entryFunc); IShaderViewer *EditShader(ResourceId id, ShaderStage shaderType, const rdcstr &entry, diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 91dcadc9f..2362c2aef 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -259,6 +259,8 @@ VulkanPipelineStateViewer::VulkanPipelineStateViewer(ICaptureContext &ctx, ui->viBuffers->setHoverIconColumn(7, action, action_hover); ui->viBuffers->setClearSelectionOnFocusLoss(true); ui->viBuffers->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->viBuffers); } for(RDTreeWidget *res : resources) @@ -273,6 +275,8 @@ VulkanPipelineStateViewer::VulkanPipelineStateViewer(ICaptureContext &ctx, res->setHoverIconColumn(7, action, action_hover); res->setClearSelectionOnFocusLoss(true); res->setInstantTooltips(true); + + m_Common.SetupResourceView(res); } for(RDTreeWidget *ubo : ubos) @@ -287,6 +291,8 @@ VulkanPipelineStateViewer::VulkanPipelineStateViewer(ICaptureContext &ctx, ubo->setHoverIconColumn(6, action, action_hover); ubo->setClearSelectionOnFocusLoss(true); ubo->setInstantTooltips(true); + + m_Common.SetupResourceView(ubo); } { @@ -302,6 +308,8 @@ VulkanPipelineStateViewer::VulkanPipelineStateViewer(ICaptureContext &ctx, ui->xfbBuffers->setHoverIconColumn(7, action, action_hover); ui->xfbBuffers->setClearSelectionOnFocusLoss(true); ui->xfbBuffers->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->xfbBuffers); } { @@ -360,6 +368,8 @@ VulkanPipelineStateViewer::VulkanPipelineStateViewer(ICaptureContext &ctx, ui->fbAttach->setHoverIconColumn(8, action, action_hover); ui->fbAttach->setClearSelectionOnFocusLoss(true); ui->fbAttach->setInstantTooltips(true); + + m_Common.SetupResourceView(ui->fbAttach); } { @@ -471,6 +481,56 @@ void VulkanPipelineStateViewer::SelectPipelineStage(PipelineStage stage) ui->pipeFlow->setSelectedStage((int)stage); } +ResourceId VulkanPipelineStateViewer::GetResource(RDTreeWidgetItem *item) +{ + QVariant tag = item->tag(); + + if(tag.canConvert()) + { + return tag.value(); + } + else if(tag.canConvert()) + { + VulkanTextureTag texTag = tag.value(); + return texTag.ID; + } + else if(tag.canConvert()) + { + VulkanBufferTag buf = tag.value(); + return buf.ID; + } + else if(tag.canConvert()) + { + VulkanVBIBTag buf = tag.value(); + return buf.id; + } + else if(tag.canConvert()) + { + const VKPipe::Shader *stage = stageForSender(item->treeWidget()); + + if(stage == NULL) + return ResourceId(); + + VulkanCBufferTag cb = tag.value(); + + if(cb.slotIdx == ~0U) + { + // unused cbuffer, open regular buffer viewer + const VKPipe::Pipeline &pipe = cb.isGraphics ? m_Ctx.CurVulkanPipelineState()->graphics + : m_Ctx.CurVulkanPipelineState()->compute; + + const VKPipe::BindingElement &buf = + pipe.descriptorSets[cb.descSet].bindings[cb.descBind].binds[cb.arrayIdx]; + + return buf.resourceResourceId; + } + + return m_Ctx.CurPipelineState().GetConstantBuffer(stage->stage, cb.slotIdx, cb.arrayIdx).resourceId; + } + + return ResourceId(); +} + void VulkanPipelineStateViewer::on_showUnused_toggled(bool checked) { setState(); diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.h index 1a92c6e7d..ad2cd308c 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.h @@ -61,6 +61,7 @@ public: void OnEventChanged(uint32_t eventId); void SelectPipelineStage(PipelineStage stage); + ResourceId GetResource(RDTreeWidgetItem *item); private slots: // automatic slots