diff --git a/qrenderdoc/Code/Interface/PersistantConfig.h b/qrenderdoc/Code/Interface/PersistantConfig.h index 54d52a22e..488b15888 100644 --- a/qrenderdoc/Code/Interface/PersistantConfig.h +++ b/qrenderdoc/Code/Interface/PersistantConfig.h @@ -662,7 +662,17 @@ DECLARE_REFLECTION_STRUCT(BugReport); CONFIG_SETTING(public, QVariantList, rdcarray, AlwaysLoad_Extensions) \ \ DOCUMENT(""); \ - CONFIG_SETTING(private, QVariantList, rdcarray, RemoteHostList) + CONFIG_SETTING(private, QVariantList, rdcarray, RemoteHostList) \ + \ + DOCUMENT(""); \ + DOCUMENT( \ + "``False`` if :class:`ResourceUsage` should combine resource usage across marker " \ + "boundaries.\n" \ + "\n:" \ + "Defaults to ``False``." \ + "" \ + ":type: bool"); \ + CONFIG_SETTING_VAL(public, bool, bool, ResourceUsage_SplitByMarker, false) DOCUMENT(R"(The formatting mode used when displaying fields marked as Offsets or Sizes. diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp index be8865358..e5156dec0 100644 --- a/qrenderdoc/Code/QRDUtils.cpp +++ b/qrenderdoc/Code/QRDUtils.cpp @@ -1882,19 +1882,92 @@ float ConvertLinearToSRGB(float linear) return 1.055f * powf(linear, 1.0f / 2.4f) - 0.055f; } -void CombineUsageEvents(ICaptureContext &ctx, const rdcarray &usage, +static const ActionDescription *GetParentMarker(ICaptureContext &ctx, uint32_t eventId) +{ + const ActionDescription *parent = ctx.GetAction(eventId); + if(!parent) + { + rdcarray actions; + // Search the actions to find which action contains this eventId + for(const ActionDescription &action : ctx.CurRootActions()) + actions.push_back(&action); + + while(!parent && !actions.empty()) + { + const ActionDescription *action = actions.back(); + for(const APIEvent &event : action->events) + { + if(event.eventId == eventId) + { + parent = action; + break; + } + } + actions.pop_back(); + if(action->eventId < eventId) + { + for(const ActionDescription &child : action->children) + actions.push_back(&child); + } + } + } + while(parent != NULL && (parent->flags != ActionFlags::PushMarker)) + parent = parent->parent; + + return parent; +} + +QString GetParentMarkerName(ICaptureContext &ctx, uint32_t eventId) +{ + const ActionDescription *parent = GetParentMarker(ctx, eventId); + return parent ? QString(parent->customName) : QString(); +} + +QString GetParentMarkerPath(ICaptureContext &ctx, uint32_t eventId, bool &hasParent) +{ + const ActionDescription *parent = GetParentMarker(ctx, eventId); + + QString markerPath; + while(parent) + { + if(parent->flags & ActionFlags::PushMarker) + { + QString prevPath = markerPath; + markerPath = parent->customName; + if(!prevPath.isEmpty()) + { + markerPath += lit(" -> "); + markerPath += prevPath; + hasParent = true; + } + } + parent = parent->parent; + } + return markerPath; +} + +uint32_t GetParentMarkerEventId(ICaptureContext &ctx, uint32_t eventId) +{ + const ActionDescription *parent = GetParentMarker(ctx, eventId); + return parent ? parent->eventId : 0; +} + +void CombineUsageEvents(ICaptureContext &ctx, const rdcarray &usage, bool splitByMarker, std::function callback) { uint32_t start = 0; uint32_t end = 0; ResourceUsage us = ResourceUsage::IndexBuffer; + uint32_t parentEID = 0; for(const EventUsage &u : usage) { if(start == 0) { start = end = u.eventId; us = u.usage; + + parentEID = GetParentMarkerEventId(ctx, u.eventId); } if(u.usage == us && u.eventId == end) @@ -1904,9 +1977,12 @@ void CombineUsageEvents(ICaptureContext &ctx, const rdcarray &usage, bool distinct = false; + const uint32_t newParentEID = GetParentMarkerEventId(ctx, u.eventId); + // if the usage is different from the last, add a new entry, // or if the previous action link is broken. - if(u.usage != us || action == NULL || action->previous == 0) + if(u.usage != us || action == NULL || action->previous == 0 || + (splitByMarker && (parentEID != newParentEID))) { distinct = true; } @@ -1920,6 +1996,16 @@ void CombineUsageEvents(ICaptureContext &ctx, const rdcarray &usage, while(prev != NULL && prev->eventId > end) { + if(splitByMarker) + { + const uint32_t prevParentEID = GetParentMarkerEventId(ctx, prev->eventId); + if(parentEID != prevParentEID) + { + distinct = true; + break; + } + } + if(!(prev->flags & (ActionFlags::Dispatch | ActionFlags::MeshDispatch | ActionFlags::Drawcall | ActionFlags::CmdList))) { @@ -1947,6 +2033,7 @@ void CombineUsageEvents(ICaptureContext &ctx, const rdcarray &usage, { start = end = u.eventId; us = u.usage; + parentEID = newParentEID; } } diff --git a/qrenderdoc/Code/QRDUtils.h b/qrenderdoc/Code/QRDUtils.h index a9bf563d4..3294be0e0 100644 --- a/qrenderdoc/Code/QRDUtils.h +++ b/qrenderdoc/Code/QRDUtils.h @@ -271,8 +271,11 @@ QString GetComponentString(byte mask); QIcon MakeSwatchIcon(QWidget *parentWidget, QColor swatchColor); float ConvertLinearToSRGB(float linear); void CombineUsageEvents( - ICaptureContext &ctx, const rdcarray &usage, + ICaptureContext &ctx, const rdcarray &usage, bool splitByMarker, std::function callback); +uint32_t GetParentMarkerEventId(ICaptureContext &ctx, uint32_t eventId); +QString GetParentMarkerName(ICaptureContext &ctx, uint32_t eventId); +QString GetParentMarkerPath(ICaptureContext &ctx, uint32_t eventId, bool &hasParent); class RDTreeWidgetItem; diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp index ad4a097b1..306644ddf 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp @@ -1190,7 +1190,7 @@ void PipelineStateViewer::ShowResourceContextMenu(RDTreeWidget *widget, const QP m_Ctx.GetResourceInspector()->Inspect(id); }); - CombineUsageEvents(m_Ctx, usage, + CombineUsageEvents(m_Ctx, usage, false, [this, &contextMenu](uint32_t start, uint32_t end, ResourceUsage use) { AddResourceUsageEntry(contextMenu, start, end, use); }); diff --git a/qrenderdoc/Windows/ResourceInspector.cpp b/qrenderdoc/Windows/ResourceInspector.cpp index 1dc8023bb..480d6e0be 100644 --- a/qrenderdoc/Windows/ResourceInspector.cpp +++ b/qrenderdoc/Windows/ResourceInspector.cpp @@ -138,6 +138,8 @@ bool ResourceSorterModel::lessThan(const QModelIndex &source_left, const QModelI ResourceInspector::ResourceInspector(ICaptureContext &ctx, QWidget *parent) : QFrame(parent), ui(new Ui::ResourceInspector), m_Ctx(ctx) { + m_SplitByMarker = ctx.Config().ResourceUsage_SplitByMarker; + ui->setupUi(this); SetResourceNameDisplay(tr("No Resource Selected")); @@ -178,6 +180,10 @@ ResourceInspector::ResourceInspector(ICaptureContext &ctx, QWidget *parent) ui->relatedResources->setFont(Formatter::PreferredFont()); ui->resourceUsage->setFont(Formatter::PreferredFont()); + ui->resourceUsage->setContextMenuPolicy(Qt::CustomContextMenu); + QObject::connect(ui->resourceUsage, &QWidget::customContextMenuRequested, this, + &ResourceInspector::resourceUsage_contextMenu); + { RDHeaderView *header = new RDHeaderView(Qt::Horizontal, this); ui->relatedResources->setHeader(header); @@ -190,8 +196,8 @@ ResourceInspector::ResourceInspector(ICaptureContext &ctx, QWidget *parent) RDHeaderView *header = new RDHeaderView(Qt::Horizontal, this); ui->resourceUsage->setHeader(header); - ui->resourceUsage->setColumns({tr("EID"), tr("Usage")}); - header->setColumnStretchHints({-1, 1}); + ui->resourceUsage->setColumns({tr("EID"), tr("Usage"), tr("End Marker")}); + header->setColumnStretchHints({-1, -1, 1}); } QObject::connect(ui->resourceList, &QListView::activated, this, @@ -309,31 +315,47 @@ void ResourceInspector::Inspect(ResourceId id) ui->resourceUsage->setEnabled(false); ui->resourceUsage->addTopLevelItem(new RDTreeWidgetItem( - {QString(), tr("Resource usage not tracked for this type of resource")})); + {QString(), QString(), tr("Resource usage not tracked for this type of resource")})); } else if(usage.empty()) { - ui->resourceUsage->addTopLevelItem( - new RDTreeWidgetItem({QString(), tr("No static usage observed for this resource")})); + ui->resourceUsage->addTopLevelItem(new RDTreeWidgetItem( + {QString(), QString(), tr("No static usage observed for this resource")})); } else { - CombineUsageEvents( - m_Ctx, usage, [this](uint32_t startEID, uint32_t endEID, ResourceUsage use) { - QString text; + CombineUsageEvents(m_Ctx, usage, m_SplitByMarker, [this](uint32_t startEID, uint32_t endEID, ResourceUsage use) { + QString text; - if(startEID == endEID) - text = QFormatStr("EID %1").arg(startEID); - else - text = QFormatStr("EID %1-%2").arg(startEID).arg(endEID); + if(startEID == endEID) + text = QFormatStr("EID %1").arg(startEID); + else + text = QFormatStr("EID %1-%2").arg(startEID).arg(endEID); + uint32_t eid = m_SplitByMarker ? startEID : endEID; - RDTreeWidgetItem *item = - new RDTreeWidgetItem({text, ToQStr(use, m_Ctx.APIProps().pipelineType)}); - item->setData(0, ResourceIdRole, QVariant(endEID)); - item->setData(1, ResourceIdRole, QVariant(endEID)); + QString markerName(GetParentMarkerName(m_Ctx, eid)); + bool hasParent = false; + QString fullMarkerPath = GetParentMarkerPath(m_Ctx, eid, hasParent); - ui->resourceUsage->addTopLevelItem(item); - }); + RDTreeWidgetItem *item = + new RDTreeWidgetItem({text, ToQStr(use, m_Ctx.APIProps().pipelineType), markerName}); + item->setData(0, ResourceIdRole, QVariant(endEID)); + item->setData(1, ResourceIdRole, QVariant(endEID)); + item->setData(2, ResourceIdRole, QVariant(endEID)); + item->setToolTip(fullMarkerPath); + + if(hasParent) + { + RDTreeWidgetItem *child = new RDTreeWidgetItem({QString(), QString(), fullMarkerPath}); + child->setData(0, ResourceIdRole, QVariant(endEID)); + child->setData(1, ResourceIdRole, QVariant(endEID)); + child->setData(2, ResourceIdRole, QVariant(endEID)); + child->setToolTip(fullMarkerPath); + + item->addChild(child); + } + ui->resourceUsage->addTopLevelItem(item); + }); } ui->resourceUsage->endUpdate(); @@ -654,6 +676,44 @@ void ResourceInspector::on_resourceUsage_doubleClicked(const QModelIndex &index) m_Ctx.SetEventID({}, eid, eid); } +void ResourceInspector::on_resourceUsage_SplitByMarker_toggled() +{ + m_SplitByMarker = !m_SplitByMarker; + m_Ctx.Config().ResourceUsage_SplitByMarker = m_SplitByMarker; + m_Ctx.Config().Save(); + + // force a refresh to pick up the new grouping of usage + ResourceId id = m_Resource; + m_Resource = ResourceId(); + Inspect(id); + if(m_SplitByMarker) + ui->resourceUsage->setColumns({tr("EID"), tr("Usage"), tr("Start Marker")}); + else + ui->resourceUsage->setColumns({tr("EID"), tr("Usage"), tr("End Marker")}); +} + +void ResourceInspector::resourceUsage_contextMenu(const QPoint &pos) +{ + QMenu contextMenu(this); + QAction copyText(tr("Copy"), this); + QAction splitByMarker(tr("Split By Marker"), this); + splitByMarker.setCheckable(true); + splitByMarker.setChecked(m_SplitByMarker); + + RDTreeWidget *resourceUsage = ui->resourceUsage; + QModelIndex index = resourceUsage->indexAt(pos); + + QObject::connect(©Text, &QAction::triggered, + [resourceUsage, pos, index] { resourceUsage->copyIndex(pos, index); }); + QObject::connect(&splitByMarker, &QAction::triggered, + [this] { this->on_resourceUsage_SplitByMarker_toggled(); }); + + contextMenu.addAction(©Text); + contextMenu.addAction(&splitByMarker); + + RDDialog::show(&contextMenu, ui->resourceUsage->viewport()->mapToGlobal(pos)); +} + void ResourceInspector::enterEvent(QEvent *event) { HighlightUsage(); diff --git a/qrenderdoc/Windows/ResourceInspector.h b/qrenderdoc/Windows/ResourceInspector.h index 50cffe9eb..5a3e60d41 100644 --- a/qrenderdoc/Windows/ResourceInspector.h +++ b/qrenderdoc/Windows/ResourceInspector.h @@ -103,10 +103,12 @@ public slots: // manual slots void resource_doubleClicked(const QModelIndex &index); + void resourceUsage_contextMenu(const QPoint &pos); private slots: void on_viewContents_clicked(); void on_resourceUsage_doubleClicked(const QModelIndex &index); + void on_resourceUsage_SplitByMarker_toggled(); protected: void enterEvent(QEvent *event) override; @@ -127,4 +129,5 @@ private: ResourceSorterModel *m_FilterModel; StructuredDataItemModel *m_ChunksModel; RichTextViewDelegate *m_delegate; + bool m_SplitByMarker = false; }; diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 7f2fb63b1..a633f171d 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -2392,7 +2392,7 @@ void TextureViewer::OpenResourceContextMenu(ResourceId id, bool input, m_Ctx.GetResourceInspector()->Inspect(id); }); - CombineUsageEvents(m_Ctx, usage, + CombineUsageEvents(m_Ctx, usage, false, [this, &contextMenu](uint32_t start, uint32_t end, ResourceUsage use) { AddResourceUsageEntry(contextMenu, start, end, use); });