From ef58d7e1f8601732e197353b0d39dca6b6c13552 Mon Sep 17 00:00:00 2001 From: Steve Karolewics Date: Tue, 5 May 2020 22:59:13 -0700 Subject: [PATCH] Extend info in accessed resources panel in the shader viewer --- qrenderdoc/Windows/ShaderViewer.cpp | 249 ++++++++++++++++++++++------ qrenderdoc/Windows/ShaderViewer.h | 21 ++- qrenderdoc/Windows/ShaderViewer.ui | 81 +++++++++ 3 files changed, 295 insertions(+), 56 deletions(-) diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index 8f51a0630..9c29af146 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -60,11 +60,11 @@ struct VariableTag struct AccessedResourceTag { - AccessedResourceTag() : type(VarType::Unknown) { bind.bind = -1; } - AccessedResourceTag(BindpointIndex bp, VarType t) : bind(bp), type(t) {} - AccessedResourceTag(ShaderVariable var) + AccessedResourceTag() : type(VarType::Unknown), step(0) { bind.bind = -1; } + AccessedResourceTag(uint32_t s) : type(VarType::Unknown), step(s) { bind.bind = -1; } + AccessedResourceTag(BindpointIndex bp, VarType t) : bind(bp), type(t), step(0) {} + AccessedResourceTag(ShaderVariable var) : step(0), type(var.type) { - type = var.type; if(var.type == VarType::ReadOnlyResource || var.type == VarType::ReadWriteResource) bind = var.GetBinding(); else @@ -72,6 +72,7 @@ struct AccessedResourceTag } BindpointIndex bind; VarType type; + uint32_t step; }; }; @@ -523,7 +524,7 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR ui->constants->header()->resizeSection(0, 80); - ui->accessedResources->setColumns({tr("Register(s)"), tr("Type"), tr("Resource")}); + ui->accessedResources->setColumns({tr("Location"), tr("Type"), tr("Info")}); ui->accessedResources->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); ui->accessedResources->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); ui->accessedResources->header()->setSectionResizeMode(2, QHeaderView::Interactive); @@ -1215,24 +1216,41 @@ void ShaderViewer::accessedResources_contextMenu(const QPoint &pos) if(tree->selectedItem() == NULL) return; - QMenu contextMenu(this); + const AccessedResourceTag &tag = tree->selectedItem()->tag().value(); + if(tag.type == VarType::Unknown) + { + // Right clicked on an instruction row + QMenu contextMenu(this); - QAction prevAccess(tr("Run To Previous Access"), this); - QAction nextAccess(tr("Run To Next Access"), this); + QAction gotoInstr(tr("Go to Step"), this); - contextMenu.addAction(&prevAccess); - contextMenu.addAction(&nextAccess); + contextMenu.addAction(&gotoInstr); - QObject::connect(&prevAccess, &QAction::triggered, [this, tree] { - const AccessedResourceTag &tag = tree->selectedItem()->tag().value(); - runToResourceAccess(false, tag.type, tag.bind); - }); - QObject::connect(&nextAccess, &QAction::triggered, [this, tree] { - const AccessedResourceTag &tag = tree->selectedItem()->tag().value(); - runToResourceAccess(true, tag.type, tag.bind); - }); + QObject::connect(&gotoInstr, &QAction::triggered, [this, tag] { + bool forward = (tag.step >= m_CurrentStateIdx); + runTo({tag.step}, forward); + }); - RDDialog::show(&contextMenu, w->viewport()->mapToGlobal(pos)); + RDDialog::show(&contextMenu, w->viewport()->mapToGlobal(pos)); + } + else + { + // Right clicked on a resource row + QMenu contextMenu(this); + + QAction prevAccess(tr("Run to Previous Access"), this); + QAction nextAccess(tr("Run to Next Access"), this); + + contextMenu.addAction(&prevAccess); + contextMenu.addAction(&nextAccess); + + QObject::connect(&prevAccess, &QAction::triggered, + [this, tag] { runToResourceAccess(false, tag.type, tag.bind); }); + QObject::connect(&nextAccess, &QAction::triggered, + [this, tag] { runToResourceAccess(true, tag.type, tag.bind); }); + + RDDialog::show(&contextMenu, w->viewport()->mapToGlobal(pos)); + } } void ShaderViewer::disassembly_buttonReleased(QMouseEvent *event) @@ -1716,15 +1734,6 @@ void ShaderViewer::applyBackwardsChange() break; } } - - for(size_t i = 0; i < m_AccessedResources.size(); i++) - { - if(c.after.name == m_AccessedResources[i].name) - { - m_AccessedResources.erase(i); - break; - } - } } else { @@ -1758,7 +1767,7 @@ void ShaderViewer::applyForwardsChange() m_CurrentStateIdx++; rdcarray newVariables; - rdcarray newAccessedResources; + rdcarray newAccessedResources; for(const ShaderVariableChange &c : GetCurrentState().changes) { @@ -1797,15 +1806,17 @@ void ShaderViewer::applyForwardsChange() bool found = false; for(size_t i = 0; i < m_AccessedResources.size(); i++) { - if(c.after.GetBinding() == m_AccessedResources[i].GetBinding()) + if(c.after.GetBinding() == m_AccessedResources[i].resource.GetBinding()) { found = true; + if(m_AccessedResources[i].steps.indexOf(m_CurrentStateIdx) < 0) + m_AccessedResources[i].steps.push_back(m_CurrentStateIdx); break; } } if(!found) - newAccessedResources.push_back(c.after); + newAccessedResources.push_back({c.after, {m_CurrentStateIdx}}); } } } @@ -2245,6 +2256,141 @@ void ShaderViewer::highlightMatchingVars(RDTreeWidgetItem *root, const QString v } } +void ShaderViewer::updateAccessedResources() +{ + RDTreeViewExpansionState expansion; + ui->accessedResources->saveExpansion(expansion, 0); + + ui->accessedResources->beginUpdate(); + + ui->accessedResources->clear(); + + switch(m_AccessedResourceView) + { + case AccessedResourceView::SortByResource: + { + for(size_t i = 0; i < m_AccessedResources.size(); ++i) + { + // Check if the resource was accessed prior to this step + bool accessed = false; + for(size_t j = 0; j < m_AccessedResources[i].steps.size(); ++j) + { + if(m_AccessedResources[i].steps[j] <= m_CurrentStateIdx) + { + accessed = true; + break; + } + } + if(!accessed) + continue; + + bool modified = false; + for(const ShaderVariableChange &c : GetCurrentState().changes) + { + if(c.before.name == m_AccessedResources[i].resource.name || + c.after.name == m_AccessedResources[i].resource.name) + { + modified = true; + break; + } + } + + RDTreeWidgetItem *resourceNode = + makeAccessedResourceNode(m_AccessedResources[i].resource, modified); + if(resourceNode) + { + // Add a child for each step that it was accessed + for(size_t j = 0; j < m_AccessedResources[i].steps.size(); ++j) + { + accessed = m_AccessedResources[i].steps[j] <= m_CurrentStateIdx; + if(accessed) + { + RDTreeWidgetItem *stepNode = new RDTreeWidgetItem( + {tr("Step %1").arg(m_AccessedResources[i].steps[j]), lit("Access"), lit("")}); + stepNode->setTag(QVariant::fromValue( + AccessedResourceTag((uint32_t)m_AccessedResources[i].steps[j]))); + if(m_CurrentStateIdx == m_AccessedResources[i].steps[j]) + stepNode->setForegroundColor(QColor(Qt::red)); + resourceNode->addChild(stepNode); + } + } + + ui->accessedResources->addTopLevelItem(resourceNode); + } + } + + break; + } + case AccessedResourceView::SortByStep: + { + rdcarray> stepNodes; + for(size_t i = 0; i < m_AccessedResources.size(); ++i) + { + bool modified = false; + for(const ShaderVariableChange &c : GetCurrentState().changes) + { + if(c.before.name == m_AccessedResources[i].resource.name || + c.after.name == m_AccessedResources[i].resource.name) + { + modified = true; + break; + } + } + + // Add a root node for each instruction, and place the resource node as a child + for(size_t j = 0; j < m_AccessedResources[i].steps.size(); ++j) + { + bool accessed = m_AccessedResources[i].steps[j] <= m_CurrentStateIdx; + if(accessed) + { + int32_t nodeIdx = -1; + for(int32_t k = 0; k < stepNodes.count(); ++k) + { + if(stepNodes[k].first == m_AccessedResources[i].steps[j]) + { + nodeIdx = k; + break; + } + } + + RDTreeWidgetItem *resourceNode = + makeAccessedResourceNode(m_AccessedResources[i].resource, modified); + + if(nodeIdx == -1) + { + RDTreeWidgetItem *stepNode = new RDTreeWidgetItem( + {tr("Step %1").arg(m_AccessedResources[i].steps[j]), lit("Access"), lit("")}); + stepNode->setTag(QVariant::fromValue( + AccessedResourceTag((uint32_t)m_AccessedResources[i].steps[j]))); + if(m_CurrentStateIdx == m_AccessedResources[i].steps[j]) + stepNode->setForegroundColor(QColor(Qt::red)); + stepNode->addChild(resourceNode); + stepNodes.push_back({m_AccessedResources[i].steps[j], stepNode}); + } + else + { + stepNodes[nodeIdx].second->addChild(resourceNode); + } + } + } + } + + std::sort(stepNodes.begin(), stepNodes.end(), + [](const rdcpair &a, + const rdcpair &b) { return a.first < b.first; }); + + for(size_t i = 0; i < stepNodes.size(); ++i) + ui->accessedResources->addTopLevelItem(stepNodes[i].second); + + break; + } + } + + ui->accessedResources->endUpdate(); + + ui->accessedResources->applyExpansion(expansion, 0); +} + void ShaderViewer::updateDebugState() { if(!m_Trace || m_States.empty()) @@ -2758,30 +2904,7 @@ void ShaderViewer::updateDebugState() ui->debugVars->applyExpansion(expansion, 0); } - { - ui->accessedResources->beginUpdate(); - - ui->accessedResources->clear(); - - for(int i = 0; i < m_AccessedResources.count(); i++) - { - bool modified = false; - - for(const ShaderVariableChange &c : GetCurrentState().changes) - { - if(c.before.name == m_AccessedResources[i].name || c.after.name == m_AccessedResources[i].name) - { - modified = true; - break; - } - } - - ui->accessedResources->addTopLevelItem( - makeAccessedResourceNode(m_AccessedResources[i], modified)); - } - - ui->accessedResources->endUpdate(); - } + updateAccessedResources(); updateWatchVariables(); @@ -4565,6 +4688,22 @@ void ShaderViewer::on_debugToggle_clicked() updateDebugState(); } +void ShaderViewer::on_resources_sortByStep_clicked() +{ + m_AccessedResourceView = AccessedResourceView::SortByStep; + ui->resources_sortByStep->setChecked(true); + ui->resources_sortByResource->setChecked(false); + updateAccessedResources(); +} + +void ShaderViewer::on_resources_sortByResource_clicked() +{ + m_AccessedResourceView = AccessedResourceView::SortByResource; + ui->resources_sortByResource->setChecked(true); + ui->resources_sortByStep->setChecked(false); + updateAccessedResources(); +} + ScintillaEdit *ShaderViewer::currentScintilla() { ScintillaEdit *cur = qobject_cast(QApplication::focusWidget()); diff --git a/qrenderdoc/Windows/ShaderViewer.h b/qrenderdoc/Windows/ShaderViewer.h index 507e1e2c0..f0e2a1930 100644 --- a/qrenderdoc/Windows/ShaderViewer.h +++ b/qrenderdoc/Windows/ShaderViewer.h @@ -56,6 +56,18 @@ enum class VariableCategory ByString, }; +enum class AccessedResourceView +{ + SortByStep, + SortByResource, +}; + +struct AccessedResourceData +{ + ShaderVariable resource; + rdcarray steps; +}; + class ShaderViewer : public QFrame, public IShaderViewer, public ICaptureViewer { Q_OBJECT @@ -117,6 +129,9 @@ private slots: void on_floatView_clicked(); void on_debugToggle_clicked(); + void on_resources_sortByStep_clicked(); + void on_resources_sortByResource_clicked(); + void on_watch_itemChanged(QTableWidgetItem *item); // manual slots @@ -238,7 +253,10 @@ private: rdcarray m_States; size_t m_CurrentStateIdx = 0; rdcarray m_Variables; - rdcarray m_AccessedResources; + + rdcarray m_AccessedResources; + AccessedResourceView m_AccessedResourceView = AccessedResourceView::SortByResource; + rdcarray m_ReadOnlyResources; rdcarray m_ReadWriteResources; QList m_Breakpoints; @@ -278,6 +296,7 @@ private: void updateDebugState(); void updateWatchVariables(); + void updateAccessedResources(); RDTreeWidgetItem *makeSourceVariableNode(const ShaderVariable &var, const rdcstr &sourcePath, const rdcstr &debugVarPath, bool modified); diff --git a/qrenderdoc/Windows/ShaderViewer.ui b/qrenderdoc/Windows/ShaderViewer.ui index ae87db104..44f4531c1 100644 --- a/qrenderdoc/Windows/ShaderViewer.ui +++ b/qrenderdoc/Windows/ShaderViewer.ui @@ -165,6 +165,87 @@ + + + + Qt::PreventContextMenu + + + QFrame::NoFrame + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Sort By Resource + + + true + + + true + + + true + + + Sort accessed resource by shader binding + + + + + + + Sort By Instruction + + + true + + + false + + + true + + + Sort accessed resource by instruction step + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + +