in qrenderdoc/Windows/ShaderViewer.cpp [394:1177]
void ShaderViewer::debugShader(const ShaderReflection *shader, ResourceId pipeline,
ShaderDebugTrace *trace, const QString &debugContext)
{
m_ShaderDetails = shader;
m_Pipeline = pipeline;
m_Trace = trace;
m_Stage = ShaderStage::Vertex;
m_DebugContext = debugContext;
// no recompilation happening, hide that group
ui->compilationGroup->hide();
// no replacing allowed, stay in find mode
m_FindReplace->allowUserModeChange(false);
if(!m_ShaderDetails)
m_Trace = NULL;
if(m_ShaderDetails)
{
m_Stage = m_ShaderDetails->stage;
QPointer<ShaderViewer> me(this);
m_Ctx.Replay().AsyncInvoke([me, this](IReplayController *r) {
if(!me)
return;
rdcarray<rdcstr> targets = r->GetDisassemblyTargets(m_Pipeline != ResourceId());
if(m_Pipeline == ResourceId())
{
rdcarray<rdcstr> pipelineTargets = r->GetDisassemblyTargets(true);
if(pipelineTargets.size() > targets.size())
{
m_PipelineTargets = pipelineTargets;
m_PipelineTargets.removeIf([&targets](const rdcstr &t) { return targets.contains(t); });
}
}
rdcstr disasm = r->DisassembleShader(m_Pipeline, m_ShaderDetails, "");
if(!me)
return;
GUIInvoke::call(this, [this, targets, disasm]() {
QStringList targetNames;
for(int i = 0; i < targets.count(); i++)
{
QString target = targets[i];
targetNames << QString(targets[i]);
if(i == 0)
{
// add any custom decompiling tools we have after the first one
for(const ShaderProcessingTool &d : m_Ctx.Config().ShaderProcessors)
{
if(d.input == m_ShaderDetails->encoding && IsTextRepresentation(d.output))
targetNames << targetName(d);
}
}
}
if(!m_PipelineTargets.empty())
targetNames << tr("More disassembly formats...");
m_DisassemblyType->clear();
m_DisassemblyType->addItems(targetNames);
m_DisassemblyType->setCurrentIndex(0);
QObject::connect(m_DisassemblyType, OverloadedSlot<int>::of(&QComboBox::currentIndexChanged),
this, &ShaderViewer::disassemble_typeChanged);
// read-only applies to us too!
m_DisassemblyView->setReadOnly(false);
SetTextAndUpdateMargin0(m_DisassemblyView, disasm);
m_DisassemblyView->setReadOnly(true);
});
});
}
updateWindowTitle();
// we always want to highlight words/registers
QObject::connect(m_DisassemblyView, &ScintillaEdit::buttonReleased, this,
&ShaderViewer::disassembly_buttonReleased);
if(m_Trace)
{
if(m_Stage == ShaderStage::Vertex)
{
ANALYTIC_SET(ShaderDebug.Vertex, true);
}
else if(m_Stage == ShaderStage::Pixel)
{
ANALYTIC_SET(ShaderDebug.Pixel, true);
}
else if(m_Stage == ShaderStage::Compute)
{
ANALYTIC_SET(ShaderDebug.Compute, true);
}
m_DisassemblyFrame->layout()->removeWidget(m_DisassemblyToolbar);
}
if(m_ShaderDetails && !m_ShaderDetails->debugInfo.files.isEmpty())
{
updateWindowTitle();
// add all the files, skipping any that have empty contents. We push a NULL in that case so the
// indices still match up with what the debug info expects. Debug info *shouldn't* point us at
// an empty file, but if it does we'll just bail out when we see NULL
m_FileScintillas.reserve(m_ShaderDetails->debugInfo.files.count());
QWidget *sel = NULL;
int32_t entryFile = m_ShaderDetails->debugInfo.entryLocation.fileIndex;
int32_t i = -1;
for(const ShaderSourceFile &f : m_ShaderDetails->debugInfo.files)
{
i++;
if(f.contents.isEmpty())
{
m_FileScintillas.push_back(NULL);
continue;
}
QString name = QFileInfo(f.filename).fileName();
QString text = f.contents;
ScintillaEdit *scintilla = AddFileScintilla(name, text, m_ShaderDetails->debugInfo.encoding);
if(sel == NULL)
sel = scintilla;
if(i == entryFile)
{
sel = scintilla;
if(m_ShaderDetails->debugInfo.entryLocation.lineStart > 0)
{
GUIInvoke::defer(scintilla, [scintilla, this]() {
ensureLineScrolled(scintilla, m_ShaderDetails->debugInfo.entryLocation.lineStart);
});
}
}
m_FileScintillas.push_back(scintilla);
}
if(m_Trace || sel == NULL)
sel = m_DisassemblyFrame;
if(m_ShaderDetails->debugInfo.files.size() > 2)
addFileList();
ToolWindowManager::raiseToolWindow(sel);
}
// hide edit buttons
ui->refresh->hide();
ui->unrefresh->hide();
ui->resetEdits->hide();
ui->editStatusLabel->hide();
ui->snippets->hide();
ui->editSep->hide();
if(m_Trace)
{
// hide signatures
ui->inputSig->hide();
ui->outputSig->hide();
// hide int/float toggles except on DXBC, other encodings are strongly typed
if(m_ShaderDetails->encoding != ShaderEncoding::DXBC)
{
ui->intView->hide();
ui->floatView->hide();
}
if(!m_ShaderDetails->debugInfo.sourceDebugInformation)
{
ui->debugToggle->setEnabled(false);
ui->debugToggle->setText(tr("Source debugging Unavailable"));
}
ui->debugVars->setColumns({tr("Name"), tr("Value")});
ui->debugVars->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
ui->debugVars->header()->setSectionResizeMode(1, QHeaderView::Interactive);
ui->sourceVars->setColumns({tr("Name"), tr("Register(s)"), tr("Type"), tr("Value")});
ui->sourceVars->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
ui->sourceVars->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
ui->sourceVars->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
ui->sourceVars->header()->setSectionResizeMode(3, QHeaderView::Interactive);
ui->constants->setColumns({tr("Name"), tr("Register(s)"), tr("Type"), tr("Value")});
ui->constants->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
ui->constants->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
ui->constants->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
ui->constants->header()->setSectionResizeMode(3, QHeaderView::Interactive);
ui->constants->header()->resizeSection(0, 80);
ui->accessedResources->setColumns({tr("Location"), tr("Type"), tr("Info")});
ui->accessedResources->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
ui->accessedResources->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
ui->accessedResources->header()->setSectionResizeMode(2, QHeaderView::Interactive);
ui->accessedResources->header()->resizeSection(0, 80);
ui->debugVars->setTooltipElidedItems(false);
ui->constants->setTooltipElidedItems(false);
ui->accessedResources->setTooltipElidedItems(false);
ui->watch->setColumns({tr("Name"), tr("Register(s)"), tr("Type"), tr("Value")});
ui->watch->header()->setSectionResizeMode(0, QHeaderView::Interactive);
ui->watch->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
ui->watch->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
ui->watch->header()->setSectionResizeMode(3, QHeaderView::Interactive);
ui->watch->header()->resizeSection(0, 80);
ui->watch->setItemDelegate(new FullEditorDelegate(ui->watch));
ToolWindowManager::ToolWindowProperty windowProps =
ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow;
ui->watch->setWindowTitle(tr("Watch"));
ui->docking->addToolWindow(
ui->watch, ToolWindowManager::AreaReference(ToolWindowManager::BottomOf,
ui->docking->areaOf(m_DisassemblyFrame), 0.25f));
ui->docking->setToolWindowProperties(ui->watch, windowProps);
ui->debugVars->setWindowTitle(tr("Variable Values"));
ui->docking->addToolWindow(
ui->debugVars,
ToolWindowManager::AreaReference(ToolWindowManager::AddTo, ui->docking->areaOf(ui->watch)));
ui->docking->setToolWindowProperties(ui->debugVars, windowProps);
ui->constants->setWindowTitle(tr("Constants && Resources"));
ui->docking->addToolWindow(
ui->constants, ToolWindowManager::AreaReference(ToolWindowManager::LeftOf,
ui->docking->areaOf(ui->debugVars), 0.5f));
ui->docking->setToolWindowProperties(ui->constants, windowProps);
ui->resourcesPanel->setWindowTitle(tr("Accessed Resources"));
ui->docking->addToolWindow(
ui->resourcesPanel, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
ui->docking->areaOf(ui->constants)));
ui->docking->setToolWindowProperties(ui->resourcesPanel, windowProps);
ui->docking->raiseToolWindow(ui->constants);
ui->callstack->setWindowTitle(tr("Callstack"));
ui->docking->addToolWindow(
ui->callstack, ToolWindowManager::AreaReference(ToolWindowManager::RightOf,
ui->docking->areaOf(ui->debugVars), 0.2f));
ui->docking->setToolWindowProperties(ui->callstack, windowProps);
ui->sourceVars->setWindowTitle(tr("High-level Variables"));
ui->docking->addToolWindow(
ui->sourceVars, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
ui->docking->areaOf(ui->debugVars)));
ui->docking->setToolWindowProperties(ui->sourceVars, windowProps);
bool hasLineInfo = false;
LineColumnInfo prevLine;
for(uint32_t inst = 0; inst < m_Trace->instInfo.size(); inst++)
{
const InstructionSourceInfo &instInfo = m_Trace->instInfo[inst];
LineColumnInfo line = instInfo.lineInfo;
int disasmLine = (int)line.disassemblyLine;
if(disasmLine > 0 && disasmLine >= m_AsmLine2Inst.size())
{
int oldSize = m_AsmLine2Inst.size();
m_AsmLine2Inst.resize(disasmLine + 1);
for(int i = oldSize; i < disasmLine; i++)
m_AsmLine2Inst[i] = -1;
}
if(disasmLine > 0)
m_AsmLine2Inst[disasmLine] = (int)instInfo.instruction;
if(line.fileIndex < 0)
continue;
hasLineInfo = true;
// store the source location *without* any disassembly line
line.disassemblyLine = 0;
// skip any instructions with the same mapping as the last one, this is a contiguous block
if(line.SourceEqual(prevLine))
continue;
prevLine = line;
m_Location2Inst[line].push_back(instInfo.instruction);
}
// if we don't have line mapping info, assume we also don't have useful high-level variable
// info. Show the debug variables first rather than a potentially empty source variables panel.
if(!hasLineInfo)
ui->docking->raiseToolWindow(ui->debugVars);
// set up stepping/running actions
// we register the shortcuts via MainWindow so that it works regardless of the active scintilla
// but still handles multiple shader viewers being present (the one with focus will get the
// input)
// all shortcuts have a reverse version with shift. This means step out is Ctrl-F11 instead of
// Shift-F11, but otherwise the shortcuts behave the same as visual studio
{
QMenu *backwardsMenu = new QMenu(this);
backwardsMenu->setToolTipsVisible(true);
QAction *act;
act = MakeExecuteAction(tr("&Run backwards"), Icons::control_start_blue(),
tr("Run backwards to the start of the shader"),
QKeySequence(Qt::Key_F5 | Qt::ShiftModifier));
QObject::connect(act, &QAction::triggered, [this]() { runTo(~0U, false); });
backwardsMenu->addAction(act);
act = MakeExecuteAction(
tr("Run backwards to &Cursor"), Icons::control_reverse_cursor_blue(),
tr("Run backwards until execution reaches the cursor, or the start of the shader"),
QKeySequence(Qt::Key_F10 | Qt::ControlModifier | Qt::ShiftModifier));
QObject::connect(act, &QAction::triggered, [this]() { runToCursor(false); });
backwardsMenu->addAction(act);
act = MakeExecuteAction(tr("Run backwards to &Sample"), Icons::control_reverse_sample_blue(),
tr("Run backwards until execution reads from a resource, or the "
"start of the shader is reached"),
QKeySequence());
QObject::connect(act, &QAction::triggered,
[this]() { runTo(~0U, false, ShaderEvents::SampleLoadGather); });
backwardsMenu->addAction(act);
act = MakeExecuteAction(
tr("Run backwards to &NaN/Inf"), Icons::control_reverse_nan_blue(),
tr("Run backwards until a floating point instruction generates a NaN "
"or Inf, an integer instruction divides by 0, or the start of the shader is reached"),
QKeySequence());
QObject::connect(act, &QAction::triggered,
[this]() { runTo(~0U, false, ShaderEvents::GeneratedNanOrInf); });
backwardsMenu->addAction(act);
backwardsMenu->addSeparator();
act = MakeExecuteAction(tr("Step backwards &Over"), Icons::control_reverse_blue(),
tr("Step backwards, and don't enter functions when source debugging"),
QKeySequence(Qt::Key_F10 | Qt::ShiftModifier));
QObject::connect(act, &QAction::triggered, [this]() { step(false, StepOver); });
backwardsMenu->addAction(act);
act = MakeExecuteAction(tr("Step backwards &Into"), Icons::control_reverse_blue(),
tr("Step backwards, entering functions when source debugging"),
QKeySequence(Qt::Key_F11 | Qt::ShiftModifier));
QObject::connect(act, &QAction::triggered, [this]() { step(false, StepInto); });
backwardsMenu->addAction(act);
act =
MakeExecuteAction(tr("Step backwards Ou&t"), Icons::control_reverse_blue(),
tr("Step backwards, out of the current function when source debugging"),
QKeySequence(Qt::Key_F11 | Qt::ControlModifier | Qt::ShiftModifier));
QObject::connect(act, &QAction::triggered, [this]() { step(false, StepOut); });
backwardsMenu->addAction(act);
ui->execBackwards->setMenu(backwardsMenu);
}
{
QMenu *forwardsMenu = new QMenu(this);
forwardsMenu->setToolTipsVisible(true);
QAction *act;
act = MakeExecuteAction(tr("&Run forwards"), Icons::control_end_blue(),
tr("Run forwards to the start of the shader"),
QKeySequence(Qt::Key_F5));
QObject::connect(act, &QAction::triggered, [this]() { runTo(~0U, true); });
forwardsMenu->addAction(act);
act = MakeExecuteAction(
tr("Run forwards to &Cursor"), Icons::control_cursor_blue(),
tr("Run forwards until execution reaches the cursor, or the end of the shader"),
QKeySequence(Qt::Key_F10 | Qt::ControlModifier));
QObject::connect(act, &QAction::triggered, [this]() { runToCursor(true); });
forwardsMenu->addAction(act);
act = MakeExecuteAction(tr("Run forwards to &Sample"), Icons::control_sample_blue(),
tr("Run forwards until execution reads from a resource, or the "
"end of the shader is reached"),
QKeySequence());
QObject::connect(act, &QAction::triggered,
[this]() { runTo(~0U, true, ShaderEvents::SampleLoadGather); });
forwardsMenu->addAction(act);
act = MakeExecuteAction(
tr("Run forwards to &NaN/Inf"), Icons::control_nan_blue(),
tr("Run forwards until a floating point instruction generates a NaN "
"or Inf, an integer instruction divides by 0, or the end of the shader is reached"),
QKeySequence());
QObject::connect(act, &QAction::triggered,
[this]() { runTo(~0U, true, ShaderEvents::GeneratedNanOrInf); });
forwardsMenu->addAction(act);
forwardsMenu->addSeparator();
act = MakeExecuteAction(tr("Step forwards &Over"), Icons::control_play_blue(),
tr("Step forwards, and don't enter functions when source debugging"),
QKeySequence(Qt::Key_F10));
QObject::connect(act, &QAction::triggered, [this]() { step(true, StepOver); });
forwardsMenu->addAction(act);
act = MakeExecuteAction(tr("Step forwards &Into"), Icons::control_play_blue(),
tr("Step forwards, entering functions when source debugging"),
QKeySequence(Qt::Key_F11));
QObject::connect(act, &QAction::triggered, [this]() { step(true, StepInto); });
forwardsMenu->addAction(act);
act =
MakeExecuteAction(tr("Step forwards Ou&t"), Icons::control_play_blue(),
tr("Step forwards, out of the current function when source debugging"),
QKeySequence(Qt::Key_F11 | Qt::ControlModifier));
QObject::connect(act, &QAction::triggered, [this]() { step(true, StepOut); });
forwardsMenu->addAction(act);
ui->execForwards->setMenu(forwardsMenu);
}
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);
edit->setMouseDwellTime(500);
QObject::connect(edit, &ScintillaEdit::dwellStart, this, &ShaderViewer::disasm_tooltipShow);
QObject::connect(edit, &ScintillaEdit::dwellEnd, this, &ShaderViewer::disasm_tooltipHide);
}
// toggle breakpoint - F9
m_Ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_F9).toString(), this,
[this](QWidget *) { ToggleBreakpointOnInstruction(); });
// event filter to pick up tooltip events
ui->constants->installEventFilter(this);
ui->accessedResources->installEventFilter(this);
ui->debugVars->installEventFilter(this);
ui->watch->installEventFilter(this);
cacheResources();
m_BackgroundRunning.release();
QPointer<ShaderViewer> me(this);
m_DeferredInit = true;
m_Ctx.Replay().AsyncInvoke([this, me](IReplayController *r) {
if(!me)
return;
rdcarray<ShaderDebugState> *states = new rdcarray<ShaderDebugState>();
states->append(r->ContinueDebug(m_Trace->debugger));
rdcarray<ShaderDebugState> nextStates;
bool finished = false;
do
{
if(!me)
{
delete states;
return;
}
nextStates = r->ContinueDebug(m_Trace->debugger);
if(!me)
{
delete states;
return;
}
finished = nextStates.empty();
states->append(std::move(nextStates));
} while(!finished && m_BackgroundRunning.available() == 1);
if(!me)
{
delete states;
return;
}
m_BackgroundRunning.tryAcquire(1);
r->SetFrameEvent(m_Ctx.CurEvent(), true);
if(!me)
{
delete states;
return;
}
GUIInvoke::call(this, [this, states]() {
m_States.swap(*states);
delete states;
if(!m_States.empty())
{
for(const ShaderVariableChange &c : GetCurrentState().changes)
m_Variables.push_back(c.after);
}
bool preferSourceDebug = false;
for(const ShaderCompileFlag &flag : m_ShaderDetails->debugInfo.compileFlags.flags)
{
if(flag.name == "preferSourceDebug")
{
preferSourceDebug = true;
break;
}
}
updateDebugState();
// we do updateDebugging() again because the first call finds the scintilla for the current
// source file, the second time jumps to it.
if(preferSourceDebug)
{
// if we're not on a source line, move forward to the first source line
while(!m_CurInstructionScintilla)
{
do
{
applyForwardsChange();
if(GetCurrentInstInfo().lineInfo.fileIndex >= 0)
break;
if(IsLastState())
break;
} while(true);
updateDebugState();
if(IsLastState())
break;
}
// if we got to the last state something's wrong - we're preferring source debug but we
// didn't ever reach an instruction mapped to source lines? just reverse course and don't
// switch to source debugging
if(IsLastState())
{
m_FirstSourceStateIdx = ~0U;
runTo(~0U, false);
}
else
{
m_FirstSourceStateIdx = m_CurrentStateIdx;
gotoSourceDebugging();
updateDebugState();
}
}
m_DeferredInit = false;
for(std::function<void(ShaderViewer *)> &f : m_DeferredCommands)
f(this);
m_DeferredCommands.clear();
});
});
GUIInvoke::defer(this, [this, debugContext]() {
// wait a short while before displaying the progress dialog (which won't show if we're already
// done by the time we reach it)
for(int i = 0; m_BackgroundRunning.available() == 1 && i < 100; i++)
QThread::msleep(5);
ShowProgressDialog(
this, tr("Debugging %1").arg(debugContext),
[this]() { return m_BackgroundRunning.available() == 0; }, NULL,
[this]() { m_BackgroundRunning.acquire(); });
});
m_CurrentStateIdx = 0;
QObject::connect(ui->watch, &RDTreeWidget::keyPress, this, &ShaderViewer::watch_keyPress);
ui->watch->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(ui->watch, &RDTreeWidget::customContextMenuRequested, this,
&ShaderViewer::variables_contextMenu);
ui->constants->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(ui->constants, &RDTreeWidget::customContextMenuRequested, this,
&ShaderViewer::variables_contextMenu);
ui->debugVars->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(ui->debugVars, &RDTreeWidget::customContextMenuRequested, this,
&ShaderViewer::variables_contextMenu);
ui->sourceVars->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(ui->sourceVars, &RDTreeWidget::customContextMenuRequested, this,
&ShaderViewer::variables_contextMenu);
ui->accessedResources->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(ui->accessedResources, &RDTreeWidget::customContextMenuRequested, this,
&ShaderViewer::accessedResources_contextMenu);
RDTreeWidgetItem *item = new RDTreeWidgetItem({
QVariant(),
QVariant(),
QVariant(),
QVariant(),
});
item->setEditable(0, true);
ui->watch->addTopLevelItem(item);
ToolWindowManager::raiseToolWindow(m_DisassemblyFrame);
}
else
{
// hide watch, constants, variables
ui->watch->hide();
ui->debugVars->hide();
ui->constants->hide();
ui->resourcesPanel->hide();
ui->sourceVars->hide();
ui->callstack->hide();
// hide debugging toolbar buttons
ui->editSep->hide();
ui->execBackwards->hide();
ui->execForwards->hide();
ui->regFormatSep->hide();
ui->intView->hide();
ui->floatView->hide();
ui->debugToggleSep->hide();
ui->debugToggle->hide();
// show input and output signatures
ui->inputSig->setColumns(
{tr("Name"), tr("Index"), tr("Reg"), tr("Type"), tr("SysValue"), tr("Mask"), tr("Used")});
for(int i = 0; i < ui->inputSig->header()->count(); i++)
ui->inputSig->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
ui->outputSig->setColumns(
{tr("Name"), tr("Index"), tr("Reg"), tr("Type"), tr("SysValue"), tr("Mask"), tr("Used")});
for(int i = 0; i < ui->outputSig->header()->count(); i++)
ui->outputSig->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
if(m_ShaderDetails)
{
for(const SigParameter &s : m_ShaderDetails->inputSignature)
{
QString name = s.varName.isEmpty()
? QString(s.semanticName)
: QFormatStr("%1 (%2)").arg(s.varName).arg(s.semanticName);
if(s.semanticName.isEmpty())
name = s.varName;
QString semIdx = s.needSemanticIndex ? QString::number(s.semanticIndex) : QString();
QString regIdx =
s.systemValue == ShaderBuiltin::Undefined ? QString::number(s.regIndex) : lit("-");
ui->inputSig->addTopLevelItem(new RDTreeWidgetItem(
{name, semIdx, regIdx, TypeString(s), ToQStr(s.systemValue),
GetComponentString(s.regChannelMask), GetComponentString(s.channelUsedMask)}));
}
bool multipleStreams = false;
for(const SigParameter &s : m_ShaderDetails->outputSignature)
{
if(s.stream > 0)
{
multipleStreams = true;
break;
}
}
for(const SigParameter &s : m_ShaderDetails->outputSignature)
{
QString name = s.varName.isEmpty()
? QString(s.semanticName)
: QFormatStr("%1 (%2)").arg(s.varName).arg(s.semanticName);
if(s.semanticName.isEmpty())
name = s.varName;
if(multipleStreams)
name = QFormatStr("Stream %1 : %2").arg(s.stream).arg(name);
if(s.perPrimitiveRate)
name += tr(" (Per-Prim)");
QString semIdx = s.needSemanticIndex ? QString::number(s.semanticIndex) : QString();
QString regIdx =
s.systemValue == ShaderBuiltin::Undefined ? QString::number(s.regIndex) : lit("-");
ui->outputSig->addTopLevelItem(new RDTreeWidgetItem(
{name, semIdx, regIdx, TypeString(s), ToQStr(s.systemValue),
GetComponentString(s.regChannelMask), GetComponentString(s.channelUsedMask)}));
}
}
ui->inputSig->setWindowTitle(tr("Input Signature"));
ui->docking->addToolWindow(ui->inputSig, ToolWindowManager::AreaReference(
ToolWindowManager::BottomOf,
ui->docking->areaOf(m_DisassemblyFrame), 0.2f));
ui->docking->setToolWindowProperties(
ui->inputSig, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
ui->outputSig->setWindowTitle(tr("Output Signature"));
ui->docking->addToolWindow(
ui->outputSig, ToolWindowManager::AreaReference(ToolWindowManager::RightOf,
ui->docking->areaOf(ui->inputSig), 0.5f));
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);
}
}