diff options
Diffstat (limited to 'src/citra_qt/debugger')
23 files changed, 271 insertions, 190 deletions
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index e97e81b65..d45eed179 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp @@ -4,14 +4,14 @@ #include <QStandardItemModel> +#include "citra_qt/debugger/callstack.h" + #include "common/common_types.h" #include "common/symbols.h" -#include "callstack.h" - #include "core/core.h" -#include "core/arm/arm_interface.h" #include "core/memory.h" +#include "core/arm/arm_interface.h" #include "core/arm/disassembler/arm_disasm.h" CallstackWidget::CallstackWidget(QWidget* parent): QDockWidget(parent) diff --git a/src/citra_qt/debugger/callstack.h b/src/citra_qt/debugger/callstack.h index 1a9b6dc81..7aa83db1e 100644 --- a/src/citra_qt/debugger/callstack.h +++ b/src/citra_qt/debugger/callstack.h @@ -12,7 +12,7 @@ class CallstackWidget : public QDockWidget Q_OBJECT public: - CallstackWidget(QWidget* parent = 0); + CallstackWidget(QWidget* parent = nullptr); public slots: void OnDebugModeEntered(); diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index d3629bbf6..d4f72809d 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -4,20 +4,19 @@ #include <QShortcut> -#include "disassembler.h" +#include "citra_qt/bootmanager.h" +#include "citra_qt/hotkeys.h" +#include "citra_qt/debugger/disassembler.h" +#include "citra_qt/util/util.h" -#include "../bootmanager.h" -#include "../hotkeys.h" - -#include "core/memory.h" - -#include "core/core.h" #include "common/break_points.h" #include "common/symbols.h" + +#include "core/core.h" +#include "core/memory.h" #include "core/arm/arm_interface.h" #include "core/arm/disassembler/arm_disasm.h" - DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { } @@ -78,6 +77,14 @@ QVariant DisassemblerModel::data(const QModelIndex& index, int role) const { break; } + case Qt::FontRole: + { + if (index.column() == 0 || index.column() == 1) { // 2 is the symbols column + return GetMonospaceFont(); + } + break; + } + default: break; } diff --git a/src/citra_qt/debugger/graphics.cpp b/src/citra_qt/debugger/graphics.cpp index 7d15028f0..8008f914c 100644 --- a/src/citra_qt/debugger/graphics.cpp +++ b/src/citra_qt/debugger/graphics.cpp @@ -2,11 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "graphics.h" #include <QListView> -#include <QVBoxLayout> -#include <QDebug> +#include "citra_qt/debugger/graphics.h" #include "citra_qt/util/util.h" extern GraphicsDebugger g_debugger; diff --git a/src/citra_qt/debugger/graphics.h b/src/citra_qt/debugger/graphics.h index 8119b4c87..36b25b81d 100644 --- a/src/citra_qt/debugger/graphics.h +++ b/src/citra_qt/debugger/graphics.h @@ -37,7 +37,7 @@ class GPUCommandStreamWidget : public QDockWidget Q_OBJECT public: - GPUCommandStreamWidget(QWidget* parent = 0); + GPUCommandStreamWidget(QWidget* parent = nullptr); private: }; diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.cpp b/src/citra_qt/debugger/graphics_breakpoint_observer.cpp index 10ac1ebad..f134eef63 100644 --- a/src/citra_qt/debugger/graphics_breakpoint_observer.cpp +++ b/src/citra_qt/debugger/graphics_breakpoint_observer.cpp @@ -4,7 +4,7 @@ #include <QMetaType> -#include "graphics_breakpoint_observer.h" +#include "citra_qt/debugger/graphics_breakpoint_observer.h" BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, const QString& title, QWidget* parent) diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index 5202c168c..819ec7707 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -2,16 +2,16 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <QLabel> #include <QMetaType> #include <QPushButton> #include <QTreeView> #include <QVBoxLayout> -#include <QLabel> -#include "common/assert.h" +#include "citra_qt/debugger/graphics_breakpoints.h" +#include "citra_qt/debugger/graphics_breakpoints_p.h" -#include "graphics_breakpoints.h" -#include "graphics_breakpoints_p.h" +#include "common/assert.h" BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent) : QAbstractListModel(parent), context_weak(debug_context), diff --git a/src/citra_qt/debugger/graphics_breakpoints.h b/src/citra_qt/debugger/graphics_breakpoints.h index d900729da..2371b0e39 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.h +++ b/src/citra_qt/debugger/graphics_breakpoints.h @@ -6,7 +6,6 @@ #include <memory> -#include <QAbstractListModel> #include <QDockWidget> #include "video_core/debug_utils/debug_utils.h" diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics_breakpoints_p.h index 00d8d5101..251114d06 100644 --- a/src/citra_qt/debugger/graphics_breakpoints_p.h +++ b/src/citra_qt/debugger/graphics_breakpoints_p.h @@ -23,7 +23,7 @@ public: int columnCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - Qt::ItemFlags flags(const QModelIndex &index) const; + Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 025434687..ab97c8d2d 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -4,26 +4,24 @@ #include <QApplication> #include <QClipboard> +#include <QComboBox> +#include <QHeaderView> #include <QLabel> #include <QListView> #include <QMainWindow> #include <QPushButton> -#include <QVBoxLayout> -#include <QTreeView> -#include <QHeaderView> #include <QSpinBox> -#include <QComboBox> +#include <QTreeView> +#include <QVBoxLayout> +#include "citra_qt/debugger/graphics_cmdlists.h" +#include "citra_qt/util/spinbox.h" #include "citra_qt/util/util.h" #include "common/vector_math.h" -#include "video_core/debug_utils/debug_utils.h" #include "video_core/pica.h" - -#include "graphics_cmdlists.h" - -#include "util/spinbox.h" +#include "video_core/debug_utils/debug_utils.h" QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) { QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); @@ -359,7 +357,7 @@ void GPUCommandListWidget::CopyAllToClipboard() { QClipboard* clipboard = QApplication::clipboard(); QString text; - QAbstractItemModel* model = static_cast<QAbstractListModel*>(list_widget->model()); + QAbstractItemModel* model = static_cast<QAbstractItemModel*>(list_widget->model()); for (int row = 0; row < model->rowCount({}); ++row) { for (int col = 0; col < model->columnCount({}); ++col) { diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics_cmdlists.h index 4859b6ec8..586cc7239 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.h +++ b/src/citra_qt/debugger/graphics_cmdlists.h @@ -41,7 +41,7 @@ class GPUCommandListWidget : public QDockWidget Q_OBJECT public: - GPUCommandListWidget(QWidget* parent = 0); + GPUCommandListWidget(QWidget* parent = nullptr); public slots: void OnToggleTracing(); diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index 39eefbf75..80b32eaff 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -9,18 +9,17 @@ #include <QPushButton> #include <QSpinBox> +#include "citra_qt/debugger/graphics_framebuffer.h" +#include "citra_qt/util/spinbox.h" + #include "common/color.h" -#include "core/hw/gpu.h" #include "core/memory.h" +#include "core/hw/gpu.h" #include "video_core/pica.h" #include "video_core/utils.h" -#include "graphics_framebuffer.h" - -#include "util/spinbox.h" - GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent) : BreakPointObserverDock(debug_context, tr("Pica Framebuffer"), parent), diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h index e9eae679f..5cd96f2e9 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.h +++ b/src/citra_qt/debugger/graphics_framebuffer.h @@ -4,9 +4,7 @@ #pragma once -#include <QDockWidget> - -#include "graphics_breakpoint_observer.h" +#include "citra_qt/debugger/graphics_breakpoint_observer.h" class QComboBox; class QLabel; diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp index f80cb7493..b0bc782df 100644 --- a/src/citra_qt/debugger/graphics_tracing.cpp +++ b/src/citra_qt/debugger/graphics_tracing.cpp @@ -4,26 +4,25 @@ #include <memory> +#include <boost/range/algorithm/copy.hpp> + #include <QBoxLayout> #include <QComboBox> #include <QFileDialog> -#include <QLabel> #include <QMessageBox> #include <QPushButton> -#include <QSpinBox> -#include <boost/range/algorithm/copy.hpp> +#include "citra_qt/debugger/graphics_tracing.h" #include "common/common_types.h" #include "core/hw/gpu.h" #include "core/hw/lcd.h" -#include "video_core/pica.h" - #include "nihstro/float24.h" -#include "graphics_tracing.h" +#include "video_core/pica.h" + GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent) diff --git a/src/citra_qt/debugger/graphics_tracing.h b/src/citra_qt/debugger/graphics_tracing.h index 2a0e4819b..753dfa914 100644 --- a/src/citra_qt/debugger/graphics_tracing.h +++ b/src/citra_qt/debugger/graphics_tracing.h @@ -4,7 +4,7 @@ #pragma once -#include "graphics_breakpoint_observer.h" +#include "citra_qt/debugger/graphics_breakpoint_observer.h" class EmuThread; diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp index 1d9a00e89..f915d2bab 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp @@ -7,6 +7,7 @@ #include <QBoxLayout> #include <QFileDialog> +#include <QFormLayout> #include <QGroupBox> #include <QLabel> #include <QLineEdit> @@ -15,27 +16,18 @@ #include <QSpinBox> #include <QTreeView> +#include "citra_qt/debugger/graphics_vertex_shader.h" #include "citra_qt/util/util.h" #include "video_core/shader/shader.h" -#include "graphics_vertex_shader.h" - using nihstro::OpCode; using nihstro::Instruction; using nihstro::SourceRegister; using nihstro::SwizzlePattern; -GraphicsVertexShaderModel::GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent): QAbstractItemModel(parent), par(parent) { - -} +GraphicsVertexShaderModel::GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent): QAbstractTableModel(parent), par(parent) { -QModelIndex GraphicsVertexShaderModel::index(int row, int column, const QModelIndex& parent) const { - return createIndex(row, column); -} - -QModelIndex GraphicsVertexShaderModel::parent(const QModelIndex& child) const { - return QModelIndex(); } int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const { @@ -65,6 +57,28 @@ QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orie return QVariant(); } +static std::string SelectorToString(u32 selector) { + std::string ret; + for (int i = 0; i < 4; ++i) { + int component = (selector >> ((3 - i) * 2)) & 3; + ret += "xyzw"[component]; + } + return ret; +} + +// e.g. "-c92[a0.x].xyzw" +static void print_input(std::ostringstream& output, const SourceRegister& input, + bool negate, const std::string& swizzle_mask, bool align = true, + const std::string& address_register_name = std::string()) { + if (align) + output << std::setw(4) << std::right; + output << ((negate ? "-" : "") + input.GetName()); + + if (!address_register_name.empty()) + output << '[' << address_register_name << ']'; + output << '.' << swizzle_mask; +}; + QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const { switch (role) { case Qt::DisplayRole: @@ -81,102 +95,120 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con case 2: { - std::stringstream output; - output.flags(std::ios::hex); - - Instruction instr = par->info.code[index.row()]; - const SwizzlePattern& swizzle = par->info.swizzle_info[instr.common.operand_desc_id].pattern; - - // longest known instruction name: "setemit " - output << std::setw(8) << std::left << instr.opcode.Value().GetInfo().name; - - // e.g. "-c92.xyzw" - static auto print_input = [](std::stringstream& output, const SourceRegister& input, - bool negate, const std::string& swizzle_mask) { - output << std::setw(4) << std::right << (negate ? "-" : "") + input.GetName(); - output << "." << swizzle_mask; + std::ostringstream output; + output.flags(std::ios::uppercase); + + // To make the code aligning columns of assembly easier to keep track of, this function + // keeps track of the start of the start of the previous column, allowing alignment + // based on desired field widths. + int current_column = 0; + auto AlignToColumn = [&](int col_width) { + // Prints spaces to the output to pad previous column to size and advances the + // column marker. + current_column += col_width; + int to_add = std::max(1, current_column - (int)output.tellp()); + for (int i = 0; i < to_add; ++i) { + output << ' '; + } }; - // e.g. "-c92[a0.x].xyzw" - static auto print_input_indexed = [](std::stringstream& output, const SourceRegister& input, - bool negate, const std::string& swizzle_mask, - const std::string& address_register_name) { - std::string relative_address; - if (!address_register_name.empty()) - relative_address = "[" + address_register_name + "]"; + const Instruction instr = par->info.code[index.row()]; + const OpCode opcode = instr.opcode; + const OpCode::Info opcode_info = opcode.GetInfo(); + const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd ? + instr.mad.operand_desc_id.Value() : instr.common.operand_desc_id.Value(); + const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern; - output << std::setw(10) << std::right << (negate ? "-" : "") + input.GetName() + relative_address; - output << "." << swizzle_mask; - }; + // longest known instruction name: "setemit " + int kOpcodeColumnWidth = 8; + // "rXX.xyzw " + int kOutputColumnWidth = 10; + // "-rXX.xyzw ", no attempt is made to align indexed inputs + int kInputOperandColumnWidth = 11; - // Use print_input or print_input_indexed depending on whether relative addressing is used or not. - static auto print_input_indexed_compact = [](std::stringstream& output, const SourceRegister& input, - bool negate, const std::string& swizzle_mask, - const std::string& address_register_name) { - if (address_register_name.empty()) - print_input(output, input, negate, swizzle_mask); - else - print_input_indexed(output, input, negate, swizzle_mask, address_register_name); - }; + output << opcode_info.name; - switch (instr.opcode.Value().GetInfo().type) { + switch (opcode_info.type) { case OpCode::Type::Trivial: // Nothing to do here break; case OpCode::Type::Arithmetic: + case OpCode::Type::MultiplyAdd: { // Use custom code for special instructions - switch (instr.opcode.Value().EffectiveOpCode()) { + switch (opcode.EffectiveOpCode()) { case OpCode::Id::CMP: { + AlignToColumn(kOpcodeColumnWidth); + // NOTE: CMP always writes both cc components, so we do not consider the dest mask here. - output << std::setw(4) << std::right << "cc."; - output << "xy "; + output << " cc.xy"; + AlignToColumn(kOutputColumnWidth); SourceRegister src1 = instr.common.GetSrc1(false); SourceRegister src2 = instr.common.GetSrc2(false); - print_input_indexed_compact(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(0,1), instr.common.AddressRegisterName()); - output << " " << instr.common.compare_op.ToString(instr.common.compare_op.x) << " "; - print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(0,1)); + output << ' '; + print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(0,1), false, instr.common.AddressRegisterName()); + output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.x) << ' '; + print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(0,1), false); output << ", "; - print_input_indexed_compact(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(1,1), instr.common.AddressRegisterName()); - output << " " << instr.common.compare_op.ToString(instr.common.compare_op.y) << " "; - print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(1,1)); + print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(1,1), false, instr.common.AddressRegisterName()); + output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.y) << ' '; + print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(1,1), false); break; } + case OpCode::Id::MAD: + case OpCode::Id::MADI: + { + AlignToColumn(kOpcodeColumnWidth); + + bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); + SourceRegister src1 = instr.mad.GetSrc1(src_is_inverted); + SourceRegister src2 = instr.mad.GetSrc2(src_is_inverted); + SourceRegister src3 = instr.mad.GetSrc3(src_is_inverted); + + output << std::setw(3) << std::right << instr.mad.dest.Value().GetName() << '.' << swizzle.DestMaskToString(); + AlignToColumn(kOutputColumnWidth); + print_input(output, src1, swizzle.negate_src1, SelectorToString(swizzle.src1_selector)); + AlignToColumn(kInputOperandColumnWidth); + print_input(output, src2, swizzle.negate_src2, SelectorToString(swizzle.src2_selector)); + AlignToColumn(kInputOperandColumnWidth); + print_input(output, src3, swizzle.negate_src3, SelectorToString(swizzle.src3_selector)); + AlignToColumn(kInputOperandColumnWidth); + break; + } + default: { - bool src_is_inverted = 0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed); + AlignToColumn(kOpcodeColumnWidth); + + bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); - if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Dest) { + if (opcode_info.subtype & OpCode::Info::Dest) { // e.g. "r12.xy__" - output << std::setw(4) << std::right << instr.common.dest.Value().GetName() + "."; - output << swizzle.DestMaskToString(); - } else if (instr.opcode.Value().GetInfo().subtype == OpCode::Info::MOVA) { - output << std::setw(4) << std::right << "a0."; - output << swizzle.DestMaskToString(); - } else { - output << " "; + output << std::setw(3) << std::right << instr.common.dest.Value().GetName() << '.' << swizzle.DestMaskToString(); + } else if (opcode_info.subtype == OpCode::Info::MOVA) { + output << " a0." << swizzle.DestMaskToString(); } - output << " "; + AlignToColumn(kOutputColumnWidth); - if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Src1) { + if (opcode_info.subtype & OpCode::Info::Src1) { SourceRegister src1 = instr.common.GetSrc1(src_is_inverted); - print_input_indexed(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false), instr.common.AddressRegisterName()); - } else { - output << " "; + print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false), true, instr.common.AddressRegisterName()); + AlignToColumn(kInputOperandColumnWidth); } // TODO: In some cases, the Address Register is used as an index for SRC2 instead of SRC1 - if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::Src2) { + if (opcode_info.subtype & OpCode::Info::Src2) { SourceRegister src2 = instr.common.GetSrc2(src_is_inverted); print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true)); + AlignToColumn(kInputOperandColumnWidth); } break; } @@ -186,46 +218,55 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con } case OpCode::Type::Conditional: + case OpCode::Type::UniformFlowControl: { - switch (instr.opcode.Value().EffectiveOpCode()) { + output << ' '; + + switch (opcode.EffectiveOpCode()) { case OpCode::Id::LOOP: output << "(unknown instruction format)"; break; default: - output << "if "; - - if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasCondition) { - const char* ops[] = { - " || ", " && ", "", "" - }; - if (instr.flow_control.op != instr.flow_control.JustY) - output << ((!instr.flow_control.refx) ? "!" : " ") << "cc.x"; - - output << ops[instr.flow_control.op]; - - if (instr.flow_control.op != instr.flow_control.JustX) - output << ((!instr.flow_control.refy) ? "!" : " ") << "cc.y"; - - output << " "; - } else if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasUniformIndex) { - output << "b" << instr.flow_control.bool_uniform_id << " "; + if (opcode_info.subtype & OpCode::Info::HasCondition) { + output << '('; + + if (instr.flow_control.op != instr.flow_control.JustY) { + if (instr.flow_control.refx) output << '!'; + output << "cc.x"; + } + + if (instr.flow_control.op == instr.flow_control.Or) { + output << " || "; + } else if (instr.flow_control.op == instr.flow_control.And) { + output << " && "; + } + + if (instr.flow_control.op != instr.flow_control.JustX) { + if (instr.flow_control.refy) output << '!'; + output << "cc.y"; + } + + output << ") "; + } else if (opcode_info.subtype & OpCode::Info::HasUniformIndex) { + output << 'b' << instr.flow_control.bool_uniform_id << ' '; } u32 target_addr = instr.flow_control.dest_offset; u32 target_addr_else = instr.flow_control.dest_offset; - if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasAlternative) { - output << "else jump to 0x" << std::setw(4) << std::right << std::setfill('0') << 4 * instr.flow_control.dest_offset << " "; - } else if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasExplicitDest) { - output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') << 4 * instr.flow_control.dest_offset << " "; + if (opcode_info.subtype & OpCode::Info::HasAlternative) { + output << "else jump to 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex << (4 * instr.flow_control.dest_offset); + } else if (opcode_info.subtype & OpCode::Info::HasExplicitDest) { + output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex << (4 * instr.flow_control.dest_offset); } else { // TODO: Handle other cases + output << "(unknown destination)"; } - if (instr.opcode.Value().GetInfo().subtype & OpCode::Info::HasFinishPoint) { - output << "(return on " << std::setw(4) << std::right << std::setfill('0') - << 4 * instr.flow_control.dest_offset + 4 * instr.flow_control.num_instructions << ")"; + if (opcode_info.subtype & OpCode::Info::HasFinishPoint) { + output << " (return on 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex + << (4 * instr.flow_control.dest_offset + 4 * instr.flow_control.num_instructions) << ')'; } break; @@ -234,7 +275,7 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con } default: - output << "(unknown instruction format)"; + output << " (unknown instruction format)"; break; } @@ -250,12 +291,23 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con return GetMonospaceFont(); case Qt::BackgroundRole: - // Highlight instructions which have no debug data associated to them + { + // Highlight current instruction + int current_record_index = par->cycle_index->value(); + if (current_record_index < par->debug_data.records.size()) { + const auto& current_record = par->debug_data.records[current_record_index]; + if (index.row() == current_record.instruction_offset) { + return QColor(255, 255, 63); + } + } + + // Use a grey background for instructions which have no debug data associated to them for (const auto& record : par->debug_data.records) if (index.row() == record.instruction_offset) return QVariant(); - return QBrush(QColor(255, 255, 127)); + return QBrush(QColor(192, 192, 192)); + } // TODO: Draw arrows for each "reachable" instruction to visualize control flow @@ -288,6 +340,13 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De : BreakPointObserverDock(debug_context, "Pica Vertex Shader", parent) { setObjectName("PicaVertexShader"); + // Clear input vertex data so that it contains valid float values in case a debug shader + // execution happens before the first Vertex Loaded breakpoint. + // TODO: This makes a crash in the interpreter much less likely, but not impossible. The + // interpreter should guard against out-of-bounds accesses to ensure crashes in it aren't + // possible. + std::memset(&input_vertex, 0, sizeof(input_vertex)); + auto input_data_mapper = new QSignalMapper(this); // TODO: Support inputting data in hexadecimal raw format @@ -312,9 +371,6 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De cycle_index = new QSpinBox; - connect(this, SIGNAL(SelectCommand(const QModelIndex&, QItemSelectionModel::SelectionFlags)), - binary_list->selectionModel(), SLOT(select(const QModelIndex&, QItemSelectionModel::SelectionFlags))); - connect(dump_shader, SIGNAL(clicked()), this, SLOT(DumpShader())); connect(cycle_index, SIGNAL(valueChanged(int)), this, SLOT(OnCycleIndexChanged(int))); @@ -339,6 +395,9 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De // Create an HBoxLayout to store the widgets used to specify a particular attribute // and store it in a QWidget to allow for easy hiding and unhiding. auto row_layout = new QHBoxLayout; + // Remove unecessary padding between rows + row_layout->setContentsMargins(0, 0, 0, 0); + row_layout->addWidget(new QLabel(tr("Attribute %1").arg(i, 2))); for (unsigned comp = 0; comp < 4; ++comp) row_layout->addWidget(input_data[4 * i + comp]); @@ -358,20 +417,25 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De input_data_group->setLayout(sub_layout); main_layout->addWidget(input_data_group); } - { - auto sub_layout = new QHBoxLayout; - sub_layout->addWidget(binary_list); - main_layout->addLayout(sub_layout); - } + + // Make program listing expand to fill available space in the dialog + binary_list->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); + main_layout->addWidget(binary_list); + main_layout->addWidget(dump_shader); { - auto sub_layout = new QHBoxLayout; - sub_layout->addWidget(new QLabel(tr("Cycle Index:"))); - sub_layout->addWidget(cycle_index); + auto sub_layout = new QFormLayout; + sub_layout->addRow(tr("Cycle Index:"), cycle_index); + main_layout->addLayout(sub_layout); } + + // Set a minimum height so that the size of this label doesn't cause the rest of the bottom + // part of the UI to keep jumping up and down when cycling through instructions. + instruction_description->setMinimumHeight(instruction_description->fontMetrics().lineSpacing() * 6); + instruction_description->setAlignment(Qt::AlignLeft | Qt::AlignTop); main_layout->addWidget(instruction_description); - main_layout->addStretch(); + main_widget->setLayout(main_layout); setWidget(main_widget); @@ -418,6 +482,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d auto& shader_config = Pica::g_state.regs.vs; for (auto instr : shader_setup.program_code) info.code.push_back({instr}); + int num_attributes = Pica::g_state.regs.vertex_attributes.GetNumTotalAttributes(); for (auto pattern : shader_setup.swizzle_data) info.swizzle_info.push_back({pattern}); @@ -426,19 +491,18 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d info.labels.insert({ entry_point, "main" }); // Generate debug information - debug_data = Pica::Shader::ProduceDebugInfo(input_vertex, 1, shader_config, shader_setup); + debug_data = Pica::Shader::ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup); // Reload widget state - - // Only show input attributes which are used as input to the shader - for (unsigned int attr = 0; attr < 16; ++attr) { - input_data_container[attr]->setVisible(false); - } - for (unsigned int attr = 0; attr < Pica::g_state.regs.vertex_attributes.GetNumTotalAttributes(); ++attr) { + for (unsigned int attr = 0; attr < num_attributes; ++attr) { unsigned source_attr = shader_config.input_register_map.GetRegisterForAttribute(attr); input_data_mapping[source_attr]->setText(QString("-> v%1").arg(attr)); input_data_container[source_attr]->setVisible(true); } + // Only show input attributes which are used as input to the shader + for (unsigned int attr = num_attributes; attr < 16; ++attr) { + input_data_container[attr]->setVisible(false); + } // Initialize debug info text for current cycle count cycle_index->setMaximum(debug_data.records.size() - 1); @@ -453,6 +517,8 @@ void GraphicsVertexShaderWidget::OnResumed() { void GraphicsVertexShaderWidget::OnInputAttributeChanged(int index) { float value = input_data[index]->text().toFloat(); + input_vertex.attr[index / 4][index % 4] = Pica::float24::FromFloat32(value); + // Re-execute shader with updated value Reload(); } @@ -492,8 +558,8 @@ void GraphicsVertexShaderWidget::OnCycleIndexChanged(int index) { instruction_description->setText(text); - // Scroll to current instruction - const QModelIndex& instr_index = model->index(record.instruction_offset, 0); - emit SelectCommand(instr_index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + // Emit model update notification and scroll to current instruction + QModelIndex instr_index = model->index(record.instruction_offset, 0); + emit model->dataChanged(instr_index, model->index(record.instruction_offset, model->columnCount())); binary_list->scrollTo(instr_index, QAbstractItemView::EnsureVisible); } diff --git a/src/citra_qt/debugger/graphics_vertex_shader.h b/src/citra_qt/debugger/graphics_vertex_shader.h index 1b3f1f7ec..7f06f496a 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.h +++ b/src/citra_qt/debugger/graphics_vertex_shader.h @@ -4,9 +4,9 @@ #pragma once -#include <QAbstractListModel> +#include <QAbstractTableModel> -#include "graphics_breakpoint_observer.h" +#include "citra_qt/debugger/graphics_breakpoint_observer.h" #include "nihstro/parser_shbin.h" @@ -17,14 +17,12 @@ class QSpinBox; class GraphicsVertexShaderWidget; -class GraphicsVertexShaderModel : public QAbstractItemModel { +class GraphicsVertexShaderModel : public QAbstractTableModel { Q_OBJECT public: GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent); - QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex& child) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; @@ -62,11 +60,6 @@ private slots: */ void Reload(bool replace_vertex_data = false, void* vertex_data = nullptr); - -signals: - // Call this to change the current command selection in the disassembly view - void SelectCommand(const QModelIndex&, QItemSelectionModel::SelectionFlags); - private: QLabel* instruction_description; QTreeView* binary_list; diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp index 5261d4836..4f6ba0e1f 100644 --- a/src/citra_qt/debugger/profiler.cpp +++ b/src/citra_qt/debugger/profiler.cpp @@ -6,12 +6,11 @@ #include <QPainter> #include <QString> -#include "profiler.h" - +#include "citra_qt/debugger/profiler.h" #include "citra_qt/util/util.h" -#include "common/profiler_reporting.h" #include "common/microprofile.h" +#include "common/profiler_reporting.h" // Include the implementation of the UI in this file. This isn't in microprofile.cpp because the // non-Qt frontends don't need it (and don't implement the UI drawing hooks either). @@ -151,7 +150,7 @@ void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable) class MicroProfileWidget : public QWidget { public: - MicroProfileWidget(QWidget* parent = 0); + MicroProfileWidget(QWidget* parent = nullptr); protected: void paintEvent(QPaintEvent* ev) override; diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h index 2199eaef1..036054740 100644 --- a/src/citra_qt/debugger/profiler.h +++ b/src/citra_qt/debugger/profiler.h @@ -37,7 +37,7 @@ class ProfilerWidget : public QDockWidget Q_OBJECT public: - ProfilerWidget(QWidget* parent = 0); + ProfilerWidget(QWidget* parent = nullptr); private slots: void setProfilingInfoUpdateEnabled(bool enable); @@ -53,7 +53,7 @@ class MicroProfileDialog : public QWidget { Q_OBJECT public: - MicroProfileDialog(QWidget* parent = 0); + MicroProfileDialog(QWidget* parent = nullptr); /// Returns a QAction that can be used to toggle visibility of this dialog. QAction* toggleViewAction(); diff --git a/src/citra_qt/debugger/ramview.cpp b/src/citra_qt/debugger/ramview.cpp index b6ebc7fc4..02347e83a 100644 --- a/src/citra_qt/debugger/ramview.cpp +++ b/src/citra_qt/debugger/ramview.cpp @@ -2,8 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "ramview.h" - +#include "citra_qt/debugger/ramview.h" GRamView::GRamView(QWidget* parent) : QHexEdit(parent) { diff --git a/src/citra_qt/debugger/ramview.h b/src/citra_qt/debugger/ramview.h index 18423036f..0ef74586b 100644 --- a/src/citra_qt/debugger/ramview.h +++ b/src/citra_qt/debugger/ramview.h @@ -9,7 +9,7 @@ class GRamView : public QHexEdit Q_OBJECT public: - GRamView(QWidget* parent = NULL); + GRamView(QWidget* parent = nullptr); public slots: void OnCPUStepped(); diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp index 4174b3945..6100d67c5 100644 --- a/src/citra_qt/debugger/registers.cpp +++ b/src/citra_qt/debugger/registers.cpp @@ -2,7 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "registers.h" +#include <QTreeWidgetItem> + +#include "citra_qt/debugger/registers.h" +#include "citra_qt/util/util.h" #include "core/core.h" #include "core/arm/arm_interface.h" @@ -26,9 +29,32 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { vfp_registers->addChild(child); } + QFont font = GetMonospaceFont(); + CreateCPSRChildren(); CreateVFPSystemRegisterChildren(); + // Set Registers to display in monospace font + for (int i = 0; i < core_registers->childCount(); ++i) + core_registers->child(i)->setFont(1, font); + + for (int i = 0; i < vfp_registers->childCount(); ++i) + vfp_registers->child(i)->setFont(1, font); + + for (int i = 0; i < vfp_system_registers->childCount(); ++i) { + vfp_system_registers->child(i)->setFont(1, font); + for (int x = 0; x < vfp_system_registers->child(i)->childCount(); ++x) { + vfp_system_registers->child(i)->child(x)->setFont(1, font); + } + } + // Set CSPR to display in monospace font + cpsr->setFont(1, font); + for (int i = 0; i < cpsr->childCount(); ++i) { + cpsr->child(i)->setFont(1, font); + for (int x = 0; x < cpsr->child(i)->childCount(); ++x) { + cpsr->child(i)->child(x)->setFont(1, font); + } + } setEnabled(false); } diff --git a/src/citra_qt/debugger/registers.h b/src/citra_qt/debugger/registers.h index 09b830e80..cf27acc1c 100644 --- a/src/citra_qt/debugger/registers.h +++ b/src/citra_qt/debugger/registers.h @@ -5,9 +5,9 @@ #include "ui_registers.h" #include <QDockWidget> -#include <QTreeWidgetItem> class QTreeWidget; +class QTreeWidgetItem; class EmuThread; class RegistersWidget : public QDockWidget @@ -15,7 +15,7 @@ class RegistersWidget : public QDockWidget Q_OBJECT public: - RegistersWidget(QWidget* parent = NULL); + RegistersWidget(QWidget* parent = nullptr); public slots: void OnDebugModeEntered(); |