From 9bef60d6c3be2c6204c933bc325cf9d6e360f2b4 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 19 Jan 2026 13:34:58 +0000 Subject: [PATCH] Display source variables mapped to OpUndef as `` * Undefined values are still 0xccccccccc, since that value can propagate through operations. But source variables mapped directly to an OpUndef are displayed in a more semantically clear way. --- qrenderdoc/Windows/ShaderViewer.cpp | 69 ++++++++++++++----- qrenderdoc/Windows/ShaderViewer.h | 12 ++-- renderdoc/api/replay/shader_types.h | 7 ++ .../shaders/spirv/spirv_debug_setup.cpp | 19 ++++- 4 files changed, 82 insertions(+), 25 deletions(-) diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index d4a9a4427..91e915347 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -3415,7 +3415,8 @@ QString ShaderViewer::getRegNames(const RDTreeWidgetItem *item, uint32_t swizzle } const RDTreeWidgetItem *ShaderViewer::evaluateVar(const RDTreeWidgetItem *item, uint32_t swizzle, - ShaderVariable *var) + ShaderVariable *var, + SourceVariableMapping *mappingPtr) { VariableTag tag = item->tag().value(); @@ -3528,13 +3529,16 @@ const RDTreeWidgetItem *ShaderViewer::evaluateVar(const RDTreeWidgetItem *item, for(int i = 0; i < item->childCount(); i++) { ret.members.push_back(ShaderVariable()); - if(!evaluateVar(item->child(i), ~0U, &ret.members.back())) + if(!evaluateVar(item->child(i), ~0U, &ret.members.back(), NULL)) return NULL; } return item; } + if(mappingPtr) + *mappingPtr = mapping; + if(mapping.variables.empty()) return NULL; @@ -3575,6 +3579,9 @@ const RDTreeWidgetItem *ShaderViewer::evaluateVar(const RDTreeWidgetItem *item, } } + if(mappingPtr) + *mappingPtr = mapping; + ShaderVariable &ret = *var; ret.name = mapping.name; ret.flags |= ShaderVariableFlags::RowMajorMatrix; @@ -3649,14 +3656,15 @@ const RDTreeWidgetItem *ShaderViewer::evaluateVar(const RDTreeWidgetItem *item, } const RDTreeWidgetItem *ShaderViewer::getVarFromPath(const rdcstr &path, const RDTreeWidgetItem *root, - ShaderVariable *var, uint32_t *swizzlePtr) + ShaderVariable *var, uint32_t *swizzlePtr, + SourceVariableMapping *mappingPtr) { VariableTag tag = root->tag().value(); // if the path is an exact match, return the evaluation directly if(tag.absoluteRefPath == path) { - return evaluateVar(root, ~0U, var); + return evaluateVar(root, ~0U, var, mappingPtr); } for(int i = 0; i < root->childCount(); i++) @@ -3672,7 +3680,7 @@ const RDTreeWidgetItem *ShaderViewer::getVarFromPath(const rdcstr &path, const R // if the path is an exact match, return the evaluation directly if(tag.absoluteRefPath == path) { - return evaluateVar(child, ~0U, var); + return evaluateVar(child, ~0U, var, mappingPtr); } // after the common prefix, if the next value is . or [ then this is the next child, so recurse. @@ -3684,7 +3692,7 @@ const RDTreeWidgetItem *ShaderViewer::getVarFromPath(const rdcstr &path, const R if(common == tag.absoluteRefPath && (path[tag.absoluteRefPath.size()] == '.' || path[tag.absoluteRefPath.size()] == '[')) { - return getVarFromPath(path, child, var, swizzlePtr); + return getVarFromPath(path, child, var, swizzlePtr, mappingPtr); } } @@ -3726,7 +3734,7 @@ const RDTreeWidgetItem *ShaderViewer::getVarFromPath(const rdcstr &path, const R if(swizzlePtr) *swizzlePtr = swizzleMask; - return evaluateVar(root, swizzleMask, var); + return evaluateVar(root, swizzleMask, var, mappingPtr); } } @@ -3734,7 +3742,8 @@ const RDTreeWidgetItem *ShaderViewer::getVarFromPath(const rdcstr &path, const R } const RDTreeWidgetItem *ShaderViewer::getVarFromPath(const rdcstr &path, ShaderVariable *var, - uint32_t *swizzle) + uint32_t *swizzle, + SourceVariableMapping *mapping) { if(!m_Trace || m_States.empty()) return NULL; @@ -3765,7 +3774,7 @@ const RDTreeWidgetItem *ShaderViewer::getVarFromPath(const rdcstr &path, ShaderV if(item->text(0) == root) { - const RDTreeWidgetItem *ret = getVarFromPath(path, item, var, swizzle); + const RDTreeWidgetItem *ret = getVarFromPath(path, item, var, swizzle, mapping); if(ret) return ret; } @@ -3781,7 +3790,7 @@ const RDTreeWidgetItem *ShaderViewer::getVarFromPath(const rdcstr &path, ShaderV VariableTag tag = item->tag().value(); const RDTreeWidgetItem *ret = - getVarFromPath(tag.absoluteRefPath + "." + path, child, var, swizzle); + getVarFromPath(tag.absoluteRefPath + "." + path, child, var, swizzle, mapping); if(ret) return ret; } @@ -4515,6 +4524,7 @@ void ShaderViewer::markWatchStale(RDTreeWidgetItem *item) bool ShaderViewer::updateWatchVariable(RDTreeWidgetItem *watchItem, const RDTreeWidgetItem *varItem, const rdcstr &path, uint32_t swizzle, + const SourceVariableMapping &mapping, const ShaderVariable &var, QChar regcast) { if(!var.members.empty()) @@ -4577,7 +4587,7 @@ bool ShaderViewer::updateWatchVariable(RDTreeWidgetItem *watchItem, const RDTree rdcstr sep = var.members[i].name[0] == '[' ? "" : "."; updateWatchVariable(watchItem->child(idx), varItem->child(i), - path + sep + var.members[i].name, ~0U, var.members[i], regcast); + path + sep + var.members[i].name, ~0U, mapping, var.members[i], regcast); } // any children that weren't marked as valid are now stale @@ -4644,7 +4654,8 @@ bool ShaderViewer::updateWatchVariable(RDTreeWidgetItem *watchItem, const RDTree QVariant(), }); - updateWatchVariable(item, varItem->child(r), path + ".row" + ToStr(r), ~0U, rowVar, regcast); + updateWatchVariable(item, varItem->child(r), path + ".row" + ToStr(r), ~0U, mapping, rowVar, + regcast); item->setText(1, getRegNames(varItem, ~0U, r)); item->setTag(QVariant()); watchItem->addChild(item); @@ -4787,8 +4798,16 @@ bool ShaderViewer::updateWatchVariable(RDTreeWidgetItem *watchItem, const RDTree val += lit(", "); } + QString typeString = TypeString(var); + + if(mapping.type != VarType::Unknown && mapping.undefinedValue) + { + typeString = lit("-"); + val = tr(""); + } + watchItem->setText(1, getRegNames(varItem, swizzle)); - watchItem->setText(2, TypeString(var)); + watchItem->setText(2, typeString); if(!swatchColor.isValid()) { @@ -4844,12 +4863,13 @@ void ShaderViewer::updateWatchVariables() if(!match.captured(2).isEmpty()) regcast = match.captured(2)[1]; + SourceVariableMapping mapping; ShaderVariable var; uint32_t swizzle = ~0U; - const RDTreeWidgetItem *varItem = getVarFromPath(path, &var, &swizzle); + const RDTreeWidgetItem *varItem = getVarFromPath(path, &var, &swizzle, &mapping); if(varItem) { - if(updateWatchVariable(item, varItem, path, swizzle, var, regcast)) + if(updateWatchVariable(item, varItem, path, swizzle, mapping, var, regcast)) continue; error = tr("Couldn't evaluate watch for '%1'").arg(expr); @@ -5181,6 +5201,12 @@ RDTreeWidgetItem *ShaderViewer::makeSourceVariableNode(const SourceVariableMappi } } + if(l.undefinedValue) + { + typeName = lit("-"); + value = tr(""); + } + RDTreeWidgetItem *node = new RDTreeWidgetItem({localName, QString(), typeName, value}); for(RDTreeWidgetItem *c : children) @@ -6099,8 +6125,9 @@ void ShaderViewer::updateVariableTooltip() return; ShaderVariable var; + SourceVariableMapping mapping; - if(!getVarFromPath(m_TooltipVarPath, &var)) + if(!getVarFromPath(m_TooltipVarPath, &var, NULL, &mapping)) return; if(var.type != VarType::Unknown) @@ -6125,6 +6152,9 @@ void ShaderViewer::updateVariableTooltip() tooltip += lit(""); } + if(mapping.type != VarType::Unknown && mapping.undefinedValue) + tooltip = tr("%1: ").arg(var.name); + QToolTip::showText(m_TooltipPos, tooltip); return; } @@ -6141,8 +6171,13 @@ void ShaderViewer::updateVariableTooltip() } else if(!var.members.empty()) { + QString tooltip = tr("%1: { ... }").arg(var.name); + + if(mapping.type != VarType::Unknown && mapping.undefinedValue) + tooltip = tr("%1: ").arg(var.name); + // other structs - QToolTip::showText(m_TooltipPos, lit("{ ... }")); + QToolTip::showText(m_TooltipPos, tooltip); return; } diff --git a/qrenderdoc/Windows/ShaderViewer.h b/qrenderdoc/Windows/ShaderViewer.h index 7ee1868c9..f2053be45 100644 --- a/qrenderdoc/Windows/ShaderViewer.h +++ b/qrenderdoc/Windows/ShaderViewer.h @@ -402,8 +402,8 @@ private: void updateDebugState(); void markWatchStale(RDTreeWidgetItem *item); bool updateWatchVariable(RDTreeWidgetItem *watchItem, const RDTreeWidgetItem *varItem, - const rdcstr &path, uint32_t swizzle, const ShaderVariable &var, - QChar regcast); + const rdcstr &path, uint32_t swizzle, const SourceVariableMapping &mapping, + const ShaderVariable &var, QChar regcast); void updateWatchVariables(); void updateAccessedResources(); @@ -452,9 +452,11 @@ private: QString getRegNames(const RDTreeWidgetItem *item, uint32_t swizzle, uint32_t child = ~0U); const RDTreeWidgetItem *evaluateVar(const RDTreeWidgetItem *item, uint32_t swizzle, - ShaderVariable *var); + ShaderVariable *var, SourceVariableMapping *mapping); const RDTreeWidgetItem *getVarFromPath(const rdcstr &path, const RDTreeWidgetItem *root, - ShaderVariable *var, uint32_t *swizzle); + ShaderVariable *var, uint32_t *swizzle, + SourceVariableMapping *mapping); const RDTreeWidgetItem *getVarFromPath(const rdcstr &path, ShaderVariable *var = NULL, - uint32_t *swizzle = NULL); + uint32_t *swizzle = NULL, + SourceVariableMapping *mapping = NULL); }; diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index acc3760ed..bd8f5f1a8 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -676,6 +676,13 @@ struct SourceVariableMapping )"); VarType type = VarType::Unknown; + DOCUMENT(R"(A flag indicating if this mapping indicates an undefined value - the meaning of which +is compiler defined but may mean either uninitialised data, unassigned values, or optimised away values. + +:type: bool +)"); + bool undefinedValue = false; + DOCUMENT(R"(The number of rows in this variable - 1 for vectors, >1 for matrices. :type: int diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index c260722b7..26c29a24b 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -2626,11 +2626,24 @@ void Debugger::FillDebugSourceVars(rdcarray &instInfo) co if(n->children.empty()) { - RDCASSERTNOTEQUAL(n->rows * n->columns, 0); - for(uint32_t c = 0; c < n->rows * n->columns; ++c) + ConstIter it = GetID(n->debugVar); + + if(it.opcode() == Op::Undef) { + sourceVar.rows = sourceVar.columns = 1; + sourceVar.undefinedValue = true; + sourceVar.variables.push_back(DebugVariableReference( - DebugVariableType::Variable, GetRawName(n->debugVar) + n->debugVarSuffix, c)); + DebugVariableType::Variable, GetRawName(n->debugVar) + n->debugVarSuffix, 0)); + } + else + { + RDCASSERTNOTEQUAL(n->rows * n->columns, 0); + for(uint32_t c = 0; c < n->rows * n->columns; ++c) + { + sourceVar.variables.push_back(DebugVariableReference( + DebugVariableType::Variable, GetRawName(n->debugVar) + n->debugVarSuffix, c)); + } } } else