diff --git a/qrenderdoc/Code/Resources.h b/qrenderdoc/Code/Resources.h index 6ab088d38..6e69bc050 100644 --- a/qrenderdoc/Code/Resources.h +++ b/qrenderdoc/Code/Resources.h @@ -28,79 +28,83 @@ #include #include -#define RESOURCE_LIST() \ - RESOURCE_DEF(add, "add.png") \ - RESOURCE_DEF(arrow_in, "arrow_in.png") \ - RESOURCE_DEF(arrow_join, "arrow_join.png") \ - RESOURCE_DEF(arrow_left, "arrow_left.png") \ - RESOURCE_DEF(arrow_refresh, "arrow_refresh.png") \ - RESOURCE_DEF(arrow_right, "arrow_right.png") \ - RESOURCE_DEF(arrow_undo, "arrow_undo.png") \ - RESOURCE_DEF(asterisk_orange, "asterisk_orange.png") \ - RESOURCE_DEF(bug, "bug.png") \ - RESOURCE_DEF(chart_curve, "chart_curve.png") \ - RESOURCE_DEF(cog, "cog.png") \ - RESOURCE_DEF(color_wheel, "color_wheel.png") \ - RESOURCE_DEF(copy, "copy.png") \ - RESOURCE_DEF(connect, "connect.png") \ - RESOURCE_DEF(control_base_blue, "control_base_blue.png") \ - RESOURCE_DEF(control_cursor_blue, "control_cursor_blue.png") \ - RESOURCE_DEF(control_end_blue, "control_end_blue.png") \ - RESOURCE_DEF(control_play_blue, "control_play_blue.png") \ - RESOURCE_DEF(control_nan_blue, "control_nan_blue.png") \ - RESOURCE_DEF(control_reverse_blue, "control_reverse_blue.png") \ - RESOURCE_DEF(control_sample_blue, "control_sample_blue.png") \ - RESOURCE_DEF(control_start_blue, "control_start_blue.png") \ - RESOURCE_DEF(cross, "cross.png") \ - RESOURCE_DEF(checkerboard, "checkerboard.png") \ - RESOURCE_DEF(cut, "cut.png") \ - RESOURCE_DEF(del, "del.png") \ - RESOURCE_DEF(disconnect, "disconnect.png") \ - RESOURCE_DEF(find, "find.png") \ - RESOURCE_DEF(filter, "filter.png") \ - RESOURCE_DEF(filter_reapply, "filter_reapply.png") \ - RESOURCE_DEF(arrow_out, "arrow_out.png") \ - RESOURCE_DEF(flag_green, "flag_green.png") \ - RESOURCE_DEF(flip_y, "flip_y.png") \ - RESOURCE_DEF(folder, "folder.png") \ - RESOURCE_DEF(folder_page_white, "folder_page_white.png") \ - RESOURCE_DEF(hourglass, "hourglass.png") \ - RESOURCE_DEF(house, "house.png") \ - RESOURCE_DEF(information, "information.png") \ - RESOURCE_DEF(link, "link.png") \ - RESOURCE_DEF(page_go, "page_go.png") \ - RESOURCE_DEF(page_white_code, "page_white_code.png") \ - RESOURCE_DEF(page_white_database, "page_white_database.png") \ - RESOURCE_DEF(page_white_delete, "page_white_delete.png") \ - RESOURCE_DEF(page_white_edit, "page_white_edit.png") \ - RESOURCE_DEF(page_white_link, "page_white_link.png") \ - RESOURCE_DEF(page_white_stack, "page_white_stack.png") \ - RESOURCE_DEF(paste, "paste.png") \ - RESOURCE_DEF(pixel_history, "pixel_history.png") \ - RESOURCE_DEF(plugin, "plugin.png") \ - RESOURCE_DEF(plugin_add, "plugin_add.png") \ - RESOURCE_DEF(save, "save.png") \ - RESOURCE_DEF(text_add, "text_add.png") \ - RESOURCE_DEF(tick, "tick.png") \ - RESOURCE_DEF(time, "time.png") \ - RESOURCE_DEF(timeline_marker, "timeline_marker.png") \ - RESOURCE_DEF(upfolder, "upfolder.png") \ - RESOURCE_DEF(update, "update.png") \ - RESOURCE_DEF(wand, "wand.png") \ - RESOURCE_DEF(wireframe_mesh, "wireframe_mesh.png") \ - RESOURCE_DEF(wrench, "wrench.png") \ - RESOURCE_DEF(zoom, "zoom.png") \ - RESOURCE_DEF(topo_linelist, "topologies/topo_linelist.svg") \ - RESOURCE_DEF(topo_linelist_adj, "topologies/topo_linelist_adj.svg") \ - RESOURCE_DEF(topo_linestrip, "topologies/topo_linestrip.svg") \ - RESOURCE_DEF(topo_linestrip_adj, "topologies/topo_linestrip_adj.svg") \ - RESOURCE_DEF(topo_patch, "topologies/topo_patch.svg") \ - RESOURCE_DEF(topo_pointlist, "topologies/topo_pointlist.svg") \ - RESOURCE_DEF(topo_trilist, "topologies/topo_trilist.svg") \ - RESOURCE_DEF(topo_trilist_adj, "topologies/topo_trilist_adj.svg") \ - RESOURCE_DEF(topo_tristrip, "topologies/topo_tristrip.svg") \ - RESOURCE_DEF(topo_tristrip_adj, "topologies/topo_tristrip_adj.svg") \ - RESOURCE_DEF(action, "action.png") \ +#define RESOURCE_LIST() \ + RESOURCE_DEF(add, "add.png") \ + RESOURCE_DEF(arrow_in, "arrow_in.png") \ + RESOURCE_DEF(arrow_join, "arrow_join.png") \ + RESOURCE_DEF(arrow_left, "arrow_left.png") \ + RESOURCE_DEF(arrow_refresh, "arrow_refresh.png") \ + RESOURCE_DEF(arrow_right, "arrow_right.png") \ + RESOURCE_DEF(arrow_undo, "arrow_undo.png") \ + RESOURCE_DEF(asterisk_orange, "asterisk_orange.png") \ + RESOURCE_DEF(bug, "bug.png") \ + RESOURCE_DEF(chart_curve, "chart_curve.png") \ + RESOURCE_DEF(cog, "cog.png") \ + RESOURCE_DEF(color_wheel, "color_wheel.png") \ + RESOURCE_DEF(copy, "copy.png") \ + RESOURCE_DEF(connect, "connect.png") \ + RESOURCE_DEF(control_base_blue, "control_base_blue.png") \ + RESOURCE_DEF(control_cursor_blue, "control_cursor_blue.png") \ + RESOURCE_DEF(control_end_blue, "control_end_blue.png") \ + RESOURCE_DEF(control_play_blue, "control_play_blue.png") \ + RESOURCE_DEF(control_nan_blue, "control_nan_blue.png") \ + RESOURCE_DEF(control_reverse_blue, "control_reverse_blue.png") \ + RESOURCE_DEF(control_reverse_base_blue, "control_reverse_base_blue.png") \ + RESOURCE_DEF(control_reverse_cursor_blue, "control_reverse_cursor_blue.png") \ + RESOURCE_DEF(control_reverse_nan_blue, "control_reverse_nan_blue.png") \ + RESOURCE_DEF(control_reverse_sample_blue, "control_reverse_sample_blue.png") \ + RESOURCE_DEF(control_sample_blue, "control_sample_blue.png") \ + RESOURCE_DEF(control_start_blue, "control_start_blue.png") \ + RESOURCE_DEF(cross, "cross.png") \ + RESOURCE_DEF(checkerboard, "checkerboard.png") \ + RESOURCE_DEF(cut, "cut.png") \ + RESOURCE_DEF(del, "del.png") \ + RESOURCE_DEF(disconnect, "disconnect.png") \ + RESOURCE_DEF(find, "find.png") \ + RESOURCE_DEF(filter, "filter.png") \ + RESOURCE_DEF(filter_reapply, "filter_reapply.png") \ + RESOURCE_DEF(arrow_out, "arrow_out.png") \ + RESOURCE_DEF(flag_green, "flag_green.png") \ + RESOURCE_DEF(flip_y, "flip_y.png") \ + RESOURCE_DEF(folder, "folder.png") \ + RESOURCE_DEF(folder_page_white, "folder_page_white.png") \ + RESOURCE_DEF(hourglass, "hourglass.png") \ + RESOURCE_DEF(house, "house.png") \ + RESOURCE_DEF(information, "information.png") \ + RESOURCE_DEF(link, "link.png") \ + RESOURCE_DEF(page_go, "page_go.png") \ + RESOURCE_DEF(page_white_code, "page_white_code.png") \ + RESOURCE_DEF(page_white_database, "page_white_database.png") \ + RESOURCE_DEF(page_white_delete, "page_white_delete.png") \ + RESOURCE_DEF(page_white_edit, "page_white_edit.png") \ + RESOURCE_DEF(page_white_link, "page_white_link.png") \ + RESOURCE_DEF(page_white_stack, "page_white_stack.png") \ + RESOURCE_DEF(paste, "paste.png") \ + RESOURCE_DEF(pixel_history, "pixel_history.png") \ + RESOURCE_DEF(plugin, "plugin.png") \ + RESOURCE_DEF(plugin_add, "plugin_add.png") \ + RESOURCE_DEF(save, "save.png") \ + RESOURCE_DEF(text_add, "text_add.png") \ + RESOURCE_DEF(tick, "tick.png") \ + RESOURCE_DEF(time, "time.png") \ + RESOURCE_DEF(timeline_marker, "timeline_marker.png") \ + RESOURCE_DEF(upfolder, "upfolder.png") \ + RESOURCE_DEF(update, "update.png") \ + RESOURCE_DEF(wand, "wand.png") \ + RESOURCE_DEF(wireframe_mesh, "wireframe_mesh.png") \ + RESOURCE_DEF(wrench, "wrench.png") \ + RESOURCE_DEF(zoom, "zoom.png") \ + RESOURCE_DEF(topo_linelist, "topologies/topo_linelist.svg") \ + RESOURCE_DEF(topo_linelist_adj, "topologies/topo_linelist_adj.svg") \ + RESOURCE_DEF(topo_linestrip, "topologies/topo_linestrip.svg") \ + RESOURCE_DEF(topo_linestrip_adj, "topologies/topo_linestrip_adj.svg") \ + RESOURCE_DEF(topo_patch, "topologies/topo_patch.svg") \ + RESOURCE_DEF(topo_pointlist, "topologies/topo_pointlist.svg") \ + RESOURCE_DEF(topo_trilist, "topologies/topo_trilist.svg") \ + RESOURCE_DEF(topo_trilist_adj, "topologies/topo_trilist_adj.svg") \ + RESOURCE_DEF(topo_tristrip, "topologies/topo_tristrip.svg") \ + RESOURCE_DEF(topo_tristrip_adj, "topologies/topo_tristrip_adj.svg") \ + RESOURCE_DEF(action, "action.png") \ RESOURCE_DEF(action_hover, "action_hover.png") struct Resource diff --git a/qrenderdoc/Resources/control_reverse_base_blue.png b/qrenderdoc/Resources/control_reverse_base_blue.png new file mode 100644 index 000000000..e11a21cf9 Binary files /dev/null and b/qrenderdoc/Resources/control_reverse_base_blue.png differ diff --git a/qrenderdoc/Resources/control_reverse_base_blue@2x.png b/qrenderdoc/Resources/control_reverse_base_blue@2x.png new file mode 100644 index 000000000..25657a222 Binary files /dev/null and b/qrenderdoc/Resources/control_reverse_base_blue@2x.png differ diff --git a/qrenderdoc/Resources/control_reverse_cursor_blue.png b/qrenderdoc/Resources/control_reverse_cursor_blue.png new file mode 100644 index 000000000..90da61cb4 Binary files /dev/null and b/qrenderdoc/Resources/control_reverse_cursor_blue.png differ diff --git a/qrenderdoc/Resources/control_reverse_cursor_blue@2x.png b/qrenderdoc/Resources/control_reverse_cursor_blue@2x.png new file mode 100644 index 000000000..63b50e2e7 Binary files /dev/null and b/qrenderdoc/Resources/control_reverse_cursor_blue@2x.png differ diff --git a/qrenderdoc/Resources/control_reverse_nan_blue.png b/qrenderdoc/Resources/control_reverse_nan_blue.png new file mode 100644 index 000000000..389eefee4 Binary files /dev/null and b/qrenderdoc/Resources/control_reverse_nan_blue.png differ diff --git a/qrenderdoc/Resources/control_reverse_nan_blue@2x.png b/qrenderdoc/Resources/control_reverse_nan_blue@2x.png new file mode 100644 index 000000000..7ae7b4bc7 Binary files /dev/null and b/qrenderdoc/Resources/control_reverse_nan_blue@2x.png differ diff --git a/qrenderdoc/Resources/control_reverse_sample_blue.png b/qrenderdoc/Resources/control_reverse_sample_blue.png new file mode 100644 index 000000000..bcd4d4bbd Binary files /dev/null and b/qrenderdoc/Resources/control_reverse_sample_blue.png differ diff --git a/qrenderdoc/Resources/control_reverse_sample_blue@2x.png b/qrenderdoc/Resources/control_reverse_sample_blue@2x.png new file mode 100644 index 000000000..bdd46f6d1 Binary files /dev/null and b/qrenderdoc/Resources/control_reverse_sample_blue@2x.png differ diff --git a/qrenderdoc/Resources/resources.qrc b/qrenderdoc/Resources/resources.qrc index 4522456e1..05048cef5 100644 --- a/qrenderdoc/Resources/resources.qrc +++ b/qrenderdoc/Resources/resources.qrc @@ -59,6 +59,14 @@ control_play_blue@2x.png control_reverse_blue.png control_reverse_blue@2x.png + control_reverse_base_blue.png + control_reverse_base_blue@2x.png + control_reverse_cursor_blue.png + control_reverse_cursor_blue@2x.png + control_reverse_nan_blue.png + control_reverse_nan_blue@2x.png + control_reverse_sample_blue.png + control_reverse_sample_blue@2x.png control_sample_blue.png control_sample_blue@2x.png control_start_blue.png diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index bc7b0d859..6f7a6d7e2 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -32,6 +32,7 @@ #include #include #include +#include "Code/Resources.h" #include "Code/ScintillaSyntax.h" #include "Widgets/FindReplace.h" #include "scintilla/include/SciLexer.h" @@ -280,14 +281,9 @@ void ShaderViewer::editShader(ResourceId id, ShaderStage stage, const QString &e ui->snippets->setVisible(m_CustomShader); // hide debugging toolbar buttons - ui->debugSep->hide(); - ui->runBack->hide(); - ui->run->hide(); - ui->stepBack->hide(); - ui->stepNext->hide(); - ui->runToCursor->hide(); - ui->runToSample->hide(); - ui->runToNaNOrInf->hide(); + ui->editSep->hide(); + ui->execBackwards->hide(); + ui->execForwards->hide(); ui->regFormatSep->hide(); ui->intView->hide(); ui->floatView->hide(); @@ -529,9 +525,9 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR } // hide edit buttons - ui->editSep->hide(); ui->refresh->hide(); ui->snippets->hide(); + ui->editSep->hide(); if(m_Trace) { @@ -539,6 +535,13 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR 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.files.isEmpty()) { ui->debugToggle->setEnabled(false); @@ -647,13 +650,144 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR if(!hasLineInfo) ui->docking->raiseToolWindow(ui->debugVars); - 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); - QObject::connect(ui->run, &QToolButton::clicked, this, &ShaderViewer::run); - QObject::connect(ui->runToCursor, &QToolButton::clicked, this, &ShaderViewer::runToCursor); - QObject::connect(ui->runToSample, &QToolButton::clicked, this, &ShaderViewer::runToSample); - QObject::connect(ui->runToNaNOrInf, &QToolButton::clicked, this, &ShaderViewer::runToNanOrInf); + // 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); + 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({}, 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({}, 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({}, 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); + 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({}, 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({}, 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({}, 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) { @@ -678,19 +812,7 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR QObject::connect(edit, &ScintillaEdit::dwellEnd, this, &ShaderViewer::disasm_tooltipHide); } - // 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) - m_Ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_F10).toString(), this, - [this](QWidget *) { stepNext(); }); - m_Ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_F10 | Qt::ShiftModifier).toString(), - this, [this](QWidget *) { stepBack(); }); - m_Ctx.GetMainWindow()->RegisterShortcut( - QKeySequence(Qt::Key_F10 | Qt::ControlModifier).toString(), this, - [this](QWidget *) { runToCursor(); }); - m_Ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_F5).toString(), this, - [this](QWidget *) { run(); }); - m_Ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_F5 | Qt::ShiftModifier).toString(), - this, [this](QWidget *) { runBack(); }); + // toggle breakpoint - F9 m_Ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_F9).toString(), this, [this](QWidget *) { ToggleBreakpointOnInstruction(); }); @@ -830,14 +952,9 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR ui->callstack->hide(); // hide debugging toolbar buttons - ui->debugSep->hide(); - ui->runBack->hide(); - ui->run->hide(); - ui->stepBack->hide(); - ui->stepNext->hide(); - ui->runToCursor->hide(); - ui->runToSample->hide(); - ui->runToNaNOrInf->hide(); + ui->editSep->hide(); + ui->execBackwards->hide(); + ui->execForwards->hide(); ui->regFormatSep->hide(); ui->intView->hide(); ui->floatView->hide(); @@ -958,6 +1075,24 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR } } +QAction *ShaderViewer::MakeExecuteAction(QString name, const QIcon &icon, QString tooltip, + QKeySequence shortcut) +{ + QAction *act = new QAction(name, this); + // set the shortcut context to something that shouldn't fire, since we want to handle this + // ourselves - we just want Qt to *display* the shortcut + act->setShortcutContext(Qt::WidgetShortcut); + act->setToolTip(tooltip); + act->setIcon(icon); + if(!shortcut.isEmpty()) + { + act->setShortcut(shortcut); + m_Ctx.GetMainWindow()->RegisterShortcut(act->shortcut().toString(), this, + [act](QWidget *) { act->activate(QAction::Trigger); }); + } + return act; +} + void ShaderViewer::updateWindowTitle() { if(m_ShaderDetails) @@ -1337,19 +1472,29 @@ void ShaderViewer::debug_contextMenu(const QPoint &pos) contextMenu.addSeparator(); QAction addBreakpoint(tr("Toggle breakpoint here"), this); - QAction runCursor(tr("Run to Cursor"), this); + QAction runForwardCursor(tr("Run forwards to Cursor"), this); + QAction runBackwardCursor(tr("Run backwards to Cursor"), this); + + addBreakpoint.setShortcut(QKeySequence(Qt::Key_F9)); + runForwardCursor.setShortcut(QKeySequence(Qt::Key_F10 | Qt::ControlModifier)); + runBackwardCursor.setShortcut(QKeySequence(Qt::Key_F10 | Qt::ControlModifier | Qt::ShiftModifier)); QObject::connect(&addBreakpoint, &QAction::triggered, [this, scintillaPos] { m_DisassemblyView->setSelection(scintillaPos, scintillaPos); ToggleBreakpointOnInstruction(); }); - QObject::connect(&runCursor, &QAction::triggered, [this, scintillaPos] { + QObject::connect(&runForwardCursor, &QAction::triggered, [this, scintillaPos] { m_DisassemblyView->setSelection(scintillaPos, scintillaPos); - runToCursor(); + runToCursor(true); + }); + QObject::connect(&runBackwardCursor, &QAction::triggered, [this, scintillaPos] { + m_DisassemblyView->setSelection(scintillaPos, scintillaPos); + runToCursor(false); }); contextMenu.addAction(&addBreakpoint); - contextMenu.addAction(&runCursor); + contextMenu.addAction(&runBackwardCursor); + contextMenu.addAction(&runForwardCursor); contextMenu.addSeparator(); QAction copyText(tr("Copy"), this); @@ -1682,100 +1827,120 @@ void ShaderViewer::on_watch_itemChanged(QTableWidgetItem *item) updateDebugState(); } -bool ShaderViewer::stepBack() +bool ShaderViewer::step(bool forward, StepMode mode) { if(!m_Trace || m_States.empty()) return false; - if(IsFirstState()) + if((forward && IsLastState()) || (!forward && IsFirstState())) return false; if(isSourceDebugging()) { LineColumnInfo oldLine = m_Trace->lineInfo[GetCurrentState().nextInstruction]; + rdcarray oldStack = GetCurrentState().callstack; - // first step to the next instruction in a backwards direction that's on a different line from - // the current one do { - applyBackwardsChange(); + // step once in the right direction + if(forward) + applyForwardsChange(); + else + applyBackwardsChange(); + // break out if we hit a breakpoint, no matter what if(m_Breakpoints.contains((int)GetCurrentState().nextInstruction)) break; - if(IsFirstState()) + // if we've reached the limit, break + if((forward && IsLastState()) || (!forward && IsFirstState())) break; - if(m_Trace->lineInfo[GetCurrentState().nextInstruction].SourceEqual(oldLine)) + // keep going if we're still on the same source line as we started + LineColumnInfo curLine = m_Trace->lineInfo[GetCurrentState().nextInstruction]; + if(curLine.SourceEqual(oldLine)) continue; - break; + // if we're stepping into, break now as soon as we hit a different line + if(mode == StepInto) + break; + + // we're on a different line but that might not be enough for Step Out or Step Over + rdcarray curStack = GetCurrentState().callstack; + + // mode is StepOver or StepOut + + if(mode == StepOver) + { + // if the stack hasn't grown, we assume that we're still in the same function so return + if(curStack.size() <= oldStack.size()) + break; + } + + if(mode == StepOut) + { + // if the stack has shrunk we must have exited the function + if(curStack.size() < oldStack.size()) + break; + } + + // if the stack is bigger (for stepover) or hasn't shrunk (for stepout) but the common subset + // is different, we have stepped into a different function due to inlining, so break + // + // E.g. A() -> B() stepover A() -> C() -> D() + // + // Or A() -> B() stepout A() -> C() + bool different = false; + for(size_t i = 0; i < qMin(curStack.size(), oldStack.size()); i++) + { + if(oldStack[i] != curStack[i]) + { + different = true; + break; + } + } + + if(different) + break; + } while(true); oldLine = m_Trace->lineInfo[GetCurrentState().nextInstruction]; - // now since a line can have multiple instructions, keep stepping (looking forward) until we - // reach the first instruction with an identical line info - while(!IsFirstState() && - m_Trace->lineInfo[GetPreviousState().nextInstruction].SourceEqual(oldLine)) + if(!forward) { - applyBackwardsChange(); + // now since a line can have multiple instructions, we may only be on the last one of several. + // Keep stepping until we reach the first instruction with an identical line info and stop + // there + while(!IsFirstState() && + m_Trace->lineInfo[GetPreviousState().nextInstruction].SourceEqual(oldLine)) + { + applyBackwardsChange(); - if(m_Breakpoints.contains((int)GetCurrentState().nextInstruction)) - break; + // still need to check for instruction-level breakpoints + if(m_Breakpoints.contains((int)GetCurrentState().nextInstruction)) + break; + } } updateDebugState(); } else { - applyBackwardsChange(); - updateDebugState(); - } + // non-source stepping is easy, we just do one instruction in that direction regardless of step + // mode - return true; -} - -bool ShaderViewer::stepNext() -{ - if(!m_Trace || m_States.empty()) - return false; - - if(IsLastState()) - return false; - - if(isSourceDebugging()) - { - LineColumnInfo oldLine = m_Trace->lineInfo[GetCurrentState().nextInstruction]; - - do - { + if(forward) applyForwardsChange(); - - if(m_Breakpoints.contains((int)GetCurrentState().nextInstruction)) - break; - - if(IsLastState()) - break; - - if(m_Trace->lineInfo[GetCurrentState().nextInstruction].SourceEqual(oldLine)) - continue; - - break; - } while(true); - - updateDebugState(); - } - else - { - applyForwardsChange(); + else + applyBackwardsChange(); updateDebugState(); } return true; } -void ShaderViewer::runToCursor() +void ShaderViewer::runToCursor(bool forward) { if(!m_Trace || m_States.empty()) return; @@ -1798,13 +1963,13 @@ void ShaderViewer::runToCursor() { if(fileMap.contains(i)) { - runTo(fileMap[i], true); + runTo(fileMap[i], forward); return; } } // if we didn't find one, just run - run(); + runTo({}, forward); } else { @@ -1815,7 +1980,7 @@ void ShaderViewer::runToCursor() int line = instructionForDisassemblyLine(i); if(line >= 0) { - runTo({(size_t)line}, true); + runTo({(size_t)line}, forward); break; } } @@ -1867,26 +2032,6 @@ const ShaderDebugState &ShaderViewer::GetNextState() const return m_States.back(); } -void ShaderViewer::runToSample() -{ - runTo({}, true, ShaderEvents::SampleLoadGather); -} - -void ShaderViewer::runToNanOrInf() -{ - runTo({}, true, ShaderEvents::GeneratedNanOrInf); -} - -void ShaderViewer::runBack() -{ - runTo({}, false); -} - -void ShaderViewer::run() -{ - runTo({}, true); -} - void ShaderViewer::runTo(QVector runToInstruction, bool forward, ShaderEvents condition) { if(!m_Trace || m_States.empty()) @@ -4097,7 +4242,7 @@ void ShaderViewer::RunForward() return; } - run(); + runTo({}, true); } void ShaderViewer::ShowErrors(const rdcstr &errors) diff --git a/qrenderdoc/Windows/ShaderViewer.h b/qrenderdoc/Windows/ShaderViewer.h index 45536994a..e90417e15 100644 --- a/qrenderdoc/Windows/ShaderViewer.h +++ b/qrenderdoc/Windows/ShaderViewer.h @@ -175,23 +175,17 @@ private slots: void disasm_tooltipShow(int x, int y); void disasm_tooltipHide(int x, int y); -public slots: - bool stepBack(); - bool stepNext(); - void runToCursor(); - void runToSample(); - void runToNanOrInf(); - void runBack(); - void run(); - private: explicit ShaderViewer(ICaptureContext &ctx, QWidget *parent = 0); void editShader(ResourceId id, ShaderStage stage, const QString &entryPoint, const rdcstrpairs &files, ShaderEncoding shaderEncoding, ShaderCompileFlags flags); void debugShader(const ShaderBindpointMapping *bind, const ShaderReflection *shader, ResourceId pipeline, ShaderDebugTrace *trace, const QString &debugContext); + bool eventFilter(QObject *watched, QEvent *event) override; + QAction *MakeExecuteAction(QString name, const QIcon &icon, QString tooltip, QKeySequence shortcut); + void MarkModification(); void PopulateCompileTools(); @@ -346,6 +340,16 @@ private: void setEditorWindowTitle(); + enum StepMode + { + StepInto, + StepOver, + StepOut, + }; + + bool step(bool forward, StepMode mode); + + void runToCursor(bool forward); void runTo(QVector runToInstructions, bool forward, ShaderEvents condition = ShaderEvents::NoEvent); diff --git a/qrenderdoc/Windows/ShaderViewer.ui b/qrenderdoc/Windows/ShaderViewer.ui index 44f4531c1..ad49456bb 100644 --- a/qrenderdoc/Windows/ShaderViewer.ui +++ b/qrenderdoc/Windows/ShaderViewer.ui @@ -117,136 +117,128 @@ - - - 20 - 310 - 256 - 192 - + + + 20 + 310 + 256 + 192 + + + + Qt::PreventContextMenu + + + QFrame::NoFrame + + + + 2 - - Qt::PreventContextMenu + + 0 - - QFrame::NoFrame + + 0 - - - 2 + + 0 + + + 0 + + + + + QFrame::NoFrame - + + true + + + + + + + + 0 + 0 + + + + Qt::PreventContextMenu + + + QFrame::NoFrame + + + 0 - - + + 0 - - + + 0 - - + + 0 - - - - - - 20 - 310 - 256 - 192 - - - - QFrame::NoFrame - - - true - + + + + + Sort accessed resource by shader binding + + + Sort By Resource + + + true + + + true + + + true + - - - - - Qt::PreventContextMenu - - - QFrame::NoFrame - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Sort By Resource - - - true - - - true - - - true - - - Sort accessed resource by shader binding - - - - - - - Sort By Instruction - - - true - - - false - - - true - - - Sort accessed resource by instruction step - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + + Sort accessed resource by instruction step + + + Sort By Instruction + + + true + + + false + + + true + - - + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + @@ -385,16 +377,19 @@ - + - Run backwards (Shift-F5) + Run or step backwards in execution - Run backwards + Execute backwards... - :/control_start_blue.png:/control_start_blue.png + :/control_reverse_blue@2x.png:/control_reverse_blue@2x.png + + + QToolButton::MenuButtonPopup Qt::ToolButtonTextBesideIcon @@ -405,141 +400,19 @@ - + - Step Back (Shift-F10) + Run or step forwards in execution - Step Back - - - - :/control_reverse_blue.png:/control_reverse_blue.png - - - Qt::ToolButtonTextBesideIcon - - - true - - - - - - - Step Next (F10) - - - Step Next + Execute forwards... :/control_play_blue.png:/control_play_blue.png - - Qt::ToolButtonTextBesideIcon - - - true - - - - - - - Qt::Vertical - - - - - - - Run forwards (F5) - - - Run forwards - - - - :/control_end_blue.png:/control_end_blue.png - - - Qt::ToolButtonTextBesideIcon - - - true - - - - - - - - 23 - 22 - - - - Run to Cursor (Ctrl-F10) - - - Run to Cursor - - - - :/control_cursor_blue.png:/control_cursor_blue.png - - - Qt::ToolButtonTextBesideIcon - - - true - - - - - - - - 23 - 22 - - - - Run to Sample/Load/Gather - - - Run to Sample - - - - :/control_sample_blue.png:/control_sample_blue.png - - - Qt::ToolButtonTextBesideIcon - - - true - - - - - - - - 23 - 22 - - - - Run to NaN or Inf - - - Run to NaN/Inf - - - - :/control_nan_blue.png:/control_nan_blue.png + + QToolButton::MenuButtonPopup Qt::ToolButtonTextBesideIcon diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index d6d4ec66c..752c5c7f2 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -1947,8 +1947,16 @@ IF %ERRORLEVEL% NEQ 0 (echo ==================================================== + + + + + + + + @@ -1963,6 +1971,8 @@ IF %ERRORLEVEL% NEQ 0 (echo ==================================================== + + diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 912c9dc70..870a2d9f5 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -1912,6 +1912,36 @@ Resources\Files + + Resources\Files + + + Resources\Files + + + Resources\Files + + + Resources\Files + + + Resources\Files + + + Resources\Files + + + Resources\Files + + + Resources\Files + + + Resources\Files + + + Resources\Files +