Pass through line-mapping information for each instruction to UI

* This lets the UI highlight the source line as stepping happens, as well as
  allowing stepping purely in HLSL.
This commit is contained in:
baldurk
2018-06-22 19:28:30 +01:00
parent ff9f5675e9
commit 52e9a6c01d
12 changed files with 406 additions and 157 deletions
+1
View File
@@ -257,6 +257,7 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, PathEntry)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, PixelModification)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ResourceDescription)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ResourceId)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, LineColumnInfo)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderCompileFlag)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderConstant)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderDebugState)
+245 -60
View File
@@ -105,24 +105,6 @@ ShaderViewer::ShaderViewer(ICaptureContext &ctx, QWidget *parent)
QObject::connect(m_DisassemblyView, &ScintillaEdit::keyPressed, this,
&ShaderViewer::readonly_keyPressed);
// C# LightCoral
m_DisassemblyView->markerSetBack(CURRENT_MARKER, SCINTILLA_COLOUR(240, 128, 128));
m_DisassemblyView->markerSetBack(CURRENT_MARKER + 1, SCINTILLA_COLOUR(240, 128, 128));
m_DisassemblyView->markerDefine(CURRENT_MARKER, SC_MARK_SHORTARROW);
m_DisassemblyView->markerDefine(CURRENT_MARKER + 1, SC_MARK_BACKGROUND);
// C# LightSlateGray
m_DisassemblyView->markerSetBack(FINISHED_MARKER, SCINTILLA_COLOUR(119, 136, 153));
m_DisassemblyView->markerSetBack(FINISHED_MARKER + 1, SCINTILLA_COLOUR(119, 136, 153));
m_DisassemblyView->markerDefine(FINISHED_MARKER, SC_MARK_ROUNDRECT);
m_DisassemblyView->markerDefine(FINISHED_MARKER + 1, SC_MARK_BACKGROUND);
// C# Red
m_DisassemblyView->markerSetBack(BREAKPOINT_MARKER, SCINTILLA_COLOUR(255, 0, 0));
m_DisassemblyView->markerSetBack(BREAKPOINT_MARKER + 1, SCINTILLA_COLOUR(255, 0, 0));
m_DisassemblyView->markerDefine(BREAKPOINT_MARKER, SC_MARK_CIRCLE);
m_DisassemblyView->markerDefine(BREAKPOINT_MARKER + 1, SC_MARK_BACKGROUND);
m_Scintillas.push_back(m_DisassemblyView);
m_DisassemblyFrame = new QWidget(this);
@@ -355,7 +337,6 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
QObject::connect(m_DisassemblyView, &ScintillaEdit::buttonReleased, this,
&ShaderViewer::disassembly_buttonReleased);
// suppress the built-in context menu and hook up our own
if(trace)
{
if(m_Stage == ShaderStage::Vertex)
@@ -371,14 +352,8 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
ANALYTIC_SET(ShaderDebug.Compute, true);
}
m_DisassemblyView->usePopUp(SC_POPUP_NEVER);
m_DisassemblyFrame->layout()->removeWidget(m_DisassemblyToolbar);
m_DisassemblyView->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(m_DisassemblyView, &ScintillaEdit::customContextMenuRequested, this,
&ShaderViewer::disassembly_contextMenu);
m_DisassemblyView->setMouseDwellTime(500);
QObject::connect(m_DisassemblyView, &ScintillaEdit::dwellStart, this,
@@ -394,7 +369,7 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
else
setWindowTitle(shader->entryPoint);
int fileIdx = 0;
m_FileScintillas.reserve(shader->debugInfo.files.count());
QWidget *sel = NULL;
for(const ShaderSourceFile &f : shader->debugInfo.files)
@@ -407,7 +382,7 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
if(sel == NULL)
sel = scintilla;
fileIdx++;
m_FileScintillas.push_back(scintilla);
}
if(trace || sel == NULL)
@@ -491,14 +466,6 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
ui->locals->hide();
}
m_DisassemblyView->setMarginWidthN(1, 20.0 * devicePixelRatioF());
// display current line in margin 2, distinct from breakpoint in margin 1
sptr_t markMask = (1 << CURRENT_MARKER) | (1 << FINISHED_MARKER);
m_DisassemblyView->setMarginMaskN(1, m_DisassemblyView->marginMaskN(1) & ~markMask);
m_DisassemblyView->setMarginMaskN(2, m_DisassemblyView->marginMaskN(2) | markMask);
QObject::connect(ui->stepBack, &QToolButton::clicked, this, &ShaderViewer::stepBack);
QObject::connect(ui->stepNext, &QToolButton::clicked, this, &ShaderViewer::stepNext);
QObject::connect(ui->runBack, &QToolButton::clicked, this, &ShaderViewer::runBack);
@@ -507,19 +474,38 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
QObject::connect(ui->runToSample, &QToolButton::clicked, this, &ShaderViewer::runToSample);
QObject::connect(ui->runToNaNOrInf, &QToolButton::clicked, this, &ShaderViewer::runToNanOrInf);
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F10), m_DisassemblyView),
&QShortcut::activated, this, &ShaderViewer::stepNext);
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F10 | Qt::ShiftModifier), m_DisassemblyView),
for(ScintillaEdit *edit : m_Scintillas)
{
edit->setMarginWidthN(1, 20.0 * devicePixelRatioF());
// display current line in margin 2, distinct from breakpoint in margin 1
sptr_t markMask = (1 << CURRENT_MARKER) | (1 << FINISHED_MARKER);
edit->setMarginMaskN(1, edit->marginMaskN(1) & ~markMask);
edit->setMarginMaskN(2, edit->marginMaskN(2) | markMask);
// suppress the built-in context menu and hook up our own
edit->usePopUp(SC_POPUP_NEVER);
edit->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(edit, &ScintillaEdit::customContextMenuRequested, this,
&ShaderViewer::debug_contextMenu);
}
// register the shortcuts globally for this shader viewer so it works regardless of the active
// scintilla
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F10), this), &QShortcut::activated, this,
&ShaderViewer::stepNext);
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F10 | Qt::ShiftModifier), this),
&QShortcut::activated, this, &ShaderViewer::stepBack);
QObject::connect(
new QShortcut(QKeySequence(Qt::Key_F10 | Qt::ControlModifier), m_DisassemblyView),
&QShortcut::activated, this, &ShaderViewer::runToCursor);
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F5), m_DisassemblyView),
&QShortcut::activated, this, &ShaderViewer::run);
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F5 | Qt::ShiftModifier), m_DisassemblyView),
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F10 | Qt::ControlModifier), this),
&QShortcut::activated, this, &ShaderViewer::runToCursor);
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F5), this), &QShortcut::activated, this,
&ShaderViewer::run);
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F5 | Qt::ShiftModifier), this),
&QShortcut::activated, this, &ShaderViewer::runBack);
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F9), m_DisassemblyView),
&QShortcut::activated, [this]() { ToggleBreakpoint(); });
QObject::connect(new QShortcut(QKeySequence(Qt::Key_F9), this), &QShortcut::activated,
[this]() { ToggleBreakpoint(); });
// event filter to pick up tooltip events
ui->constants->installEventFilter(this);
@@ -541,6 +527,8 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
}
ui->watch->resizeRowsToContents();
ToolWindowManager::raiseToolWindow(m_DisassemblyFrame);
}
else
{
@@ -641,6 +629,41 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
ui->docking->setToolWindowProperties(
ui->outputSig, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
}
for(ScintillaEdit *edit : m_Scintillas)
{
// C# LightCoral
edit->markerSetBack(CURRENT_MARKER, SCINTILLA_COLOUR(240, 128, 128));
edit->markerSetBack(CURRENT_MARKER + 1, SCINTILLA_COLOUR(240, 128, 128));
edit->markerDefine(CURRENT_MARKER, SC_MARK_SHORTARROW);
edit->markerDefine(CURRENT_MARKER + 1, SC_MARK_BACKGROUND);
edit->indicSetFore(CURRENT_INDICATOR, SCINTILLA_COLOUR(240, 128, 128));
edit->indicSetAlpha(CURRENT_INDICATOR, 220);
edit->indicSetOutlineAlpha(CURRENT_INDICATOR, 255);
edit->indicSetUnder(CURRENT_INDICATOR, true);
edit->indicSetStyle(CURRENT_INDICATOR, INDIC_STRAIGHTBOX);
edit->indicSetHoverFore(CURRENT_INDICATOR, SCINTILLA_COLOUR(240, 128, 128));
edit->indicSetHoverStyle(CURRENT_INDICATOR, INDIC_STRAIGHTBOX);
// C# LightSlateGray
edit->markerSetBack(FINISHED_MARKER, SCINTILLA_COLOUR(119, 136, 153));
edit->markerSetBack(FINISHED_MARKER + 1, SCINTILLA_COLOUR(119, 136, 153));
edit->markerDefine(FINISHED_MARKER, SC_MARK_ROUNDRECT);
edit->markerDefine(FINISHED_MARKER + 1, SC_MARK_BACKGROUND);
edit->indicSetFore(FINISHED_INDICATOR, SCINTILLA_COLOUR(119, 136, 153));
edit->indicSetAlpha(FINISHED_INDICATOR, 220);
edit->indicSetOutlineAlpha(FINISHED_INDICATOR, 255);
edit->indicSetUnder(FINISHED_INDICATOR, true);
edit->indicSetStyle(FINISHED_INDICATOR, INDIC_STRAIGHTBOX);
edit->indicSetHoverFore(FINISHED_INDICATOR, SCINTILLA_COLOUR(119, 136, 153));
edit->indicSetHoverStyle(FINISHED_INDICATOR, INDIC_STRAIGHTBOX);
// C# Red
edit->markerSetBack(BREAKPOINT_MARKER, SCINTILLA_COLOUR(255, 0, 0));
edit->markerSetBack(BREAKPOINT_MARKER + 1, SCINTILLA_COLOUR(255, 0, 0));
edit->markerDefine(BREAKPOINT_MARKER, SC_MARK_CIRCLE);
edit->markerDefine(BREAKPOINT_MARKER + 1, SC_MARK_BACKGROUND);
}
}
void ShaderViewer::updateWindowTitle()
@@ -793,12 +816,33 @@ void ShaderViewer::editable_keyPressed(QKeyEvent *event)
}
}
void ShaderViewer::disassembly_contextMenu(const QPoint &pos)
void ShaderViewer::debug_contextMenu(const QPoint &pos)
{
int scintillaPos = m_DisassemblyView->positionFromPoint(pos.x(), pos.y());
ScintillaEdit *edit = qobject_cast<ScintillaEdit *>(QObject::sender());
bool isDisasm = (edit == m_DisassemblyView);
int scintillaPos = edit->positionFromPoint(pos.x(), pos.y());
QMenu contextMenu(this);
QAction gotoOther(isDisasm ? tr("Go to Source") : tr("Go to Disassembly"), this);
QObject::connect(&gotoOther, &QAction::triggered, [this, isDisasm]() {
if(isDisasm && m_CurInstructionScintilla)
{
ToolWindowManager::raiseToolWindow(m_CurInstructionScintilla);
m_CurInstructionScintilla->setFocus(Qt::MouseFocusReason);
}
else if(!isDisasm)
{
ToolWindowManager::raiseToolWindow(m_DisassemblyFrame);
m_DisassemblyFrame->setFocus(Qt::MouseFocusReason);
}
updateDebugging();
});
QAction intDisplay(tr("Integer register display"), this);
QAction floatDisplay(tr("Float register display"), this);
@@ -811,6 +855,12 @@ void ShaderViewer::disassembly_contextMenu(const QPoint &pos)
QObject::connect(&intDisplay, &QAction::triggered, this, &ShaderViewer::on_intView_clicked);
QObject::connect(&floatDisplay, &QAction::triggered, this, &ShaderViewer::on_floatView_clicked);
if(isDisasm && m_CurInstructionScintilla == NULL)
gotoOther.setEnabled(false);
contextMenu.addAction(&gotoOther);
contextMenu.addSeparator();
contextMenu.addAction(&intDisplay);
contextMenu.addAction(&floatDisplay);
contextMenu.addSeparator();
@@ -831,22 +881,26 @@ void ShaderViewer::disassembly_contextMenu(const QPoint &pos)
contextMenu.addAction(&runCursor);
contextMenu.addSeparator();
if(!isDisasm)
{
addBreakpoint.setEnabled(false);
runCursor.setEnabled(false);
}
QAction copyText(tr("Copy"), this);
QAction selectAll(tr("Select All"), this);
copyText.setEnabled(!m_DisassemblyView->selectionEmpty());
copyText.setEnabled(!edit->selectionEmpty());
QObject::connect(&copyText, &QAction::triggered, [this] {
m_DisassemblyView->copyRange(m_DisassemblyView->selectionStart(),
m_DisassemblyView->selectionEnd());
});
QObject::connect(&selectAll, &QAction::triggered, [this] { m_DisassemblyView->selectAll(); });
QObject::connect(&copyText, &QAction::triggered,
[this, edit] { edit->copyRange(edit->selectionStart(), edit->selectionEnd()); });
QObject::connect(&selectAll, &QAction::triggered, [this, edit] { edit->selectAll(); });
contextMenu.addAction(&copyText);
contextMenu.addAction(&selectAll);
contextMenu.addSeparator();
RDDialog::show(&contextMenu, m_DisassemblyView->viewport()->mapToGlobal(pos));
RDDialog::show(&contextMenu, edit->viewport()->mapToGlobal(pos));
}
void ShaderViewer::disassembly_buttonReleased(QMouseEvent *event)
@@ -1015,7 +1069,36 @@ bool ShaderViewer::stepBack()
if(CurrentStep() == 0)
return false;
SetCurrentStep(CurrentStep() - 1);
if(isSourceDebugging())
{
const ShaderDebugState &oldstate = m_Trace->states[CurrentStep()];
LineColumnInfo oldLine = m_Trace->lineInfo[oldstate.nextInstruction];
while(CurrentStep() < m_Trace->states.count())
{
m_CurrentStep--;
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
if(m_Breakpoints.contains((int)state.nextInstruction))
break;
if(m_CurrentStep == 0)
break;
if(m_Trace->lineInfo[state.nextInstruction] == oldLine)
continue;
break;
}
SetCurrentStep(CurrentStep());
}
else
{
SetCurrentStep(CurrentStep() - 1);
}
return true;
}
@@ -1028,7 +1111,36 @@ bool ShaderViewer::stepNext()
if(CurrentStep() + 1 >= m_Trace->states.count())
return false;
SetCurrentStep(CurrentStep() + 1);
if(isSourceDebugging())
{
const ShaderDebugState &oldstate = m_Trace->states[CurrentStep()];
LineColumnInfo oldLine = m_Trace->lineInfo[oldstate.nextInstruction];
while(CurrentStep() < m_Trace->states.count())
{
m_CurrentStep++;
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
if(m_Breakpoints.contains((int)state.nextInstruction))
break;
if(m_CurrentStep + 1 >= m_Trace->states.count())
break;
if(m_Trace->lineInfo[state.nextInstruction] == oldLine)
continue;
break;
}
SetCurrentStep(CurrentStep());
}
else
{
SetCurrentStep(CurrentStep() + 1);
}
return true;
}
@@ -1244,6 +1356,18 @@ void ShaderViewer::updateDebugging()
m_DisassemblyView->markerDeleteAll(FINISHED_MARKER);
m_DisassemblyView->markerDeleteAll(FINISHED_MARKER + 1);
if(m_CurInstructionScintilla)
{
m_CurInstructionScintilla->markerDeleteAll(CURRENT_MARKER);
m_CurInstructionScintilla->markerDeleteAll(CURRENT_MARKER + 1);
m_CurInstructionScintilla->markerDeleteAll(FINISHED_MARKER);
m_CurInstructionScintilla->markerDeleteAll(FINISHED_MARKER + 1);
m_CurInstructionScintilla->indicatorClearRange(0, m_CurInstructionScintilla->length());
m_CurInstructionScintilla = NULL;
}
for(sptr_t i = 0; i < m_DisassemblyView->lineCount(); i++)
{
if(QString::fromUtf8(m_DisassemblyView->getLine(i).trimmed())
@@ -1262,8 +1386,64 @@ void ShaderViewer::updateDebugging()
ui->callstack->clear();
for(const rdcstr &s : state.callstack)
ui->callstack->insertItem(0, s);
if(state.nextInstruction < m_Trace->lineInfo.size())
{
LineColumnInfo &lineInfo = m_Trace->lineInfo[state.nextInstruction];
for(const rdcstr &s : lineInfo.callstack)
ui->callstack->insertItem(0, s);
if(lineInfo.fileIndex >= 0 && lineInfo.fileIndex < m_FileScintillas.count())
{
m_CurInstructionScintilla = m_FileScintillas[lineInfo.fileIndex];
for(sptr_t line = lineInfo.lineStart; line <= lineInfo.lineEnd; line++)
{
if(line == lineInfo.lineEnd)
m_CurInstructionScintilla->markerAdd(line - 1, done ? FINISHED_MARKER : CURRENT_MARKER);
if(lineInfo.colStart == 0)
{
// with no column info, add a marker on the whole line
m_CurInstructionScintilla->markerAdd(line - 1,
done ? FINISHED_MARKER + 1 : CURRENT_MARKER + 1);
}
else
{
// otherwise add an indicator on the column range.
// Start from the full position/length for this line
sptr_t pos = m_CurInstructionScintilla->positionFromLine(line - 1);
sptr_t len = m_CurInstructionScintilla->lineEndPosition(line - 1) - pos;
// if we're on the last line of the range, restrict the length to end on the last column
if(line == lineInfo.lineEnd && lineInfo.colEnd != 0)
len = lineInfo.colEnd;
// if we're on the start of the range (which may also be the last line above too), shift
// inwards towards the first column
if(line == lineInfo.lineStart)
{
pos += lineInfo.colStart - 1;
len -= lineInfo.colStart - 1;
}
m_CurInstructionScintilla->setIndicatorCurrent(done ? FINISHED_INDICATOR
: CURRENT_INDICATOR);
m_CurInstructionScintilla->indicatorFillRange(pos, len);
}
}
if(isSourceDebugging() ||
ui->docking->areaOf(m_CurInstructionScintilla) != ui->docking->areaOf(m_DisassemblyFrame))
ToolWindowManager::raiseToolWindow(m_CurInstructionScintilla);
int pos = m_CurInstructionScintilla->positionFromLine(lineInfo.lineStart - 1);
m_CurInstructionScintilla->setSelection(pos, pos);
ensureLineScrolled(m_CurInstructionScintilla, lineInfo.lineStart - 1);
}
}
if(ui->constants->topLevelItemCount() == 0)
{
@@ -1707,7 +1887,7 @@ void ShaderViewer::ensureLineScrolled(ScintillaEdit *s, int line)
int linesVisible = s->linesOnScreen();
if(s->isVisible() && (line < firstLine || line > (firstLine + linesVisible)))
s->scrollCaret();
s->setFirstVisibleLine(qMax(0, line - linesVisible / 2));
}
int ShaderViewer::CurrentStep()
@@ -2276,6 +2456,11 @@ void ShaderViewer::hideVariableTooltip()
m_TooltipVarIdx = -1;
}
bool ShaderViewer::isSourceDebugging()
{
return !m_DisassemblyFrame->isVisible();
}
void ShaderViewer::on_findReplace_clicked()
{
if(m_FindReplace->isVisible())
+9 -1
View File
@@ -117,7 +117,7 @@ private slots:
// manual slots
void readonly_keyPressed(QKeyEvent *event);
void editable_keyPressed(QKeyEvent *event);
void disassembly_contextMenu(const QPoint &pos);
void debug_contextMenu(const QPoint &pos);
void disassembly_buttonReleased(QMouseEvent *event);
void disassemble_typeChanged(int index);
void watch_keyPress(QKeyEvent *event);
@@ -162,6 +162,8 @@ private:
void updateVariableTooltip();
void hideVariableTooltip();
bool isSourceDebugging();
VariableCategory m_TooltipVarCat = VariableCategory::Temporaries;
int m_TooltipVarIdx = -1;
int m_TooltipArrayIdx = -1;
@@ -182,6 +184,9 @@ private:
ScintillaEdit *m_FindResults = NULL;
QList<ScintillaEdit *> m_Scintillas;
ScintillaEdit *m_CurInstructionScintilla = NULL;
QList<ScintillaEdit *> m_FileScintillas;
FindReplace *m_FindReplace;
struct FindState
@@ -211,6 +216,9 @@ private:
static const int BREAKPOINT_MARKER = 2;
static const int FINISHED_MARKER = 4;
static const int CURRENT_INDICATOR = 20;
static const int FINISHED_INDICATOR = 21;
static const int INDICATOR_FINDRESULT = 0;
static const int INDICATOR_REGHIGHLIGHT = 1;
+61 -7
View File
@@ -289,6 +289,61 @@ components are used). This list will have the same number of elements as :data:`
};
DECLARE_REFLECTION_STRUCT(LocalVariableMapping);
DOCUMENT("Details the current region of code that an instruction maps to");
struct LineColumnInfo
{
DOCUMENT("");
bool operator==(const LineColumnInfo &o) const
{
return fileIndex == o.fileIndex && lineStart == o.lineStart && lineEnd == o.lineEnd &&
colStart == o.colStart && colEnd == o.colEnd && callstack == o.callstack;
}
bool operator<(const LineColumnInfo &o) const
{
if(!(fileIndex == o.fileIndex))
return fileIndex < o.fileIndex;
if(!(lineStart == o.lineStart))
return lineStart < o.lineStart;
if(!(lineEnd == o.lineEnd))
return lineEnd < o.lineEnd;
if(!(colStart == o.colStart))
return colStart < o.colStart;
if(!(colEnd == o.colEnd))
return colEnd < o.colEnd;
if(!(callstack == o.callstack))
return callstack < o.callstack;
return false;
}
DOCUMENT("The current file, as an index into the list of files for this shader.");
int32_t fileIndex = -1;
DOCUMENT("The line-number (starting from 1) of the start of the current section of code.");
uint32_t lineStart = 0;
DOCUMENT("The line-number (starting from 1) of the end of the current section of code.");
uint32_t lineEnd = 0;
DOCUMENT(R"(The column number (starting from 1) of the start of the code on the line specified by
:data:`lineStart`. If set to 0, no column information is available and the whole lines should be
treated as covering the code.
)");
uint32_t colStart = 0;
DOCUMENT(R"(The column number (starting from 1) of the end of the code on the line specified by
:data:`lineEnd`. If set to 0, no column information is available and the whole lines should be
treated as covering the code.
)");
uint32_t colEnd = 0;
DOCUMENT(R"(A ``list`` of ``str`` with each function call in the current callstack at this line.
The oldest/outer function is first in the list, the newest/inner function is last.
)");
rdcarray<rdcstr> callstack;
};
DECLARE_REFLECTION_STRUCT(LineColumnInfo);
DOCUMENT(R"(This stores the current state of shader debugging at one particular step in the shader,
with all mutable variable contents.
)");
@@ -298,8 +353,7 @@ struct ShaderDebugState
bool operator==(const ShaderDebugState &o) const
{
return registers == o.registers && outputs == o.outputs && indexableTemps == o.indexableTemps &&
locals == o.locals && nextInstruction == o.nextInstruction && flags == o.flags &&
callstack == o.callstack;
locals == o.locals && nextInstruction == o.nextInstruction && flags == o.flags;
}
bool operator<(const ShaderDebugState &o) const
{
@@ -315,8 +369,6 @@ 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:`ShaderVariable`.");
@@ -332,9 +384,6 @@ to which registers, and their type
)");
rdcarray<LocalVariableMapping> locals;
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``.
)");
@@ -368,6 +417,11 @@ instruction was executed
DOCUMENT("A flag indicating whether this trace has locals information");
bool hasLocals = false;
DOCUMENT(R"(A ``list`` of :class:`LineColumnInfo` detailing which source lines each instruction
corresponds to
)");
rdcarray<LineColumnInfo> lineInfo;
};
DECLARE_REFLECTION_STRUCT(ShaderDebugTrace);
+33 -12
View File
@@ -940,8 +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);
dxbc->m_DebugInfo->GetLocals(0, dxbc->GetInstruction(0).offset, initialState.locals);
if(dxbc->m_DebugInfo)
dxbc->m_DebugInfo->GetLocals(0, dxbc->GetInstruction(0).offset, initialState.locals);
states.push_back((State)initialState);
@@ -954,9 +954,9 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
initialState = initialState.GetNext(global, NULL);
if(dxbc->m_DebugInfo)
{
const ASMOperation &op = dxbc->GetInstruction((size_t)initialState.nextInstruction);
dxbc->m_DebugInfo->GetStack(initialState.nextInstruction, op.offset, initialState.callstack);
dxbc->m_DebugInfo->GetLocals(initialState.nextInstruction, op.offset, initialState.locals);
}
@@ -971,7 +971,14 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
ret.states = states;
ret.hasLocals = dxbc->m_DebugInfo->HasLocals();
ret.hasLocals = dxbc->m_DebugInfo && dxbc->m_DebugInfo->HasLocals();
ret.lineInfo.resize(dxbc->GetNumInstructions());
for(size_t i = 0; i < dxbc->GetNumInstructions(); i++)
{
const ASMOperation &op = dxbc->GetInstruction(i);
dxbc->m_DebugInfo->GetLineInfo(i, op.offset, ret.lineInfo[i]);
}
return ret;
}
@@ -1821,8 +1828,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);
dxbc->m_DebugInfo->GetLocals(0, dxbc->GetInstruction(0).offset, quad[destIdx].locals);
if(dxbc->m_DebugInfo)
dxbc->m_DebugInfo->GetLocals(0, dxbc->GetInstruction(0).offset, quad[destIdx].locals);
states.push_back((State)quad[destIdx]);
@@ -1860,9 +1867,9 @@ ShaderDebugTrace D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
{
State &s = curquad[destIdx];
if(dxbc->m_DebugInfo)
{
const ASMOperation &op = dxbc->GetInstruction((size_t)s.nextInstruction);
dxbc->m_DebugInfo->GetStack(s.nextInstruction, op.offset, s.callstack);
dxbc->m_DebugInfo->GetLocals(s.nextInstruction, op.offset, s.locals);
}
@@ -1959,7 +1966,14 @@ ShaderDebugTrace D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
traces[destIdx].states = states;
traces[destIdx].hasLocals = dxbc->m_DebugInfo->HasLocals();
traces[destIdx].hasLocals = dxbc->m_DebugInfo && dxbc->m_DebugInfo->HasLocals();
traces[destIdx].lineInfo.resize(dxbc->GetNumInstructions());
for(size_t i = 0; i < dxbc->GetNumInstructions(); i++)
{
const ASMOperation &op = dxbc->GetInstruction(i);
dxbc->m_DebugInfo->GetLineInfo(i, op.offset, traces[destIdx].lineInfo[i]);
}
return traces[destIdx];
}
@@ -2018,8 +2032,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);
dxbc->m_DebugInfo->GetLocals(0, dxbc->GetInstruction(0).offset, initialState.locals);
if(dxbc->m_DebugInfo)
dxbc->m_DebugInfo->GetLocals(0, dxbc->GetInstruction(0).offset, initialState.locals);
states.push_back((State)initialState);
@@ -2030,9 +2044,9 @@ ShaderDebugTrace D3D11Replay::DebugThread(uint32_t eventId, const uint32_t group
initialState = initialState.GetNext(global, NULL);
if(dxbc->m_DebugInfo)
{
const ASMOperation &op = dxbc->GetInstruction((size_t)initialState.nextInstruction);
dxbc->m_DebugInfo->GetStack(initialState.nextInstruction, op.offset, initialState.callstack);
dxbc->m_DebugInfo->GetLocals(initialState.nextInstruction, op.offset, initialState.locals);
}
@@ -2047,7 +2061,14 @@ ShaderDebugTrace D3D11Replay::DebugThread(uint32_t eventId, const uint32_t group
ret.states = states;
ret.hasLocals = dxbc->m_DebugInfo->HasLocals();
ret.hasLocals = dxbc->m_DebugInfo && dxbc->m_DebugInfo->HasLocals();
ret.lineInfo.resize(dxbc->GetNumInstructions());
for(size_t i = 0; i < dxbc->GetNumInstructions(); i++)
{
const ASMOperation &op = dxbc->GetInstruction(i);
dxbc->m_DebugInfo->GetLineInfo(i, op.offset, ret.lineInfo[i]);
}
return ret;
}
@@ -665,9 +665,7 @@ void DXBCFile::MakeDisassemblyString()
}
}
int32_t prevFile = -1;
int32_t prevLine = -1;
std::string prevFunc;
LineColumnInfo prevLineInfo;
size_t debugInst = 0;
@@ -694,27 +692,33 @@ void DXBCFile::MakeDisassemblyString()
if(m_DebugInfo)
{
int32_t fileID = prevFile;
int32_t lineNum = prevLine;
std::string func = prevFunc;
LineColumnInfo lineInfo = prevLineInfo;
m_DebugInfo->GetLineInfo(debugInst, m_Instructions[i].offset, fileID, lineNum, func);
m_DebugInfo->GetLineInfo(debugInst, m_Instructions[i].offset, lineInfo);
if(fileID >= 0 && lineNum >= 0 && (fileID != prevFile || lineNum != prevLine))
if(lineInfo.fileIndex >= 0 && lineInfo.lineStart >= 0 &&
(lineInfo.fileIndex != prevLineInfo.fileIndex ||
lineInfo.lineStart != prevLineInfo.lineStart))
{
string line = "";
if(fileID >= (int32_t)fileLines.size())
if(lineInfo.fileIndex >= (int32_t)fileLines.size())
{
line = "Unknown file";
}
else if(fileLines[fileID].empty())
else if(fileLines[lineInfo.fileIndex].empty())
{
line = "";
}
else
{
int32_t lineIdx = RDCMIN(lineNum, (int32_t)fileLines[fileID].size() - 1);
line = fileLines[fileID][lineIdx];
std::vector<std::string> &lines = fileLines[lineInfo.fileIndex];
int32_t lineIdx = RDCMIN(lineInfo.lineStart, (uint32_t)lines.size() - 1);
// line numbers are 1-based but we want a 0-based index
if(lineIdx > 0)
lineIdx--;
line = lines[lineIdx];
}
size_t startLine = line.find_first_not_of(" \t");
@@ -724,23 +728,27 @@ void DXBCFile::MakeDisassemblyString()
m_Disassembly += "\n";
if(((fileID != prevFile || func != prevFunc) && fileID < (int32_t)fileLines.size()) ||
if(((lineInfo.fileIndex != prevLineInfo.fileIndex ||
lineInfo.callstack.back() != prevLineInfo.callstack.back()) &&
lineInfo.fileIndex < (int32_t)fileLines.size()) ||
line == "")
{
m_Disassembly += " "; // "0000: "
for(int in = 0; in < indent; in++)
m_Disassembly += " ";
std::string func = lineInfo.callstack.back();
if(!func.empty())
{
m_Disassembly +=
StringFormat::Fmt("%s:%d - %s()\n", m_DebugInfo->Files[fileID].first.c_str(),
lineNum + 1, func.c_str());
m_Disassembly += StringFormat::Fmt("%s:%d - %s()\n",
m_DebugInfo->Files[lineInfo.fileIndex].first.c_str(),
lineInfo.lineStart, func.c_str());
}
else
{
m_Disassembly +=
StringFormat::Fmt("%s:%d\n", m_DebugInfo->Files[fileID].first.c_str(), lineNum + 1);
m_Disassembly += StringFormat::Fmt(
"%s:%d\n", m_DebugInfo->Files[lineInfo.fileIndex].first.c_str(), lineInfo.lineStart);
}
}
@@ -753,9 +761,7 @@ void DXBCFile::MakeDisassemblyString()
}
}
prevFile = fileID;
prevLine = lineNum;
prevFunc = func;
prevLineInfo = lineInfo;
}
char buf[64] = {0};
+1 -3
View File
@@ -330,9 +330,7 @@ public:
vector<pair<string, string> > Files; // <filename, source>
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;
virtual void GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const = 0;
virtual bool HasLocals() const = 0;
virtual void GetLocals(size_t instruction, uintptr_t offset,
+7 -10
View File
@@ -98,8 +98,7 @@ SDBGChunk::SDBGChunk(void *data)
m_HasDebugInfo = true;
}
void SDBGChunk::GetLineInfo(size_t instruction, uintptr_t offset, int32_t &fileIdx,
int32_t &lineNum, std::string &func) const
void SDBGChunk::GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const
{
if(instruction < m_Instructions.size())
{
@@ -108,18 +107,16 @@ void SDBGChunk::GetLineInfo(size_t instruction, uintptr_t offset, int32_t &fileI
{
const SDBGSymbol &sym = m_SymbolTable[symID];
fileIdx = sym.fileID;
lineNum = sym.lineNum - 1;
func = m_Entry;
lineInfo.fileIndex = sym.fileID;
lineInfo.lineStart = sym.lineNum;
lineInfo.lineEnd = sym.lineNum;
lineInfo.colStart = 0;
lineInfo.colEnd = 0;
lineInfo.callstack = {m_Entry};
}
}
}
void SDBGChunk::GetStack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &stack) const
{
stack = {"Stack not available"};
}
bool SDBGChunk::HasLocals() const
{
return false;
+1 -3
View File
@@ -260,9 +260,7 @@ public:
string GetEntryFunction() const { return m_Entry; }
string GetShaderProfile() const { return m_Profile; }
uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; }
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;
void GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const;
bool HasLocals() const;
void GetLocals(size_t instruction, uintptr_t offset, rdcarray<LocalVariableMapping> &locals) const;
+4 -23
View File
@@ -1257,7 +1257,6 @@ SPDBChunk::SPDBChunk(void *chunk)
lineCol.fileIndex = fileIdx;
lineCol.lineStart = line.linenumStart;
lineCol.lineEnd = line.linenumStart + line.deltaLineEnd;
lineCol.statement = line.fStatement;
if(hasColumns)
{
@@ -1313,7 +1312,7 @@ SPDBChunk::SPDBChunk(void *chunk)
}
for(auto it = m_Lines.begin(); it != m_Lines.end(); ++it)
it->second.stack.push_back(m_Functions[0].name);
it->second.callstack.push_back(m_Functions[0].name);
SPDBLOG("Applying %zu inline sites", inlines.size());
@@ -1360,12 +1359,11 @@ SPDBChunk::SPDBChunk(void *chunk)
loc.lineEnd + inlines[i].baseLineNum, loc.colEnd);
it->second.fileIndex = fileIdx;
it->second.funcIndex = inlines[i].id;
it->second.lineStart = loc.lineStart + inlines[i].baseLineNum;
it->second.lineEnd = loc.lineEnd + inlines[i].baseLineNum;
it->second.colStart = loc.colStart;
it->second.colEnd = loc.colEnd;
it->second.stack.push_back(m_Functions[inlines[i].id].name);
it->second.callstack.push_back(m_Functions[inlines[i].id].name);
nPatched++;
}
}
@@ -1428,29 +1426,12 @@ SPDBChunk::SPDBChunk(void *chunk)
m_HasDebugInfo = true;
}
void SPDBChunk::GetLineInfo(size_t instruction, uintptr_t offset, int32_t &fileIdx,
int32_t &lineNum, std::string &func) const
void SPDBChunk::GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const
{
auto it = m_Lines.lower_bound((uint32_t)offset);
if(it != m_Lines.end() && (uintptr_t)it->first <= offset)
{
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];
}
lineInfo = it->second;
}
bool SPDBChunk::HasLocals() const
+1 -14
View File
@@ -205,17 +205,6 @@ struct FileChecksum
uint8_t hashData[1];
};
struct LineColumnInfo
{
int32_t fileIndex = -1;
uint32_t funcIndex = 0;
uint32_t lineStart = 0, lineEnd = 0;
uint32_t colStart = 0, colEnd = 0;
bool statement = true;
std::vector<std::string> stack;
};
struct InstructionLocation
{
bool statement = true;
@@ -278,9 +267,7 @@ public:
std::string GetEntryFunction() const { return m_Entry; }
std::string GetShaderProfile() const { return m_Profile; }
uint32_t GetShaderCompileFlags() const { return m_ShaderFlags; }
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;
void GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const;
bool HasLocals() const;
void GetLocals(size_t instruction, uintptr_t offset, rdcarray<LocalVariableMapping> &locals) const;
+16 -3
View File
@@ -354,6 +354,19 @@ void DoSerialise(SerialiserType &ser, LocalVariableMapping &el)
SIZE_CHECK(40);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, LineColumnInfo &el)
{
SERIALISE_MEMBER(fileIndex);
SERIALISE_MEMBER(lineStart);
SERIALISE_MEMBER(lineEnd);
SERIALISE_MEMBER(colStart);
SERIALISE_MEMBER(colEnd);
SERIALISE_MEMBER(callstack);
SIZE_CHECK(40);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, ShaderDebugState &el)
{
@@ -363,9 +376,8 @@ void DoSerialise(SerialiserType &ser, ShaderDebugState &el)
SERIALISE_MEMBER(locals);
SERIALISE_MEMBER(nextInstruction);
SERIALISE_MEMBER(flags);
SERIALISE_MEMBER(callstack);
SIZE_CHECK(88);
SIZE_CHECK(72);
}
template <typename SerialiserType>
@@ -375,8 +387,9 @@ void DoSerialise(SerialiserType &ser, ShaderDebugTrace &el)
SERIALISE_MEMBER(constantBlocks);
SERIALISE_MEMBER(states);
SERIALISE_MEMBER(hasLocals);
SERIALISE_MEMBER(lineInfo);
SIZE_CHECK(56);
SIZE_CHECK(72);
}
template <typename SerialiserType>