mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-24 23:46:41 +00:00
SPIRV debug mapping updates to handle multiple overlapping mappings
Capture the mappings into a type usage tree Update elements of the tree as overlapping mappings are encountered, sub-elements of a previously mapped variable i.e. single component of a vector, single array element, member in a structure. After processing all mappings convert the finalized type usage tree into source variable mappings.
This commit is contained in:
committed by
Baldur Karlsson
parent
6532eb65f0
commit
5cfff389fe
@@ -1561,6 +1561,7 @@ void Debugger::FillDebugSourceVars(rdcarray<InstructionSourceInfo> &instInfo)
|
||||
// track which mappings we've processed, so if the same variable has mappings in multiple scopes
|
||||
// we only pick the innermost.
|
||||
rdcarray<LocalMapping> processed;
|
||||
rdcarray<Id> sourceVars;
|
||||
|
||||
// capture the scopes upwards (from child to parent)
|
||||
rdcarray<const ScopeData *> scopes;
|
||||
@@ -1611,103 +1612,278 @@ void Debugger::FillDebugSourceVars(rdcarray<InstructionSourceInfo> &instInfo)
|
||||
if(supercede)
|
||||
continue;
|
||||
|
||||
const LocalData &l = m_DebugInfo.locals[mapping.sourceVar];
|
||||
processed.push_back(mapping);
|
||||
Id sourceVar = mapping.sourceVar;
|
||||
if(!sourceVars.contains(mapping.sourceVar))
|
||||
sourceVars.push_back(mapping.sourceVar);
|
||||
}
|
||||
}
|
||||
|
||||
// Converting debug variable mappings to SourceVariableMapping is a two phase algorithm.
|
||||
|
||||
// Phase One
|
||||
// For each source variable, repeatedly apply the debug variable mappings.
|
||||
// This debug variable usage is tracked in a tree-like structure built using DebugVarNode
|
||||
// elements.
|
||||
// As each mapping is applied, the new mapping can fully or partially override the
|
||||
// existing mapping. When an existing mapping is:
|
||||
// - fully overrideen: any sub-elements of that mapping are cleared
|
||||
// i.e. assigning a vector, array, structure
|
||||
// - partially overriden: the existing mapping is expanded into its sub-elements which are
|
||||
// mapped to the current mapping and then the new mapping is set to its corresponding
|
||||
// elements i.e. y-component in a vector, member in a structure, a single array element
|
||||
// The DebugVarNode member "emitSourceVar" determines if the DebugVar mapping should be
|
||||
// converted to a source variable mapping.
|
||||
|
||||
// Phase Two
|
||||
// The DebugVarNode tree is walked to find the nodes which have "emitSourceVar" set to true and
|
||||
// then those nodes are converted to SourceVariableMapping
|
||||
|
||||
struct DebugVarNode
|
||||
{
|
||||
rdcarray<DebugVarNode> children;
|
||||
Id debugVar;
|
||||
rdcstr name;
|
||||
rdcstr debugVarSuffix;
|
||||
VarType type = VarType::Unknown;
|
||||
uint32_t rows = 0;
|
||||
uint32_t columns = 0;
|
||||
uint32_t debugVarComponent = 0;
|
||||
uint32_t offset = 0;
|
||||
bool emitSourceVar = false;
|
||||
};
|
||||
|
||||
::std::map<Id, DebugVarNode> roots;
|
||||
|
||||
// Phase One: generate the DebugVarNode tree by repeatedly apply debug variables updating
|
||||
// existing mappings with later mappings
|
||||
for(size_t sv = 0; sv < sourceVars.size(); ++sv)
|
||||
{
|
||||
Id sourceVarId = sourceVars[sv];
|
||||
const LocalData &l = m_DebugInfo.locals[sourceVarId];
|
||||
|
||||
// Convert processed mappings into a usage map
|
||||
for(size_t m = 0; m < processed.size(); ++m)
|
||||
{
|
||||
const LocalMapping &mapping = processed[m];
|
||||
if(mapping.sourceVar != sourceVarId)
|
||||
continue;
|
||||
|
||||
const TypeData *typeWalk = l.type;
|
||||
DebugVarNode *usage = &roots[sourceVarId];
|
||||
if(usage->name.isEmpty())
|
||||
{
|
||||
usage->name = l.name;
|
||||
usage->rows = 1U;
|
||||
usage->columns = 1U;
|
||||
}
|
||||
|
||||
// if it doesn't have indexes this is simple, set up a 1:1 map
|
||||
if(mapping.indexes.isEmpty())
|
||||
{
|
||||
SourceVariableMapping sourceVar;
|
||||
|
||||
const TypeData *typeWalk = l.type;
|
||||
|
||||
sourceVar.name = l.name;
|
||||
sourceVar.offset = 0;
|
||||
sourceVar.rows = 1U;
|
||||
sourceVar.columns = 1U;
|
||||
|
||||
uint32_t rows = 1;
|
||||
uint32_t columns = 1;
|
||||
// skip past any pointer types to get the 'real' type that we'll see
|
||||
while(typeWalk && typeWalk->baseType != Id() && typeWalk->type == VarType::GPUPointer)
|
||||
typeWalk = &m_DebugInfo.types[typeWalk->baseType];
|
||||
|
||||
const uint32_t arrayDimension = typeWalk->arrayDimensions.size();
|
||||
if(arrayDimension > 0)
|
||||
{
|
||||
// walk down until we get to a scalar type, if we get there. This means arrays of
|
||||
// basic types will get the right type
|
||||
while(typeWalk && typeWalk->baseType != Id() && typeWalk->type == VarType::Unknown)
|
||||
typeWalk = &m_DebugInfo.types[typeWalk->baseType];
|
||||
|
||||
usage->type = typeWalk->type;
|
||||
}
|
||||
else if(!typeWalk->structMembers.empty())
|
||||
{
|
||||
usage->type = typeWalk->type;
|
||||
}
|
||||
if(typeWalk->matSize != 0)
|
||||
{
|
||||
const TypeData &vec = m_DebugInfo.types[typeWalk->baseType];
|
||||
const TypeData &scalar = m_DebugInfo.types[vec.baseType];
|
||||
|
||||
sourceVar.type = scalar.type;
|
||||
usage->type = scalar.type;
|
||||
|
||||
if(typeWalk->colMajorMat)
|
||||
{
|
||||
sourceVar.rows = RDCMAX(1U, vec.vecSize);
|
||||
sourceVar.columns = RDCMAX(1U, typeWalk->matSize);
|
||||
rows = RDCMAX(1U, vec.vecSize);
|
||||
columns = RDCMAX(1U, typeWalk->matSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceVar.rows = RDCMAX(1U, typeWalk->matSize);
|
||||
sourceVar.columns = RDCMAX(1U, vec.vecSize);
|
||||
columns = RDCMAX(1U, vec.vecSize);
|
||||
rows = RDCMAX(1U, typeWalk->matSize);
|
||||
}
|
||||
}
|
||||
else if(typeWalk->vecSize != 0)
|
||||
{
|
||||
const TypeData &scalar = m_DebugInfo.types[typeWalk->baseType];
|
||||
|
||||
sourceVar.type = scalar.type;
|
||||
sourceVar.columns = RDCMAX(1U, typeWalk->vecSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// walk down until we get to a scalar type, if we get there. This means arrays of basic
|
||||
// types will get the right type
|
||||
while(typeWalk && typeWalk->baseType != Id() && typeWalk->type == VarType::Unknown)
|
||||
typeWalk = &m_DebugInfo.types[typeWalk->baseType];
|
||||
|
||||
sourceVar.type = typeWalk->type;
|
||||
|
||||
// anything else we treat as a struct
|
||||
if(sourceVar.type == VarType::Unknown)
|
||||
sourceVar.type = VarType::Struct;
|
||||
usage->type = scalar.type;
|
||||
columns = RDCMAX(1U, typeWalk->vecSize);
|
||||
}
|
||||
|
||||
for(uint32_t x = 0; x < sourceVar.rows * sourceVar.columns; x++)
|
||||
sourceVar.variables.push_back(DebugVariableReference(DebugVariableType::Variable,
|
||||
GetRawName(mapping.debugVar), x));
|
||||
|
||||
i.sourceVars.push_back(sourceVar);
|
||||
usage->debugVar = mapping.debugVar;
|
||||
// Remove any child mappings : this mapping covers everything
|
||||
usage->children.clear();
|
||||
usage->emitSourceVar = true;
|
||||
usage->rows = rows;
|
||||
usage->columns = columns;
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceVariableMapping sourceVar;
|
||||
|
||||
rdcarray<uint32_t> indexes = mapping.indexes;
|
||||
|
||||
const TypeData *typeWalk = l.type;
|
||||
|
||||
sourceVar.name = l.name;
|
||||
sourceVar.offset = 0;
|
||||
sourceVar.rows = 1U;
|
||||
sourceVar.columns = 1U;
|
||||
|
||||
// walk any aggregate types
|
||||
while(!indexes.empty())
|
||||
{
|
||||
if(typeWalk->arrayDimensions.size() > 0)
|
||||
uint32_t idx = ~0U;
|
||||
const TypeData *childType = NULL;
|
||||
const uint32_t arrayDimension = typeWalk->arrayDimensions.size();
|
||||
if(arrayDimension > 0)
|
||||
{
|
||||
const rdcarray<uint32_t> &dims = typeWalk->arrayDimensions;
|
||||
uint32_t numIdxs = (uint32_t)indexes.size();
|
||||
for(size_t a = 0; a < RDCMIN((uint32_t)typeWalk->arrayDimensions.size(), numIdxs); a++)
|
||||
childType = &m_DebugInfo.types[typeWalk->baseType];
|
||||
uint32_t childRows = 1U;
|
||||
uint32_t childColumns = 1U;
|
||||
VarType elementType = childType->type;
|
||||
if(childType->matSize != 0)
|
||||
{
|
||||
sourceVar.name += StringFormat::Fmt("[%u]", indexes.back());
|
||||
indexes.pop_back();
|
||||
}
|
||||
const TypeData &vec = m_DebugInfo.types[childType->baseType];
|
||||
const TypeData &scalar = m_DebugInfo.types[vec.baseType];
|
||||
|
||||
typeWalk = &m_DebugInfo.types[typeWalk->baseType];
|
||||
elementType = scalar.type;
|
||||
if(childType->colMajorMat)
|
||||
{
|
||||
childRows = RDCMAX(1U, vec.vecSize);
|
||||
childColumns = RDCMAX(1U, childType->matSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
childColumns = RDCMAX(1U, vec.vecSize);
|
||||
childRows = RDCMAX(1U, childType->matSize);
|
||||
}
|
||||
}
|
||||
else if(childType->vecSize != 0)
|
||||
{
|
||||
const TypeData &scalar = m_DebugInfo.types[childType->baseType];
|
||||
uint32_t vecColumns = RDCMAX(1U, childType->vecSize);
|
||||
|
||||
elementType = scalar.type;
|
||||
|
||||
childRows = 1U;
|
||||
childColumns = vecColumns;
|
||||
}
|
||||
const uint32_t countDims = RDCMIN(arrayDimension, numIdxs);
|
||||
// handle N dimensional arrays
|
||||
for(uint32_t d = 0; d < countDims; ++d)
|
||||
{
|
||||
idx = indexes[0];
|
||||
indexes.erase(0);
|
||||
uint32_t rows = dims[d];
|
||||
usage->rows = rows;
|
||||
usage->columns = 1U;
|
||||
// Expand the node if required
|
||||
if(usage->children.isEmpty())
|
||||
{
|
||||
usage->children.resize(rows);
|
||||
for(uint32_t x = 0; x < rows; x++)
|
||||
{
|
||||
usage->children[x].debugVar = usage->debugVar;
|
||||
rdcstr suffix = StringFormat::Fmt("[%u]", x);
|
||||
usage->children[x].debugVarSuffix = usage->debugVarSuffix + suffix;
|
||||
usage->children[x].name = usage->name + suffix;
|
||||
usage->children[x].type = elementType;
|
||||
usage->children[x].rows = childRows;
|
||||
usage->children[x].columns = childColumns;
|
||||
usage->children[x].offset = x;
|
||||
}
|
||||
}
|
||||
// if the whole node was displayed : display the sub-elements
|
||||
if(usage->emitSourceVar)
|
||||
{
|
||||
for(uint32_t x = 0; x < rows; x++)
|
||||
usage->children[x].emitSourceVar = true;
|
||||
usage->emitSourceVar = false;
|
||||
}
|
||||
usage = &usage->children[idx];
|
||||
usage->type = childType->type;
|
||||
typeWalk = childType;
|
||||
}
|
||||
}
|
||||
else if(!typeWalk->structMembers.empty())
|
||||
{
|
||||
uint32_t idx = indexes.back();
|
||||
indexes.pop_back();
|
||||
idx = indexes[0];
|
||||
indexes.erase(0);
|
||||
childType = &m_DebugInfo.types[typeWalk->structMembers[idx].second];
|
||||
uint32_t rows = typeWalk->structMembers.size();
|
||||
usage->rows = rows;
|
||||
usage->columns = 1U;
|
||||
// Expand the node if required
|
||||
if(usage->children.isEmpty())
|
||||
{
|
||||
usage->children.resize(rows);
|
||||
for(uint32_t x = 0; x < rows; x++)
|
||||
{
|
||||
rdcstr suffix = StringFormat::Fmt(".%s", typeWalk->structMembers[x].first.c_str());
|
||||
usage->children[x].debugVar = usage->debugVar;
|
||||
usage->children[x].debugVarSuffix = usage->debugVarSuffix + suffix;
|
||||
usage->children[x].name = usage->name + suffix;
|
||||
usage->children[x].offset = x;
|
||||
uint32_t memberRows = 1U;
|
||||
uint32_t memberColumns = 1U;
|
||||
const TypeData *memberType = &m_DebugInfo.types[typeWalk->structMembers[x].second];
|
||||
VarType elementType = memberType->type;
|
||||
if(memberType->matSize != 0)
|
||||
{
|
||||
const TypeData &vec = m_DebugInfo.types[memberType->baseType];
|
||||
const TypeData &scalar = m_DebugInfo.types[vec.baseType];
|
||||
|
||||
sourceVar.name += StringFormat::Fmt(".%s", typeWalk->structMembers[idx].first.c_str());
|
||||
elementType = scalar.type;
|
||||
if(memberType->colMajorMat)
|
||||
{
|
||||
memberRows = RDCMAX(1U, vec.vecSize);
|
||||
memberColumns = RDCMAX(1U, memberType->matSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
memberColumns = RDCMAX(1U, vec.vecSize);
|
||||
memberRows = RDCMAX(1U, memberType->matSize);
|
||||
}
|
||||
}
|
||||
else if(memberType->vecSize != 0)
|
||||
{
|
||||
const TypeData &scalar = m_DebugInfo.types[memberType->baseType];
|
||||
uint32_t vecColumns = RDCMAX(1U, memberType->vecSize);
|
||||
|
||||
typeWalk = &m_DebugInfo.types[typeWalk->structMembers[idx].second];
|
||||
elementType = scalar.type;
|
||||
|
||||
memberRows = 1U;
|
||||
memberColumns = vecColumns;
|
||||
}
|
||||
usage->children[x].type = elementType;
|
||||
usage->children[x].rows = memberRows;
|
||||
usage->children[x].columns = memberColumns;
|
||||
}
|
||||
}
|
||||
// if the whole node was displayed : display the sub-elements
|
||||
if(usage->emitSourceVar)
|
||||
{
|
||||
for(uint32_t x = 0; x < rows; x++)
|
||||
usage->children[x].emitSourceVar = true;
|
||||
usage->emitSourceVar = false;
|
||||
}
|
||||
|
||||
RDCASSERTEQUAL(usage->children.size(), rows);
|
||||
|
||||
usage = &usage->children[idx];
|
||||
usage->type = childType->type;
|
||||
typeWalk = childType;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1716,109 +1892,304 @@ void Debugger::FillDebugSourceVars(rdcarray<InstructionSourceInfo> &instInfo)
|
||||
}
|
||||
|
||||
const char swizzle[] = "xyzw";
|
||||
|
||||
uint32_t rows = 1U;
|
||||
uint32_t columns = 1U;
|
||||
size_t countRemainingIndexes = indexes.size();
|
||||
if(typeWalk->matSize != 0)
|
||||
{
|
||||
const TypeData &vec = m_DebugInfo.types[typeWalk->baseType];
|
||||
const TypeData &scalar = m_DebugInfo.types[vec.baseType];
|
||||
|
||||
sourceVar.type = scalar.type;
|
||||
usage->type = scalar.type;
|
||||
|
||||
if(typeWalk->colMajorMat)
|
||||
{
|
||||
sourceVar.rows = RDCMAX(1U, vec.vecSize);
|
||||
sourceVar.columns = RDCMAX(1U, typeWalk->matSize);
|
||||
rows = RDCMAX(1U, vec.vecSize);
|
||||
columns = RDCMAX(1U, typeWalk->matSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceVar.rows = RDCMAX(1U, typeWalk->matSize);
|
||||
sourceVar.columns = RDCMAX(1U, vec.vecSize);
|
||||
columns = RDCMAX(1U, vec.vecSize);
|
||||
rows = RDCMAX(1U, typeWalk->matSize);
|
||||
}
|
||||
usage->rows = rows;
|
||||
usage->columns = columns;
|
||||
|
||||
// two remaining indices selects a scalar within the matrix
|
||||
if(indexes.size() == 2)
|
||||
if((countRemainingIndexes == 2) || (countRemainingIndexes == 1))
|
||||
{
|
||||
uint32_t col = indexes[0];
|
||||
uint32_t row = indexes[1];
|
||||
RDCASSERT(col < 4 && row < 4, col, row);
|
||||
sourceVar.name += StringFormat::Fmt(".row%u.%c", row, swizzle[RDCMIN(col, 3U)]);
|
||||
|
||||
sourceVar.variables.push_back(DebugVariableReference(
|
||||
DebugVariableType::Variable, GetRawName(mapping.debugVar), indexes[0]));
|
||||
}
|
||||
// one remaining index selects a column within the matrix. Since we display source vars
|
||||
// as row-major, this means adding 4 mappings
|
||||
else if(indexes.size() == 1)
|
||||
{
|
||||
uint32_t col = indexes[0];
|
||||
rdcstr name = sourceVar.name;
|
||||
for(uint32_t row = 0; row < sourceVar.rows; row++)
|
||||
if(usage->children.isEmpty())
|
||||
{
|
||||
sourceVar.name = name + StringFormat::Fmt(".row%u.%c", row, swizzle[RDCMIN(col, 3U)]);
|
||||
sourceVar.variables.push_back(DebugVariableReference(
|
||||
DebugVariableType::Variable, GetRawName(mapping.debugVar), row));
|
||||
// Matrices are stored as [row][col]
|
||||
usage->children.resize(rows);
|
||||
for(uint32_t r = 0; r < rows; ++r)
|
||||
{
|
||||
usage->children[r].emitSourceVar = false;
|
||||
usage->children[r].name = usage->name + StringFormat::Fmt(".row%u", r);
|
||||
usage->children[r].type = scalar.type;
|
||||
usage->children[r].debugVar = usage->debugVar;
|
||||
usage->children[r].debugVarComponent = 0;
|
||||
usage->children[r].rows = 1U;
|
||||
usage->children[r].columns = columns;
|
||||
usage->children[r].offset = r;
|
||||
usage->children[r].children.resize(columns);
|
||||
for(uint32_t c = 0; c < columns; ++c)
|
||||
{
|
||||
usage->children[r].children[c].emitSourceVar = false;
|
||||
usage->children[r].children[c].name =
|
||||
usage->name + StringFormat::Fmt(".row%u.%c", r, swizzle[RDCMIN(c, 3U)]);
|
||||
usage->children[r].children[c].type = scalar.type;
|
||||
usage->children[r].children[c].debugVar = usage->debugVar;
|
||||
usage->children[r].children[c].debugVarComponent = r;
|
||||
usage->children[r].children[c].rows = 1U;
|
||||
usage->children[r].children[c].columns = 1U;
|
||||
usage->children[r].children[c].offset = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// two remaining indices selects a scalar within the matrix
|
||||
if(countRemainingIndexes == 2)
|
||||
{
|
||||
uint32_t row, col;
|
||||
|
||||
if(typeWalk->colMajorMat)
|
||||
{
|
||||
col = indexes[0];
|
||||
row = indexes[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
row = indexes[0];
|
||||
col = indexes[1];
|
||||
}
|
||||
RDCASSERT(row < rows, row, rows);
|
||||
RDCASSERT(col < columns, col, columns);
|
||||
|
||||
usage->children[row].children[col].emitSourceVar =
|
||||
!usage->children[row].emitSourceVar;
|
||||
usage->children[row].children[col].debugVar = mapping.debugVar;
|
||||
usage->children[row].children[col].debugVarComponent = 0;
|
||||
|
||||
// try to recombine matrix rows to a single source var display
|
||||
if(!usage->children[row].emitSourceVar)
|
||||
{
|
||||
bool collapseVector = true;
|
||||
for(uint32_t c = 0; c < columns; ++c)
|
||||
{
|
||||
collapseVector = usage->children[row].children[c].emitSourceVar;
|
||||
if(!collapseVector)
|
||||
break;
|
||||
}
|
||||
if(collapseVector)
|
||||
{
|
||||
usage->children[row].emitSourceVar = true;
|
||||
for(uint32_t c = 0; c < columns; ++c)
|
||||
usage->children[row].children[c].emitSourceVar = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(typeWalk->colMajorMat)
|
||||
{
|
||||
uint32_t col = indexes[0];
|
||||
RDCASSERT(col < columns, col, columns);
|
||||
// one remaining index selects a column within the matrix.
|
||||
// source vars are displayed as row-major, need <rows> mappings
|
||||
for(uint32_t r = 0; r < rows; ++r)
|
||||
{
|
||||
usage->children[r].children[col].emitSourceVar =
|
||||
!usage->children[r].emitSourceVar;
|
||||
usage->children[r].children[col].debugVar = mapping.debugVar;
|
||||
usage->children[r].children[col].debugVarComponent = r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t row = indexes[0];
|
||||
RDCASSERT(row < rows, row, rows);
|
||||
// one remaining index selects a row within the matrix.
|
||||
// source vars are displayed as row-major, need <rows> mappings
|
||||
for(uint32_t c = 0; c < columns; ++c)
|
||||
{
|
||||
usage->children[row].children[c].emitSourceVar =
|
||||
!usage->children[row].emitSourceVar;
|
||||
usage->children[row].children[c].debugVar = mapping.debugVar;
|
||||
usage->children[row].children[c].debugVarComponent = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
// try to recombine matrix rows to a single source var display
|
||||
for(uint32_t r = 0; r < rows; ++r)
|
||||
{
|
||||
if(!usage->children[r].emitSourceVar)
|
||||
{
|
||||
bool collapseVector = true;
|
||||
for(uint32_t c = 0; c < columns; ++c)
|
||||
{
|
||||
collapseVector = usage->children[r].children[c].emitSourceVar;
|
||||
if(!collapseVector)
|
||||
break;
|
||||
}
|
||||
if(collapseVector)
|
||||
{
|
||||
usage->children[r].emitSourceVar = true;
|
||||
for(uint32_t c = 0; c < columns; ++c)
|
||||
usage->children[r].children[c].emitSourceVar = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
usage->emitSourceVar = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCASSERT(indexes.empty(), indexes.size());
|
||||
for(uint32_t x = 0; x < sourceVar.rows * sourceVar.columns; x++)
|
||||
sourceVar.variables.push_back(DebugVariableReference(
|
||||
DebugVariableType::Variable, GetRawName(mapping.debugVar), x));
|
||||
RDCASSERTEQUAL(countRemainingIndexes, 0);
|
||||
// Remove mappings : this mapping covers everything
|
||||
usage->debugVar = mapping.debugVar;
|
||||
usage->children.clear();
|
||||
usage->emitSourceVar = true;
|
||||
usage->debugVarSuffix.clear();
|
||||
}
|
||||
}
|
||||
else if(typeWalk->vecSize != 0)
|
||||
{
|
||||
const TypeData &scalar = m_DebugInfo.types[typeWalk->baseType];
|
||||
columns = RDCMAX(1U, typeWalk->vecSize);
|
||||
|
||||
sourceVar.type = scalar.type;
|
||||
sourceVar.columns = RDCMAX(1U, typeWalk->vecSize);
|
||||
usage->type = scalar.type;
|
||||
|
||||
usage->rows = 1U;
|
||||
usage->columns = columns;
|
||||
|
||||
// remaining index selects a scalar within the vector
|
||||
if(indexes.size() == 1)
|
||||
if(countRemainingIndexes == 1)
|
||||
{
|
||||
RDCASSERT(indexes[0] < 4, indexes[0]);
|
||||
sourceVar.name += StringFormat::Fmt(".%c", swizzle[RDCMIN(indexes[0], 3U)]);
|
||||
sourceVar.variables.push_back(DebugVariableReference(
|
||||
DebugVariableType::Variable, GetRawName(mapping.debugVar), 0));
|
||||
if(usage->children.isEmpty())
|
||||
{
|
||||
usage->children.resize(columns);
|
||||
for(uint32_t x = 0; x < columns; ++x)
|
||||
{
|
||||
usage->children[x].emitSourceVar = usage->emitSourceVar;
|
||||
usage->children[x].name =
|
||||
usage->name + StringFormat::Fmt(".%c", swizzle[RDCMIN(x, 3U)]);
|
||||
usage->children[x].type = scalar.type;
|
||||
usage->children[x].debugVar = usage->debugVar;
|
||||
usage->children[x].debugVarComponent = x;
|
||||
usage->children[x].rows = 1U;
|
||||
usage->children[x].columns = 1U;
|
||||
usage->children[x].offset = x;
|
||||
}
|
||||
usage->emitSourceVar = false;
|
||||
}
|
||||
uint32_t col = indexes[0];
|
||||
RDCASSERT(col < columns, col, columns);
|
||||
usage->children[col].debugVar = mapping.debugVar;
|
||||
usage->children[col].debugVarComponent = 0;
|
||||
usage->children[col].emitSourceVar = true;
|
||||
|
||||
// try to recombine vector to a single source var display
|
||||
bool collapseVector = true;
|
||||
for(uint32_t x = 0; x < columns; ++x)
|
||||
{
|
||||
collapseVector = usage->children[x].emitSourceVar;
|
||||
if(!collapseVector)
|
||||
break;
|
||||
}
|
||||
if(collapseVector)
|
||||
{
|
||||
usage->emitSourceVar = true;
|
||||
for(uint32_t x = 0; x < columns; ++x)
|
||||
usage->children[x].emitSourceVar = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCASSERT(indexes.empty(), indexes.size());
|
||||
for(uint32_t x = 0; x < sourceVar.rows * sourceVar.columns; x++)
|
||||
sourceVar.variables.push_back(DebugVariableReference(
|
||||
DebugVariableType::Variable, GetRawName(mapping.debugVar), x));
|
||||
RDCASSERTEQUAL(countRemainingIndexes, 0);
|
||||
// Remove mappings : this mapping covers everything
|
||||
usage->debugVar = mapping.debugVar;
|
||||
usage->children.clear();
|
||||
usage->emitSourceVar = true;
|
||||
usage->debugVarSuffix.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// walk down until we get to a scalar type, if we get there. This means arrays of basic
|
||||
// types will get the right type
|
||||
// walk down until we get to a scalar type, if we get there. This means arrays of
|
||||
// basic types will get the right type
|
||||
while(typeWalk && typeWalk->baseType != Id() && typeWalk->type == VarType::Unknown)
|
||||
typeWalk = &m_DebugInfo.types[typeWalk->baseType];
|
||||
|
||||
sourceVar.type = typeWalk->type;
|
||||
|
||||
// anything else we treat as a struct
|
||||
if(sourceVar.type == VarType::Unknown)
|
||||
sourceVar.type = VarType::Struct;
|
||||
|
||||
sourceVar.variables.push_back(DebugVariableReference(DebugVariableType::Variable,
|
||||
GetRawName(mapping.debugVar), 0));
|
||||
usage->type = typeWalk->type;
|
||||
usage->debugVar = mapping.debugVar;
|
||||
usage->debugVarComponent = 0;
|
||||
usage->rows = 1U;
|
||||
usage->columns = 1U;
|
||||
usage->emitSourceVar = true;
|
||||
usage->children.clear();
|
||||
usage->debugVarSuffix.clear();
|
||||
}
|
||||
|
||||
i.sourceVars.push_back(sourceVar);
|
||||
}
|
||||
|
||||
processed.push_back(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
// if we reach a function scope, don't go up any further.
|
||||
if(scope->type == DebugScope::Function)
|
||||
break;
|
||||
// Phase Two: walk the DebugVarNode tree and convert "emitSourceVar = true" nodes to a SourceVariableMapping
|
||||
for(size_t sv = 0; sv < sourceVars.size(); ++sv)
|
||||
{
|
||||
Id sourceVarId = sourceVars[sv];
|
||||
DebugVarNode *usage = &roots[sourceVarId];
|
||||
rdcarray<const DebugVarNode *> nodesToProcess;
|
||||
rdcarray<const DebugVarNode *> sourceVarNodes;
|
||||
nodesToProcess.push_back(usage);
|
||||
while(!nodesToProcess.isEmpty())
|
||||
{
|
||||
const DebugVarNode *n = nodesToProcess.back();
|
||||
nodesToProcess.pop_back();
|
||||
if(n->emitSourceVar)
|
||||
{
|
||||
sourceVarNodes.push_back(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t x = 0; x < n->children.size(); ++x)
|
||||
{
|
||||
const DebugVarNode *child = &n->children[x];
|
||||
nodesToProcess.push_back(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(size_t x = 0; x < sourceVarNodes.size(); ++x)
|
||||
{
|
||||
const DebugVarNode *n = sourceVarNodes[x];
|
||||
SourceVariableMapping sourceVar;
|
||||
sourceVar.name = n->name;
|
||||
sourceVar.type = n->type;
|
||||
sourceVar.signatureIndex = -1;
|
||||
sourceVar.offset = n->offset;
|
||||
sourceVar.variables.clear();
|
||||
// unknown is treated as a struct
|
||||
if(sourceVar.type == VarType::Unknown)
|
||||
sourceVar.type = VarType::Struct;
|
||||
|
||||
// move to the parent scope and apply the mappings there
|
||||
scope = scope->parent;
|
||||
if(n->children.empty())
|
||||
{
|
||||
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
|
||||
{
|
||||
RDCASSERTEQUAL(n->rows * n->columns, (uint32_t)n->children.count());
|
||||
for(int32_t c = 0; c < n->children.count(); ++c)
|
||||
sourceVar.variables.push_back(DebugVariableReference(
|
||||
DebugVariableType::Variable,
|
||||
GetRawName(n->children[c].debugVar) + n->children[c].debugVarSuffix,
|
||||
n->children[c].debugVarComponent));
|
||||
}
|
||||
i.sourceVars.push_back(sourceVar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3730,10 +4101,7 @@ void Debugger::RegisterOp(Iter it)
|
||||
|
||||
mapping.indexes.resize(dbg.params.size() - 3);
|
||||
for(uint32_t i = 0; i < mapping.indexes.size(); i++)
|
||||
{
|
||||
size_t idx = mapping.indexes.size() - 1 - i;
|
||||
mapping.indexes[idx] = EvaluateConstant(dbg.arg<Id>(i + 3), {}).value.u32v[0];
|
||||
}
|
||||
mapping.indexes[i] = EvaluateConstant(dbg.arg<Id>(i + 3), {}).value.u32v[0];
|
||||
|
||||
{
|
||||
// don't support expressions, only allow for a single 'deref' which is used for
|
||||
|
||||
Reference in New Issue
Block a user