From 1761f5ab36322b4cdbefb075ade07bb52969efe8 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 8 Jun 2018 19:05:44 +0100 Subject: [PATCH] Highlight variables/registers that have changed --- qrenderdoc/Code/pyrenderdoc/renderdoc.i | 1 + qrenderdoc/Widgets/Extended/RDTreeWidget.h | 2 + qrenderdoc/Windows/ShaderViewer.cpp | 81 ++++++++++++++++++++ renderdoc/api/replay/shader_types.h | 3 + renderdoc/driver/shaders/dxbc/dxbc_debug.cpp | 40 +++++++++- renderdoc/driver/shaders/dxbc/dxbc_debug.h | 2 +- renderdoc/replay/renderdoc_serialise.inl | 3 +- 7 files changed, 126 insertions(+), 6 deletions(-) diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index e67196f66..6a411234b 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -265,6 +265,7 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderResource) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderSampler) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderSourceFile) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderVariable) +TEMPLATE_ARRAY_INSTANTIATE(rdcarray, RegisterRange) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, LocalVariableMapping) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, SigParameter) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, TextureDescription) diff --git a/qrenderdoc/Widgets/Extended/RDTreeWidget.h b/qrenderdoc/Widgets/Extended/RDTreeWidget.h index edfad33de..9b2cfb4fb 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeWidget.h +++ b/qrenderdoc/Widgets/Extended/RDTreeWidget.h @@ -97,6 +97,8 @@ public: m_fore = foreground; dataChanged(0, Qt::ForegroundRole); } + inline QBrush background() { return m_back; } + inline QBrush foreground() { return m_fore; } inline QString text(int column) const { return m_text[column].toString(); } inline void setText(int column, const QVariant &value) { diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index 683340327..26c5dbbee 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -1470,6 +1470,11 @@ void ShaderViewer::combineStructures(RDTreeWidgetItem *root) if(!isArray) item->setText(0, item->text(0).mid(sepIndex + 1)); parent->addChild(item); + + if(item->background().color().isValid()) + parent->setBackground(item->background()); + if(item->foreground().color().isValid()) + parent->setForeground(item->foreground()); } // recurse and combine members of this object if a struct @@ -1752,11 +1757,22 @@ void ShaderViewer::updateDebugging() else if(l.type == VarType::Double) typeName = lit("double"); + bool modified = false; + if(l.registers[0].type == RegisterType::IndexedTemporary) { typeName += lit("[]"); regNames = QFormatStr("x%1").arg(l.registers[0].index); + + for(const RegisterRange &mr : state.modified) + { + if(mr.type == RegisterType::IndexedTemporary && mr.index == l.registers[0].index) + { + modified = true; + break; + } + } } else { @@ -1770,6 +1786,15 @@ void ShaderViewer::updateDebugging() const RegisterRange &r = l.registers[i]; const ShaderVariable *var = NULL; + for(const RegisterRange &mr : state.modified) + { + if(mr.type == r.type && mr.index == r.index && mr.component == r.component) + { + modified = true; + break; + } + } + if(!value.isEmpty()) value += lit(", "); if(!regNames.isEmpty()) @@ -1832,6 +1857,9 @@ void ShaderViewer::updateDebugging() RDTreeWidgetItem *node = new RDTreeWidgetItem({localName, regNames, typeName, value}); + if(modified) + node->setForegroundColor(QColor(Qt::red)); + if(l.registers[0].type == RegisterType::IndexedTemporary) { const ShaderVariable *var = NULL; @@ -1891,16 +1919,53 @@ void ShaderViewer::updateDebugging() node->setText(2, stringRep(state.registers[i], false)); node->setTag(QVariant::fromValue(VariableTag(VariableCategory::Temporaries, i))); + + bool modified = false; + + for(const RegisterRange &mr : state.modified) + { + if(mr.type == RegisterType::Temporary && mr.index == i) + { + modified = true; + break; + } + } + + if(modified) + node->setForegroundColor(QColor(Qt::red)); + else + node->setForeground(QBrush()); } for(int i = 0; i < state.indexableTemps.count(); i++) { RDTreeWidgetItem *node = ui->registers->topLevelItem(v++); + bool modified = false; + + for(const RegisterRange &mr : state.modified) + { + if(mr.type == RegisterType::IndexedTemporary && mr.index == i) + { + modified = true; + break; + } + } + + if(modified) + node->setForegroundColor(QColor(Qt::red)); + else + node->setForeground(QBrush()); + for(int t = 0; t < state.indexableTemps[i].members.count(); t++) { RDTreeWidgetItem *child = node->child(t); + if(modified) + child->setForegroundColor(QColor(Qt::red)); + else + child->setForeground(QBrush()); + child->setText(2, stringRep(state.indexableTemps[i].members[t], false)); child->setTag(QVariant::fromValue(VariableTag(VariableCategory::IndexTemporaries, t, i))); } @@ -1912,6 +1977,22 @@ void ShaderViewer::updateDebugging() node->setText(2, stringRep(state.outputs[i], false)); node->setTag(QVariant::fromValue(VariableTag(VariableCategory::Outputs, i))); + + bool modified = false; + + for(const RegisterRange &mr : state.modified) + { + if(mr.type == RegisterType::Output && mr.index == i) + { + modified = true; + break; + } + } + + if(modified) + node->setForegroundColor(QColor(Qt::red)); + else + node->setForeground(QBrush()); } ui->registers->endUpdate(); diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index fb27de22e..6066c189d 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -418,6 +418,9 @@ to which registers, and their type )"); rdcarray locals; + DOCUMENT("A list of registers that were modified."); + rdcarray modified; + DOCUMENT(R"(The next instruction to be executed after this state. The initial state before any shader execution happened will have ``nextInstruction == 0``. )"); diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp index b7bea3b0b..a9088cece 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp @@ -587,7 +587,7 @@ bool State::Finished() const return dxbc && (done || nextInstruction >= (int)dxbc->GetNumInstructions()); } -void State::AssignValue(ShaderVariable &dst, uint32_t dstIndex, const ShaderVariable &src, +bool State::AssignValue(ShaderVariable &dst, uint32_t dstIndex, const ShaderVariable &src, uint32_t srcIndex) { if(src.type == VarType::Float) @@ -603,7 +603,11 @@ void State::AssignValue(ShaderVariable &dst, uint32_t dstIndex, const ShaderVari flags |= ShaderEvents::GeneratedNanOrInf; } + bool ret = (dst.value.uv[dstIndex] != src.value.uv[srcIndex]); + dst.value.uv[dstIndex] = src.value.uv[srcIndex]; + + return ret; } void State::SetDst(const ASMOperand &dstoper, const ASMOperation &op, const ShaderVariable &val) @@ -629,10 +633,14 @@ void State::SetDst(const ASMOperand &dstoper, const ASMOperation &op, const Shad } } + RegisterRange range; + range.index = uint16_t(indices[0]); + switch(dstoper.type) { case TYPE_TEMP: { + range.type = RegisterType::Temporary; RDCASSERT(indices[0] < (uint32_t)registers.size()); if(indices[0] < (uint32_t)registers.size()) v = ®isters[(size_t)indices[0]]; @@ -640,6 +648,7 @@ void State::SetDst(const ASMOperand &dstoper, const ASMOperation &op, const Shad } case TYPE_INDEXABLE_TEMP: { + range.type = RegisterType::IndexedTemporary; RDCASSERT(dstoper.indices.size() == 2); if(dstoper.indices.size() == 2) @@ -658,6 +667,7 @@ void State::SetDst(const ASMOperand &dstoper, const ASMOperation &op, const Shad } case TYPE_OUTPUT: { + range.type = RegisterType::Output; RDCASSERT(indices[0] < (uint32_t)outputs.size()); if(indices[0] < (uint32_t)outputs.size()) v = &outputs[(size_t)indices[0]]; @@ -772,7 +782,13 @@ void State::SetDst(const ASMOperand &dstoper, const ASMOperation &op, const Shad { RDCASSERT(dstoper.comps[0] != 0xff); - AssignValue(*v, dstoper.comps[0], right, 0); + bool changed = AssignValue(*v, dstoper.comps[0], right, 0); + + if(changed && range.type != RegisterType::Undefined) + { + range.component = dstoper.comps[0]; + modified.push_back(range); + } } else { @@ -783,13 +799,27 @@ void State::SetDst(const ASMOperand &dstoper, const ASMOperation &op, const Shad if(dstoper.comps[i] != 0xff) { RDCASSERT(dstoper.comps[i] < v->columns); - AssignValue(*v, dstoper.comps[i], right, dstoper.comps[i]); + bool changed = AssignValue(*v, dstoper.comps[i], right, dstoper.comps[i]); compsWritten++; + + if(changed && range.type != RegisterType::Undefined) + { + range.component = dstoper.comps[i]; + modified.push_back(range); + } } } if(compsWritten == 0) - AssignValue(*v, 0, right, 0); + { + bool changed = AssignValue(*v, 0, right, 0); + + if(changed && range.type != RegisterType::Undefined) + { + range.component = 0; + modified.push_back(range); + } + } } } } @@ -1167,6 +1197,8 @@ State State::GetNext(GlobalState &global, State quad[4]) const { State s = *this; + s.modified.clear(); + if(s.nextInstruction >= s.dxbc->GetNumInstructions()) return s; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.h b/renderdoc/driver/shaders/dxbc/dxbc_debug.h index 92ea5f698..ec0061b84 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.h @@ -164,7 +164,7 @@ private: bool done; // validates assignment for generation of non-normal values - void AssignValue(ShaderVariable &dst, uint32_t dstIndex, const ShaderVariable &src, + bool AssignValue(ShaderVariable &dst, uint32_t dstIndex, const ShaderVariable &src, uint32_t srcIndex); // sets the destination operand by looking up in the register // file and applying any masking or swizzling diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 55a63ae1f..bda26c436 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -385,10 +385,11 @@ void DoSerialise(SerialiserType &ser, ShaderDebugState &el) SERIALISE_MEMBER(outputs); SERIALISE_MEMBER(indexableTemps); SERIALISE_MEMBER(locals); + SERIALISE_MEMBER(modified); SERIALISE_MEMBER(nextInstruction); SERIALISE_MEMBER(flags); - SIZE_CHECK(72); + SIZE_CHECK(88); } template