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.
This commit is contained in:
baldurk
2018-08-06 13:48:58 +01:00
parent 74528c4d15
commit 9e3147d021
7 changed files with 51 additions and 69 deletions
@@ -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];
+2
View File
@@ -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);
+7
View File
@@ -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<rdcstr> calls)
+2
View File
@@ -57,6 +57,8 @@ private:
Ui::APIInspector *ui;
ICaptureContext &m_Ctx;
uint32_t m_EventID;
void addCallstack(rdcarray<rdcstr> calls);
void fillAPIView();
};
+28 -64
View File
@@ -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<ShaderVariable> 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<ShaderVariable> 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<ShaderVariable> &prevVars,
const rdcarray<ShaderVariable> &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<ShaderVariable> &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);
@@ -81,11 +81,6 @@ private:
void addVariables(RDTreeWidgetItem *root, const rdcarray<ShaderVariable> &vars);
void setVariables(const rdcarray<ShaderVariable> &vars);
rdcarray<ShaderVariable> m_Vars;
bool updateVariables(RDTreeWidgetItem *root, const rdcarray<ShaderVariable> &prevVars,
const rdcarray<ShaderVariable> &newVars);
void updateLabels();
static QList<ConstantBufferPreviewer *> m_Previews;
+7
View File
@@ -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();