From 9e3147d0214483469d6f881233ca7cbbda6a46ff Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 6 Aug 2018 13:48:58 +0100 Subject: [PATCH] Save treeview expansion state while browsing. Closes #678, Closes #1034 * This is supported currently in the API inspector, constant buffer previewer, and resource inspector. * The saved expansions are only saved while the capture is open, and will be reset each time. --- qrenderdoc/Widgets/Extended/RDTreeView.cpp | 5 + qrenderdoc/Widgets/Extended/RDTreeView.h | 2 + qrenderdoc/Windows/APIInspector.cpp | 7 ++ qrenderdoc/Windows/APIInspector.h | 2 + .../Windows/ConstantBufferPreviewer.cpp | 92 ++++++------------- qrenderdoc/Windows/ConstantBufferPreviewer.h | 5 - qrenderdoc/Windows/ResourceInspector.cpp | 7 ++ 7 files changed, 51 insertions(+), 69 deletions(-) diff --git a/qrenderdoc/Widgets/Extended/RDTreeView.cpp b/qrenderdoc/Widgets/Extended/RDTreeView.cpp index 1dfa717e2..ea68ed60d 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeView.cpp +++ b/qrenderdoc/Widgets/Extended/RDTreeView.cpp @@ -243,6 +243,11 @@ void RDTreeView::saveInternalExpansion(uint key, int keyColumn, int role) saveExpansionExternal(state, key, keyColumn, role); } +bool RDTreeView::hasInternalExpansion(uint key) +{ + return m_Expansions.contains(key); +} + void RDTreeView::applyInternalExpansion(uint key, int keyColumn, int role) { RDTreeViewExpansionState &state = m_Expansions[key]; diff --git a/qrenderdoc/Widgets/Extended/RDTreeView.h b/qrenderdoc/Widgets/Extended/RDTreeView.h index d0c80bec7..9f125ccbc 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeView.h +++ b/qrenderdoc/Widgets/Extended/RDTreeView.h @@ -97,6 +97,7 @@ public: QAbstractItemDelegate *itemDelegate() const; void saveInternalExpansion(uint key, int keyColumn, int role = Qt::DisplayRole); + bool hasInternalExpansion(uint key); void applyInternalExpansion(uint key, int keyColumn, int role = Qt::DisplayRole); void clearInternalExpansions(); @@ -111,6 +112,7 @@ public: saveInternalExpansion(qHash(keystring), keyColumn, role); } + bool hasInternalExpansion(QString keystring) { return hasInternalExpansion(qHash(keystring)); } void applyInternalExpansion(QString keystring, int keyColumn, int role = Qt::DisplayRole) { applyInternalExpansion(qHash(keystring), keyColumn, role); diff --git a/qrenderdoc/Windows/APIInspector.cpp b/qrenderdoc/Windows/APIInspector.cpp index 256acf8c5..8ef165b59 100644 --- a/qrenderdoc/Windows/APIInspector.cpp +++ b/qrenderdoc/Windows/APIInspector.cpp @@ -64,13 +64,20 @@ void APIInspector::OnCaptureClosed() { ui->apiEvents->clear(); ui->callstack->clear(); + ui->apiEvents->clearInternalExpansions(); + m_EventID = 0; } void APIInspector::OnSelectedEventChanged(uint32_t eventId) { + ui->apiEvents->saveInternalExpansion(m_EventID, 0); + ui->apiEvents->clearSelection(); fillAPIView(); + + m_EventID = eventId; + ui->apiEvents->applyInternalExpansion(m_EventID, 0); } void APIInspector::addCallstack(rdcarray calls) diff --git a/qrenderdoc/Windows/APIInspector.h b/qrenderdoc/Windows/APIInspector.h index 2079b8a44..2fcded9ba 100644 --- a/qrenderdoc/Windows/APIInspector.h +++ b/qrenderdoc/Windows/APIInspector.h @@ -57,6 +57,8 @@ private: Ui::APIInspector *ui; ICaptureContext &m_Ctx; + uint32_t m_EventID; + void addCallstack(rdcarray calls); void fillAPIView(); }; diff --git a/qrenderdoc/Windows/ConstantBufferPreviewer.cpp b/qrenderdoc/Windows/ConstantBufferPreviewer.cpp index 35a0f1341..6bea5b5aa 100644 --- a/qrenderdoc/Windows/ConstantBufferPreviewer.cpp +++ b/qrenderdoc/Windows/ConstantBufferPreviewer.cpp @@ -88,6 +88,7 @@ void ConstantBufferPreviewer::OnCaptureLoaded() void ConstantBufferPreviewer::OnCaptureClosed() { ui->variables->clear(); + ui->variables->clearInternalExpansions(); ui->saveCSV->setEnabled(false); @@ -101,6 +102,8 @@ void ConstantBufferPreviewer::OnEventChanged(uint32_t eventId) uint64_t offs = cb.byteOffset; uint64_t size = cb.byteSize; + ResourceId prevShader = m_shader; + m_shader = m_Ctx.CurPipelineState().GetShader(m_stage); QString entryPoint = m_Ctx.CurPipelineState().GetShaderEntryPoint(m_stage); const ShaderReflection *reflection = m_Ctx.CurPipelineState().GetShaderReflection(m_stage); @@ -109,6 +112,13 @@ void ConstantBufferPreviewer::OnEventChanged(uint32_t eventId) updateLabels(); + if(m_formatOverride.empty()) + { + // stage, slot, and array index are all invariant across a given ConstantBufferPreviewer + // instance. We only need to use the actual bound shader as a key. + ui->variables->saveInternalExpansion(ToQStr(prevShader), 0); + } + if(reflection == NULL || m_slot >= reflection->constantBlocks.size()) { setVariables({}); @@ -121,27 +131,43 @@ void ConstantBufferPreviewer::OnEventChanged(uint32_t eventId) bytebuf data = r->GetBufferData(m_cbuffer, offs, size); rdcarray vars = applyFormatOverride(data); GUIInvoke::call(this, [this, vars, wasEmpty] { + RDTreeViewExpansionState state; + ui->variables->saveExpansionExternal(state, 0, 0); setVariables(vars); if(wasEmpty) { for(int i = 0; i < 3; i++) ui->variables->resizeColumnToContents(i); } + ui->variables->applyExternalExpansion(state, 0, 0); }); }); } else { - m_Ctx.Replay().AsyncInvoke([this, entryPoint, offs, wasEmpty](IReplayController *r) { + m_Ctx.Replay().AsyncInvoke([this, entryPoint, offs, prevShader, wasEmpty](IReplayController *r) { rdcarray vars = r->GetCBufferVariableContents( m_shader, entryPoint.toUtf8().data(), m_slot, m_cbuffer, offs); - GUIInvoke::call(this, [this, vars, wasEmpty] { + GUIInvoke::call(this, [this, vars, prevShader, wasEmpty] { + + // save this state to reapply if we don't already have an internal expansion for the new + // shader, since this means two shaders with the same or similar constants will preserve + // expansion across selections. + RDTreeViewExpansionState state; + if(!ui->variables->hasInternalExpansion(ToQStr(m_shader))) + ui->variables->saveExpansionExternal(state, 0, 0); + setVariables(vars); if(wasEmpty) { for(int i = 0; i < 3; i++) ui->variables->resizeColumnToContents(i); } + + if(ui->variables->hasInternalExpansion(ToQStr(m_shader))) + ui->variables->applyInternalExpansion(ToQStr(m_shader), 0); + else + ui->variables->applyExternalExpansion(state, 0, 0); }); }); } @@ -262,72 +288,10 @@ void ConstantBufferPreviewer::addVariables(RDTreeWidgetItem *root, } } -bool ConstantBufferPreviewer::updateVariables(RDTreeWidgetItem *root, - const rdcarray &prevVars, - const rdcarray &newVars) -{ - // mismatched child count? can't update - if(prevVars.size() != newVars.size()) - return false; - - for(int i = 0; i < prevVars.count(); i++) - { - const ShaderVariable &a = prevVars[i]; - const ShaderVariable &b = newVars[i]; - - // different names? can't update - if(strcmp(a.name.c_str(), b.name.c_str())) - return false; - - // different size or type? can't update - if(a.rows != b.rows || a.columns != b.columns || a.displayAsHex != b.displayAsHex || - a.isStruct != b.isStruct || a.rowMajor != b.rowMajor || a.type != b.type) - return false; - - // update this node's value column - RDTreeWidgetItem *node = root->child(i); - - node->setText(1, VarString(b)); - - if(a.rows > 1) - { - for(uint32_t r = 0; r < a.rows; r++) - node->child(r)->setText(1, RowString(b, r)); - } - - if(!a.members.isEmpty()) - { - // recurse to update child members. This handles a and b having different number of variables - bool updated = updateVariables(node, a.members, b.members); - - if(!updated) - return false; - } - } - - // got this far without bailing? we updated! - return true; -} - void ConstantBufferPreviewer::setVariables(const rdcarray &vars) { ui->variables->beginUpdate(); - // try to update the variables in-place by only changing their values, if the set of variables - // matches *exactly* to what we had before. - // - // This keeps things like expanded structs and matrices when moving between drawcalls - bool updated = updateVariables(ui->variables->invisibleRootItem(), m_Vars, vars); - - // update the variables either way - m_Vars = vars; - - if(updated) - { - ui->variables->endUpdate(); - return; - } - ui->variables->clear(); ui->saveCSV->setEnabled(false); diff --git a/qrenderdoc/Windows/ConstantBufferPreviewer.h b/qrenderdoc/Windows/ConstantBufferPreviewer.h index 9c6380e49..e5b282cf2 100644 --- a/qrenderdoc/Windows/ConstantBufferPreviewer.h +++ b/qrenderdoc/Windows/ConstantBufferPreviewer.h @@ -81,11 +81,6 @@ private: void addVariables(RDTreeWidgetItem *root, const rdcarray &vars); void setVariables(const rdcarray &vars); - rdcarray m_Vars; - - bool updateVariables(RDTreeWidgetItem *root, const rdcarray &prevVars, - const rdcarray &newVars); - void updateLabels(); static QList m_Previews; diff --git a/qrenderdoc/Windows/ResourceInspector.cpp b/qrenderdoc/Windows/ResourceInspector.cpp index 9fc1f6f73..897a59a78 100644 --- a/qrenderdoc/Windows/ResourceInspector.cpp +++ b/qrenderdoc/Windows/ResourceInspector.cpp @@ -201,6 +201,9 @@ void ResourceInspector::Inspect(ResourceId id) if(m_Resource == id) return; + if(m_Resource != ResourceId()) + ui->initChunks->saveInternalExpansion(ToQStr(m_Resource), 0); + m_Resource = id; ui->viewContents->setVisible(m_Ctx.GetTexture(id) || m_Ctx.GetBuffer(id)); @@ -325,6 +328,9 @@ void ResourceInspector::Inspect(ResourceId id) } ui->initChunks->setUpdatesEnabled(true); + + if(m_Resource != ResourceId()) + ui->initChunks->applyInternalExpansion(ToQStr(m_Resource), 0); } void ResourceInspector::OnCaptureLoaded() @@ -347,6 +353,7 @@ void ResourceInspector::OnCaptureClosed() m_ResourceModel->reset(); ui->initChunks->clear(); + ui->initChunks->clearInternalExpansions(); ui->relatedResources->clear(); ui->resourceUsage->clear();