Gather and display callstack information during shader debugging

This commit is contained in:
baldurk
2018-05-17 13:35:58 +01:00
parent 165434a1f0
commit e2dcd902cd
11 changed files with 121 additions and 26 deletions
+15 -1
View File
@@ -69,6 +69,7 @@ ShaderViewer::ShaderViewer(ICaptureContext &ctx, QWidget *parent)
ui->watch->setFont(Formatter::PreferredFont());
ui->inputSig->setFont(Formatter::PreferredFont());
ui->outputSig->setFont(Formatter::PreferredFont());
ui->callstack->setFont(Formatter::PreferredFont());
// we create this up front so its state stays persistent as much as possible.
m_FindReplace = new FindReplace(this);
@@ -204,10 +205,11 @@ void ShaderViewer::editShader(bool customShader, const QString &entryPoint, cons
m_DisassemblyView = NULL;
// hide watch, constants, variables
// hide debugging windows
ui->watch->hide();
ui->variables->hide();
ui->constants->hide();
ui->callstack->hide();
ui->snippets->setVisible(customShader);
@@ -460,6 +462,13 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
ui->docking->setToolWindowProperties(
ui->constants, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
ui->callstack->setWindowTitle(tr("Callstack"));
ui->docking->addToolWindow(
ui->callstack, ToolWindowManager::AreaReference(ToolWindowManager::RightOf,
ui->docking->areaOf(ui->variables), 0.2f));
ui->docking->setToolWindowProperties(
ui->callstack, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
m_DisassemblyView->setMarginWidthN(1, 20.0 * devicePixelRatioF());
// display current line in margin 2, distinct from breakpoint in margin 1
@@ -1227,6 +1236,11 @@ void ShaderViewer::updateDebugging()
}
}
ui->callstack->clear();
for(const rdcstr &s : state.callstack)
ui->callstack->insertItem(0, s);
if(ui->constants->topLevelItemCount() == 0)
{
for(int i = 0; i < m_Trace->constantBlocks.count(); i++)
+16
View File
@@ -538,6 +538,22 @@
</property>
</column>
</widget>
<widget class="QListWidget" name="callstack">
<property name="geometry">
<rect>
<x>20</x>
<y>80</y>
<width>256</width>
<height>192</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</widget>
<customwidgets>
<customwidget>
+8 -2
View File
@@ -235,7 +235,7 @@ struct ShaderDebugState
bool operator==(const ShaderDebugState &o) const
{
return registers == o.registers && outputs == o.outputs && indexableTemps == o.indexableTemps &&
nextInstruction == o.nextInstruction && flags == o.flags;
nextInstruction == o.nextInstruction && flags == o.flags && callstack == o.callstack;
}
bool operator<(const ShaderDebugState &o) const
{
@@ -249,6 +249,8 @@ struct ShaderDebugState
return nextInstruction < o.nextInstruction;
if(!(flags == o.flags))
return flags < o.flags;
if(!(callstack == o.callstack))
return callstack < o.callstack;
return false;
}
DOCUMENT("The temporary variables for this shader as a list of :class:`ShaderValue`.");
@@ -260,8 +262,12 @@ struct ShaderDebugState
"Indexable temporary variables for this shader as a list of :class:`ShaderValue` lists.");
rdcarray<ShaderVariable> indexableTemps;
DOCUMENT("An optional callstack listing function calls at the present instruction");
rdcarray<rdcstr> callstack;
DOCUMENT(R"(The next instruction to be executed after this state. The initial state before any
shader execution happened will have ``nextInstruction == 0``.)");
shader execution happened will have ``nextInstruction == 0``.
)");
uint32_t nextInstruction;
DOCUMENT("A set of :class:`ShaderEvents` flags that indicate what events happened on this step.");
+26 -1
View File
@@ -940,6 +940,8 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
vector<ShaderDebugState> states;
dxbc->m_DebugInfo->GetStack(0, dxbc->GetInstruction(0).offset, initialState.callstack);
states.push_back((State)initialState);
D3D11MarkerRegion simloop("Simulation Loop");
@@ -951,6 +953,11 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
initialState = initialState.GetNext(global, NULL);
{
const ASMOperation &op = dxbc->GetInstruction((size_t)initialState.nextInstruction);
dxbc->m_DebugInfo->GetStack(initialState.nextInstruction, op.offset, initialState.callstack);
}
states.push_back((State)initialState);
if(cycleCounter == SHADER_DEBUG_WARN_THRESHOLD)
@@ -1810,6 +1817,8 @@ ShaderDebugTrace D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
vector<ShaderDebugState> states;
dxbc->m_DebugInfo->GetStack(0, dxbc->GetInstruction(0).offset, quad[destIdx].callstack);
states.push_back((State)quad[destIdx]);
// ping pong between so that we can have 'current' quad to update into new one
@@ -1843,7 +1852,16 @@ ShaderDebugTrace D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
// if our destination quad is paused don't record multiple identical states.
if(activeMask[destIdx])
states.push_back((State)curquad[destIdx]);
{
State &s = curquad[destIdx];
{
const ASMOperation &op = dxbc->GetInstruction((size_t)s.nextInstruction);
dxbc->m_DebugInfo->GetStack(s.nextInstruction, op.offset, s.callstack);
}
states.push_back(s);
}
// we need to make sure that control flow which converges stays in lockstep so that
// derivatives are still valid. While diverged, we don't have to keep threads in lockstep
@@ -1992,6 +2010,8 @@ ShaderDebugTrace D3D11Replay::DebugThread(uint32_t eventId, const uint32_t group
vector<ShaderDebugState> states;
dxbc->m_DebugInfo->GetStack(0, dxbc->GetInstruction(0).offset, initialState.callstack);
states.push_back((State)initialState);
for(int cycleCounter = 0;; cycleCounter++)
@@ -2001,6 +2021,11 @@ ShaderDebugTrace D3D11Replay::DebugThread(uint32_t eventId, const uint32_t group
initialState = initialState.GetNext(global, NULL);
{
const ASMOperation &op = dxbc->GetInstruction((size_t)initialState.nextInstruction);
dxbc->m_DebugInfo->GetStack(initialState.nextInstruction, op.offset, initialState.callstack);
}
states.push_back((State)initialState);
if(cycleCounter == SHADER_DEBUG_WARN_THRESHOLD)
@@ -667,6 +667,7 @@ void DXBCFile::MakeDisassemblyString()
int32_t prevFile = -1;
int32_t prevLine = -1;
std::string prevFunc;
size_t debugInst = 0;
@@ -695,8 +696,9 @@ void DXBCFile::MakeDisassemblyString()
{
int32_t fileID = prevFile;
int32_t lineNum = prevLine;
std::string func = prevFunc;
m_DebugInfo->GetFileLine(debugInst, m_Instructions[i].offset, fileID, lineNum);
m_DebugInfo->GetLineInfo(debugInst, m_Instructions[i].offset, fileID, lineNum, func);
if(fileID >= 0 && lineNum >= 0 && (fileID != prevFile || lineNum != prevLine))
{
@@ -722,13 +724,24 @@ void DXBCFile::MakeDisassemblyString()
m_Disassembly += "\n";
if((fileID != prevFile && fileID < (int32_t)fileLines.size()) || line == "")
if(((fileID != prevFile || func != prevFunc) && fileID < (int32_t)fileLines.size()) ||
line == "")
{
m_Disassembly += " "; // "0000: "
for(int in = 0; in < indent; in++)
m_Disassembly += " ";
m_Disassembly +=
StringFormat::Fmt("%s:%d\n", m_DebugInfo->Files[fileID].first.c_str(), lineNum + 1);
if(!func.empty())
{
m_Disassembly +=
StringFormat::Fmt("%s:%d - %s()\n", m_DebugInfo->Files[fileID].first.c_str(),
lineNum + 1, func.c_str());
}
else
{
m_Disassembly +=
StringFormat::Fmt("%s:%d\n", m_DebugInfo->Files[fileID].first.c_str(), lineNum + 1);
}
}
if(line != "")
@@ -742,6 +755,7 @@ void DXBCFile::MakeDisassemblyString()
prevFile = fileID;
prevLine = lineNum;
prevFunc = func;
}
char buf[64] = {0};
+3 -2
View File
@@ -330,8 +330,9 @@ public:
vector<pair<string, string> > Files; // <filename, source>
virtual void GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx,
int32_t &lineNum) const = 0;
virtual void GetLineInfo(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum,
std::string &funcName) const = 0;
virtual void GetStack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &stack) const = 0;
};
uint32_t DecodeFlags(const ShaderCompileFlags &compileFlags);
+8 -2
View File
@@ -98,8 +98,8 @@ SDBGChunk::SDBGChunk(void *data)
m_HasDebugInfo = true;
}
void SDBGChunk::GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx,
int32_t &lineNum) const
void SDBGChunk::GetLineInfo(size_t instruction, uintptr_t offset, int32_t &fileIdx,
int32_t &lineNum, std::string &func) const
{
if(instruction < m_Instructions.size())
{
@@ -110,10 +110,16 @@ void SDBGChunk::GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileI
fileIdx = sym.fileID;
lineNum = sym.lineNum - 1;
func = m_Entry;
}
}
}
void SDBGChunk::GetStack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &stack) const
{
stack = {"Stack not available"};
}
string SDBGChunk::GetSymbolName(int symbolID)
{
RDCASSERT(symbolID >= 0 && symbolID < (int)m_SymbolTable.size());
+3 -1
View File
@@ -260,7 +260,9 @@ public:
string GetEntryFunction() const { return m_Entry; }
string GetShaderProfile() const { return m_Profile; }
uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; }
void GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum) const;
void GetLineInfo(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum,
std::string &func) const;
void GetStack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &stack) const;
private:
SDBGChunk();
+20 -12
View File
@@ -1044,20 +1044,28 @@ SPDBChunk::SPDBChunk(void *chunk)
m_HasDebugInfo = true;
}
void SPDBChunk::GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx,
int32_t &lineNum) const
void SPDBChunk::GetLineInfo(size_t instruction, uintptr_t offset, int32_t &fileIdx,
int32_t &lineNum, std::string &func) const
{
for(auto it = m_Lines.begin(); it != m_Lines.end(); ++it)
auto it = m_Lines.lower_bound((uint32_t)offset);
if(it != m_Lines.end() && (uintptr_t)it->first <= offset)
{
if((uintptr_t)it->first <= offset)
{
fileIdx = it->second.fileIndex;
lineNum = it->second.lineStart - 1; // 0-indexed
}
else
{
return;
}
fileIdx = it->second.fileIndex;
lineNum = it->second.lineStart - 1; // 0-indexed
func = it->second.stack.back();
}
}
void SPDBChunk::GetStack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &stack) const
{
auto it = m_Lines.lower_bound((uint32_t)offset);
if(it != m_Lines.end() && (uintptr_t)it->first <= offset)
{
stack.resize(it->second.stack.size());
for(size_t i = 0; i < stack.size(); i++)
stack[i] = it->second.stack[i];
}
}
+3 -1
View File
@@ -258,7 +258,9 @@ public:
std::string GetEntryFunction() const { return m_Entry; }
std::string GetShaderProfile() const { return m_Profile; }
uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; }
void GetFileLine(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum) const;
void GetLineInfo(size_t instruction, uintptr_t offset, int32_t &fileIdx, int32_t &lineNum,
std::string &func) const;
void GetStack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &stack) const;
private:
SPDBChunk(const SPDBChunk &);
+1
View File
@@ -349,6 +349,7 @@ void DoSerialise(SerialiserType &ser, ShaderDebugState &el)
SERIALISE_MEMBER(indexableTemps);
SERIALISE_MEMBER(nextInstruction);
SERIALISE_MEMBER(flags);
SERIALISE_MEMBER(callstack);
SIZE_CHECK(56);
}