diff options
Diffstat (limited to '')
24 files changed, 587 insertions, 569 deletions
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index 1a3077495..a87046acb 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp | |||
| @@ -9,13 +9,12 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/symbols.h" | 10 | #include "common/symbols.h" |
| 11 | 11 | ||
| 12 | #include "core/core.h" | ||
| 13 | #include "core/memory.h" | ||
| 14 | #include "core/arm/arm_interface.h" | 12 | #include "core/arm/arm_interface.h" |
| 15 | #include "core/arm/disassembler/arm_disasm.h" | 13 | #include "core/arm/disassembler/arm_disasm.h" |
| 14 | #include "core/core.h" | ||
| 15 | #include "core/memory.h" | ||
| 16 | 16 | ||
| 17 | CallstackWidget::CallstackWidget(QWidget* parent): QDockWidget(parent) | 17 | CallstackWidget::CallstackWidget(QWidget* parent) : QDockWidget(parent) { |
| 18 | { | ||
| 19 | ui.setupUi(this); | 18 | ui.setupUi(this); |
| 20 | 19 | ||
| 21 | callstack_model = new QStandardItemModel(this); | 20 | callstack_model = new QStandardItemModel(this); |
| @@ -27,29 +26,26 @@ CallstackWidget::CallstackWidget(QWidget* parent): QDockWidget(parent) | |||
| 27 | ui.treeView->setModel(callstack_model); | 26 | ui.treeView->setModel(callstack_model); |
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | void CallstackWidget::OnDebugModeEntered() | 29 | void CallstackWidget::OnDebugModeEntered() { |
| 31 | { | ||
| 32 | // Stack pointer | 30 | // Stack pointer |
| 33 | const u32 sp = Core::g_app_core->GetReg(13); | 31 | const u32 sp = Core::g_app_core->GetReg(13); |
| 34 | 32 | ||
| 35 | Clear(); | 33 | Clear(); |
| 36 | 34 | ||
| 37 | int counter = 0; | 35 | int counter = 0; |
| 38 | for (u32 addr = 0x10000000; addr >= sp; addr -= 4) | 36 | for (u32 addr = 0x10000000; addr >= sp; addr -= 4) { |
| 39 | { | ||
| 40 | if (!Memory::IsValidVirtualAddress(addr)) | 37 | if (!Memory::IsValidVirtualAddress(addr)) |
| 41 | break; | 38 | break; |
| 42 | 39 | ||
| 43 | const u32 ret_addr = Memory::Read32(addr); | 40 | const u32 ret_addr = Memory::Read32(addr); |
| 44 | const u32 call_addr = ret_addr - 4; //get call address??? | 41 | const u32 call_addr = ret_addr - 4; // get call address??? |
| 45 | 42 | ||
| 46 | if (!Memory::IsValidVirtualAddress(call_addr)) | 43 | if (!Memory::IsValidVirtualAddress(call_addr)) |
| 47 | break; | 44 | break; |
| 48 | 45 | ||
| 49 | /* TODO (mattvail) clean me, move to debugger interface */ | 46 | /* TODO (mattvail) clean me, move to debugger interface */ |
| 50 | u32 insn = Memory::Read32(call_addr); | 47 | u32 insn = Memory::Read32(call_addr); |
| 51 | if (ARM_Disasm::Decode(insn) == OP_BL) | 48 | if (ARM_Disasm::Decode(insn) == OP_BL) { |
| 52 | { | ||
| 53 | std::string name; | 49 | std::string name; |
| 54 | // ripped from disasm | 50 | // ripped from disasm |
| 55 | u8 cond = (insn >> 28) & 0xf; | 51 | u8 cond = (insn >> 28) & 0xf; |
| @@ -63,26 +59,29 @@ void CallstackWidget::OnDebugModeEntered() | |||
| 63 | i_offset += 8; | 59 | i_offset += 8; |
| 64 | const u32 func_addr = call_addr + i_offset; | 60 | const u32 func_addr = call_addr + i_offset; |
| 65 | 61 | ||
| 66 | callstack_model->setItem(counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); | 62 | callstack_model->setItem( |
| 67 | callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg(ret_addr, 8, 16, QLatin1Char('0')))); | 63 | counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); |
| 68 | callstack_model->setItem(counter, 2, new QStandardItem(QString("0x%1").arg(call_addr, 8, 16, QLatin1Char('0')))); | 64 | callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg( |
| 65 | ret_addr, 8, 16, QLatin1Char('0')))); | ||
| 66 | callstack_model->setItem(counter, 2, new QStandardItem(QString("0x%1").arg( | ||
| 67 | call_addr, 8, 16, QLatin1Char('0')))); | ||
| 69 | 68 | ||
| 70 | name = Symbols::HasSymbol(func_addr) ? Symbols::GetSymbol(func_addr).name : "unknown"; | 69 | name = Symbols::HasSymbol(func_addr) ? Symbols::GetSymbol(func_addr).name : "unknown"; |
| 71 | callstack_model->setItem(counter, 3, new QStandardItem(QString("%1_%2").arg(QString::fromStdString(name)) | 70 | callstack_model->setItem( |
| 72 | .arg(QString("0x%1").arg(func_addr, 8, 16, QLatin1Char('0'))))); | 71 | counter, 3, new QStandardItem( |
| 72 | QString("%1_%2") | ||
| 73 | .arg(QString::fromStdString(name)) | ||
| 74 | .arg(QString("0x%1").arg(func_addr, 8, 16, QLatin1Char('0'))))); | ||
| 73 | 75 | ||
| 74 | counter++; | 76 | counter++; |
| 75 | } | 77 | } |
| 76 | } | 78 | } |
| 77 | } | 79 | } |
| 78 | 80 | ||
| 79 | void CallstackWidget::OnDebugModeLeft() | 81 | void CallstackWidget::OnDebugModeLeft() { |
| 80 | { | ||
| 81 | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | void CallstackWidget::Clear() | 84 | void CallstackWidget::Clear() { |
| 85 | { | ||
| 86 | for (int row = 0; row < callstack_model->rowCount(); row++) { | 85 | for (int row = 0; row < callstack_model->rowCount(); row++) { |
| 87 | for (int column = 0; column < callstack_model->columnCount(); column++) { | 86 | for (int column = 0; column < callstack_model->columnCount(); column++) { |
| 88 | callstack_model->setItem(row, column, new QStandardItem()); | 87 | callstack_model->setItem(row, column, new QStandardItem()); |
diff --git a/src/citra_qt/debugger/callstack.h b/src/citra_qt/debugger/callstack.h index 7aa83db1e..765757986 100644 --- a/src/citra_qt/debugger/callstack.h +++ b/src/citra_qt/debugger/callstack.h | |||
| @@ -7,8 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | class QStandardItemModel; | 8 | class QStandardItemModel; |
| 9 | 9 | ||
| 10 | class CallstackWidget : public QDockWidget | 10 | class CallstackWidget : public QDockWidget { |
| 11 | { | ||
| 12 | Q_OBJECT | 11 | Q_OBJECT |
| 13 | 12 | ||
| 14 | public: | 13 | public: |
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index d4f72809d..b523fe9a7 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp | |||
| @@ -5,20 +5,21 @@ | |||
| 5 | #include <QShortcut> | 5 | #include <QShortcut> |
| 6 | 6 | ||
| 7 | #include "citra_qt/bootmanager.h" | 7 | #include "citra_qt/bootmanager.h" |
| 8 | #include "citra_qt/hotkeys.h" | ||
| 9 | #include "citra_qt/debugger/disassembler.h" | 8 | #include "citra_qt/debugger/disassembler.h" |
| 9 | #include "citra_qt/hotkeys.h" | ||
| 10 | #include "citra_qt/util/util.h" | 10 | #include "citra_qt/util/util.h" |
| 11 | 11 | ||
| 12 | #include "common/break_points.h" | 12 | #include "common/break_points.h" |
| 13 | #include "common/symbols.h" | 13 | #include "common/symbols.h" |
| 14 | 14 | ||
| 15 | #include "core/core.h" | ||
| 16 | #include "core/memory.h" | ||
| 17 | #include "core/arm/arm_interface.h" | 15 | #include "core/arm/arm_interface.h" |
| 18 | #include "core/arm/disassembler/arm_disasm.h" | 16 | #include "core/arm/disassembler/arm_disasm.h" |
| 17 | #include "core/core.h" | ||
| 18 | #include "core/memory.h" | ||
| 19 | 19 | ||
| 20 | DisassemblerModel::DisassemblerModel(QObject* parent) : | 20 | DisassemblerModel::DisassemblerModel(QObject* parent) |
| 21 | QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { | 21 | : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), |
| 22 | selection(QModelIndex()) { | ||
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | int DisassemblerModel::columnCount(const QModelIndex& parent) const { | 25 | int DisassemblerModel::columnCount(const QModelIndex& parent) const { |
| @@ -31,62 +32,60 @@ int DisassemblerModel::rowCount(const QModelIndex& parent) const { | |||
| 31 | 32 | ||
| 32 | QVariant DisassemblerModel::data(const QModelIndex& index, int role) const { | 33 | QVariant DisassemblerModel::data(const QModelIndex& index, int role) const { |
| 33 | switch (role) { | 34 | switch (role) { |
| 34 | case Qt::DisplayRole: | 35 | case Qt::DisplayRole: { |
| 35 | { | 36 | u32 address = base_address + index.row() * 4; |
| 36 | u32 address = base_address + index.row() * 4; | 37 | u32 instr = Memory::Read32(address); |
| 37 | u32 instr = Memory::Read32(address); | 38 | std::string disassembly = ARM_Disasm::Disassemble(address, instr); |
| 38 | std::string disassembly = ARM_Disasm::Disassemble(address, instr); | 39 | |
| 39 | 40 | if (index.column() == 0) { | |
| 40 | if (index.column() == 0) { | 41 | return QString("0x%1").arg((uint)(address), 8, 16, QLatin1Char('0')); |
| 41 | return QString("0x%1").arg((uint)(address), 8, 16, QLatin1Char('0')); | 42 | } else if (index.column() == 1) { |
| 42 | } else if (index.column() == 1) { | 43 | return QString::fromStdString(disassembly); |
| 43 | return QString::fromStdString(disassembly); | 44 | } else if (index.column() == 2) { |
| 44 | } else if (index.column() == 2) { | 45 | if (Symbols::HasSymbol(address)) { |
| 45 | if(Symbols::HasSymbol(address)) { | 46 | TSymbol symbol = Symbols::GetSymbol(address); |
| 46 | TSymbol symbol = Symbols::GetSymbol(address); | 47 | return QString("%1 - Size:%2") |
| 47 | return QString("%1 - Size:%2").arg(QString::fromStdString(symbol.name)) | 48 | .arg(QString::fromStdString(symbol.name)) |
| 48 | .arg(symbol.size / 4); // divide by 4 to get instruction count | 49 | .arg(symbol.size / 4); // divide by 4 to get instruction count |
| 49 | } else if (ARM_Disasm::Decode(instr) == OP_BL) { | 50 | } else if (ARM_Disasm::Decode(instr) == OP_BL) { |
| 50 | u32 offset = instr & 0xFFFFFF; | 51 | u32 offset = instr & 0xFFFFFF; |
| 51 | 52 | ||
| 52 | // Sign-extend the 24-bit offset | 53 | // Sign-extend the 24-bit offset |
| 53 | if ((offset >> 23) & 1) | 54 | if ((offset >> 23) & 1) |
| 54 | offset |= 0xFF000000; | 55 | offset |= 0xFF000000; |
| 55 | 56 | ||
| 56 | // Pre-compute the left-shift and the prefetch offset | 57 | // Pre-compute the left-shift and the prefetch offset |
| 57 | offset <<= 2; | 58 | offset <<= 2; |
| 58 | offset += 8; | 59 | offset += 8; |
| 59 | 60 | ||
| 60 | TSymbol symbol = Symbols::GetSymbol(address + offset); | 61 | TSymbol symbol = Symbols::GetSymbol(address + offset); |
| 61 | return QString(" --> %1").arg(QString::fromStdString(symbol.name)); | 62 | return QString(" --> %1").arg(QString::fromStdString(symbol.name)); |
| 62 | } | ||
| 63 | } | 63 | } |
| 64 | |||
| 65 | break; | ||
| 66 | } | 64 | } |
| 67 | 65 | ||
| 68 | case Qt::BackgroundRole: | 66 | break; |
| 69 | { | 67 | } |
| 70 | unsigned int address = base_address + 4 * index.row(); | ||
| 71 | 68 | ||
| 72 | if (breakpoints.IsAddressBreakPoint(address)) | 69 | case Qt::BackgroundRole: { |
| 73 | return QBrush(QColor(0xFF, 0xC0, 0xC0)); | 70 | unsigned int address = base_address + 4 * index.row(); |
| 74 | else if (address == program_counter) | ||
| 75 | return QBrush(QColor(0xC0, 0xC0, 0xFF)); | ||
| 76 | 71 | ||
| 77 | break; | 72 | if (breakpoints.IsAddressBreakPoint(address)) |
| 78 | } | 73 | return QBrush(QColor(0xFF, 0xC0, 0xC0)); |
| 74 | else if (address == program_counter) | ||
| 75 | return QBrush(QColor(0xC0, 0xC0, 0xFF)); | ||
| 79 | 76 | ||
| 80 | case Qt::FontRole: | 77 | break; |
| 81 | { | 78 | } |
| 82 | if (index.column() == 0 || index.column() == 1) { // 2 is the symbols column | 79 | |
| 83 | return GetMonospaceFont(); | 80 | case Qt::FontRole: { |
| 84 | } | 81 | if (index.column() == 0 || index.column() == 1) { // 2 is the symbols column |
| 85 | break; | 82 | return GetMonospaceFont(); |
| 86 | } | 83 | } |
| 84 | break; | ||
| 85 | } | ||
| 87 | 86 | ||
| 88 | default: | 87 | default: |
| 89 | break; | 88 | break; |
| 90 | } | 89 | } |
| 91 | 90 | ||
| 92 | return QVariant(); | 91 | return QVariant(); |
| @@ -103,7 +102,7 @@ const BreakPoints& DisassemblerModel::GetBreakPoints() const { | |||
| 103 | void DisassemblerModel::ParseFromAddress(unsigned int address) { | 102 | void DisassemblerModel::ParseFromAddress(unsigned int address) { |
| 104 | 103 | ||
| 105 | // NOTE: A too large value causes lagging when scrolling the disassembly | 104 | // NOTE: A too large value causes lagging when scrolling the disassembly |
| 106 | const unsigned int chunk_size = 1000*500; | 105 | const unsigned int chunk_size = 1000 * 500; |
| 107 | 106 | ||
| 108 | // If we haven't loaded anything yet, initialize base address to the parameter address | 107 | // If we haven't loaded anything yet, initialize base address to the parameter address |
| 109 | if (code_size == 0) | 108 | if (code_size == 0) |
| @@ -165,23 +164,26 @@ void DisassemblerModel::SetNextInstruction(unsigned int address) { | |||
| 165 | emit dataChanged(prev_index, prev_index); | 164 | emit dataChanged(prev_index, prev_index); |
| 166 | } | 165 | } |
| 167 | 166 | ||
| 168 | DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread) : | 167 | DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread) |
| 169 | QDockWidget(parent), base_addr(0), emu_thread(emu_thread) { | 168 | : QDockWidget(parent), base_addr(0), emu_thread(emu_thread) { |
| 170 | 169 | ||
| 171 | disasm_ui.setupUi(this); | 170 | disasm_ui.setupUi(this); |
| 172 | 171 | ||
| 173 | RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut); | 172 | RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut); |
| 174 | RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut); | 173 | RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut); |
| 175 | RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut); | 174 | RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut); |
| 176 | RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9), Qt::ApplicationShortcut); | 175 | RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9), |
| 176 | Qt::ApplicationShortcut); | ||
| 177 | 177 | ||
| 178 | connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep())); | 178 | connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep())); |
| 179 | connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause())); | 179 | connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause())); |
| 180 | connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue())); | 180 | connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue())); |
| 181 | 181 | ||
| 182 | connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this, SLOT(OnToggleStartStop())); | 182 | connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this, |
| 183 | SLOT(OnToggleStartStop())); | ||
| 183 | connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep())); | 184 | connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep())); |
| 184 | connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this, SLOT(OnStepInto())); | 185 | connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this, |
| 186 | SLOT(OnStepInto())); | ||
| 185 | 187 | ||
| 186 | setEnabled(false); | 188 | setEnabled(false); |
| 187 | } | 189 | } |
| @@ -195,7 +197,8 @@ void DisassemblerWidget::Init() { | |||
| 195 | 197 | ||
| 196 | QModelIndex model_index = model->IndexFromAbsoluteAddress(Core::g_app_core->GetPC()); | 198 | QModelIndex model_index = model->IndexFromAbsoluteAddress(Core::g_app_core->GetPC()); |
| 197 | disasm_ui.treeView->scrollTo(model_index); | 199 | disasm_ui.treeView->scrollTo(model_index); |
| 198 | disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | 200 | disasm_ui.treeView->selectionModel()->setCurrentIndex( |
| 201 | model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | ||
| 199 | } | 202 | } |
| 200 | 203 | ||
| 201 | void DisassemblerWidget::OnContinue() { | 204 | void DisassemblerWidget::OnContinue() { |
| @@ -234,7 +237,8 @@ void DisassemblerWidget::OnDebugModeEntered() { | |||
| 234 | 237 | ||
| 235 | QModelIndex model_index = model->IndexFromAbsoluteAddress(next_instr); | 238 | QModelIndex model_index = model->IndexFromAbsoluteAddress(next_instr); |
| 236 | disasm_ui.treeView->scrollTo(model_index); | 239 | disasm_ui.treeView->scrollTo(model_index); |
| 237 | disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | 240 | disasm_ui.treeView->selectionModel()->setCurrentIndex( |
| 241 | model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | ||
| 238 | } | 242 | } |
| 239 | 243 | ||
| 240 | void DisassemblerWidget::OnDebugModeLeft() { | 244 | void DisassemblerWidget::OnDebugModeLeft() { |
| @@ -254,10 +258,12 @@ void DisassemblerWidget::OnEmulationStarting(EmuThread* emu_thread) { | |||
| 254 | model = new DisassemblerModel(this); | 258 | model = new DisassemblerModel(this); |
| 255 | disasm_ui.treeView->setModel(model); | 259 | disasm_ui.treeView->setModel(model); |
| 256 | 260 | ||
| 257 | connect(disasm_ui.treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), | 261 | connect(disasm_ui.treeView->selectionModel(), |
| 258 | model, SLOT(OnSelectionChanged(const QModelIndex&))); | 262 | SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), model, |
| 263 | SLOT(OnSelectionChanged(const QModelIndex&))); | ||
| 259 | connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint())); | 264 | connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint())); |
| 260 | connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, SLOT(OnSetOrUnsetBreakpoint())); | 265 | connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, |
| 266 | SLOT(OnSetOrUnsetBreakpoint())); | ||
| 261 | 267 | ||
| 262 | Init(); | 268 | Init(); |
| 263 | setEnabled(true); | 269 | setEnabled(true); |
diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h index 340fb9936..1f5607788 100644 --- a/src/citra_qt/debugger/disassembler.h +++ b/src/citra_qt/debugger/disassembler.h | |||
| @@ -15,8 +15,7 @@ | |||
| 15 | class QAction; | 15 | class QAction; |
| 16 | class EmuThread; | 16 | class EmuThread; |
| 17 | 17 | ||
| 18 | class DisassemblerModel : public QAbstractListModel | 18 | class DisassemblerModel : public QAbstractListModel { |
| 19 | { | ||
| 20 | Q_OBJECT | 19 | Q_OBJECT |
| 21 | 20 | ||
| 22 | public: | 21 | public: |
| @@ -46,8 +45,7 @@ private: | |||
| 46 | mutable BreakPoints breakpoints; | 45 | mutable BreakPoints breakpoints; |
| 47 | }; | 46 | }; |
| 48 | 47 | ||
| 49 | class DisassemblerWidget : public QDockWidget | 48 | class DisassemblerWidget : public QDockWidget { |
| 50 | { | ||
| 51 | Q_OBJECT | 49 | Q_OBJECT |
| 52 | 50 | ||
| 53 | public: | 51 | public: |
diff --git a/src/citra_qt/debugger/graphics.cpp b/src/citra_qt/debugger/graphics.cpp index eccd619ba..b79c063db 100644 --- a/src/citra_qt/debugger/graphics.cpp +++ b/src/citra_qt/debugger/graphics.cpp | |||
| @@ -9,69 +9,62 @@ | |||
| 9 | 9 | ||
| 10 | extern GraphicsDebugger g_debugger; | 10 | extern GraphicsDebugger g_debugger; |
| 11 | 11 | ||
| 12 | GPUCommandStreamItemModel::GPUCommandStreamItemModel(QObject* parent) : QAbstractListModel(parent), command_count(0) | 12 | GPUCommandStreamItemModel::GPUCommandStreamItemModel(QObject* parent) |
| 13 | { | 13 | : QAbstractListModel(parent), command_count(0) { |
| 14 | connect(this, SIGNAL(GXCommandFinished(int)), this, SLOT(OnGXCommandFinishedInternal(int))); | 14 | connect(this, SIGNAL(GXCommandFinished(int)), this, SLOT(OnGXCommandFinishedInternal(int))); |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | int GPUCommandStreamItemModel::rowCount(const QModelIndex& parent) const | 17 | int GPUCommandStreamItemModel::rowCount(const QModelIndex& parent) const { |
| 18 | { | ||
| 19 | return command_count; | 18 | return command_count; |
| 20 | } | 19 | } |
| 21 | 20 | ||
| 22 | QVariant GPUCommandStreamItemModel::data(const QModelIndex& index, int role) const | 21 | QVariant GPUCommandStreamItemModel::data(const QModelIndex& index, int role) const { |
| 23 | { | ||
| 24 | if (!index.isValid()) | 22 | if (!index.isValid()) |
| 25 | return QVariant(); | 23 | return QVariant(); |
| 26 | 24 | ||
| 27 | int command_index = index.row(); | 25 | int command_index = index.row(); |
| 28 | const GSP_GPU::Command& command = GetDebugger()->ReadGXCommandHistory(command_index); | 26 | const GSP_GPU::Command& command = GetDebugger()->ReadGXCommandHistory(command_index); |
| 29 | if (role == Qt::DisplayRole) | 27 | if (role == Qt::DisplayRole) { |
| 30 | { | ||
| 31 | std::map<GSP_GPU::CommandId, const char*> command_names = { | 28 | std::map<GSP_GPU::CommandId, const char*> command_names = { |
| 32 | { GSP_GPU::CommandId::REQUEST_DMA, "REQUEST_DMA" }, | 29 | {GSP_GPU::CommandId::REQUEST_DMA, "REQUEST_DMA"}, |
| 33 | { GSP_GPU::CommandId::SUBMIT_GPU_CMDLIST, "SUBMIT_GPU_CMDLIST" }, | 30 | {GSP_GPU::CommandId::SUBMIT_GPU_CMDLIST, "SUBMIT_GPU_CMDLIST"}, |
| 34 | { GSP_GPU::CommandId::SET_MEMORY_FILL, "SET_MEMORY_FILL" }, | 31 | {GSP_GPU::CommandId::SET_MEMORY_FILL, "SET_MEMORY_FILL"}, |
| 35 | { GSP_GPU::CommandId::SET_DISPLAY_TRANSFER, "SET_DISPLAY_TRANSFER" }, | 32 | {GSP_GPU::CommandId::SET_DISPLAY_TRANSFER, "SET_DISPLAY_TRANSFER"}, |
| 36 | { GSP_GPU::CommandId::SET_TEXTURE_COPY, "SET_TEXTURE_COPY" }, | 33 | {GSP_GPU::CommandId::SET_TEXTURE_COPY, "SET_TEXTURE_COPY"}, |
| 37 | { GSP_GPU::CommandId::CACHE_FLUSH, "CACHE_FLUSH" }, | 34 | {GSP_GPU::CommandId::CACHE_FLUSH, "CACHE_FLUSH"}, |
| 38 | }; | 35 | }; |
| 39 | const u32* command_data = reinterpret_cast<const u32*>(&command); | 36 | const u32* command_data = reinterpret_cast<const u32*>(&command); |
| 40 | QString str = QString("%1 %2 %3 %4 %5 %6 %7 %8 %9").arg(command_names[command.id]) | 37 | QString str = QString("%1 %2 %3 %4 %5 %6 %7 %8 %9") |
| 41 | .arg(command_data[0], 8, 16, QLatin1Char('0')) | 38 | .arg(command_names[command.id]) |
| 42 | .arg(command_data[1], 8, 16, QLatin1Char('0')) | 39 | .arg(command_data[0], 8, 16, QLatin1Char('0')) |
| 43 | .arg(command_data[2], 8, 16, QLatin1Char('0')) | 40 | .arg(command_data[1], 8, 16, QLatin1Char('0')) |
| 44 | .arg(command_data[3], 8, 16, QLatin1Char('0')) | 41 | .arg(command_data[2], 8, 16, QLatin1Char('0')) |
| 45 | .arg(command_data[4], 8, 16, QLatin1Char('0')) | 42 | .arg(command_data[3], 8, 16, QLatin1Char('0')) |
| 46 | .arg(command_data[5], 8, 16, QLatin1Char('0')) | 43 | .arg(command_data[4], 8, 16, QLatin1Char('0')) |
| 47 | .arg(command_data[6], 8, 16, QLatin1Char('0')) | 44 | .arg(command_data[5], 8, 16, QLatin1Char('0')) |
| 48 | .arg(command_data[7], 8, 16, QLatin1Char('0')); | 45 | .arg(command_data[6], 8, 16, QLatin1Char('0')) |
| 46 | .arg(command_data[7], 8, 16, QLatin1Char('0')); | ||
| 49 | return QVariant(str); | 47 | return QVariant(str); |
| 50 | } | 48 | } else { |
| 51 | else | ||
| 52 | { | ||
| 53 | return QVariant(); | 49 | return QVariant(); |
| 54 | } | 50 | } |
| 55 | } | 51 | } |
| 56 | 52 | ||
| 57 | void GPUCommandStreamItemModel::GXCommandProcessed(int total_command_count) | 53 | void GPUCommandStreamItemModel::GXCommandProcessed(int total_command_count) { |
| 58 | { | ||
| 59 | emit GXCommandFinished(total_command_count); | 54 | emit GXCommandFinished(total_command_count); |
| 60 | } | 55 | } |
| 61 | 56 | ||
| 62 | void GPUCommandStreamItemModel::OnGXCommandFinishedInternal(int total_command_count) | 57 | void GPUCommandStreamItemModel::OnGXCommandFinishedInternal(int total_command_count) { |
| 63 | { | ||
| 64 | if (total_command_count == 0) | 58 | if (total_command_count == 0) |
| 65 | return; | 59 | return; |
| 66 | 60 | ||
| 67 | int prev_command_count = command_count; | 61 | int prev_command_count = command_count; |
| 68 | command_count = total_command_count; | 62 | command_count = total_command_count; |
| 69 | emit dataChanged(index(prev_command_count,0), index(total_command_count-1,0)); | 63 | emit dataChanged(index(prev_command_count, 0), index(total_command_count - 1, 0)); |
| 70 | } | 64 | } |
| 71 | 65 | ||
| 72 | 66 | GPUCommandStreamWidget::GPUCommandStreamWidget(QWidget* parent) | |
| 73 | GPUCommandStreamWidget::GPUCommandStreamWidget(QWidget* parent) : QDockWidget(tr("Graphics Debugger"), parent) | 67 | : QDockWidget(tr("Graphics Debugger"), parent) { |
| 74 | { | ||
| 75 | setObjectName("GraphicsDebugger"); | 68 | setObjectName("GraphicsDebugger"); |
| 76 | 69 | ||
| 77 | GPUCommandStreamItemModel* command_model = new GPUCommandStreamItemModel(this); | 70 | GPUCommandStreamItemModel* command_model = new GPUCommandStreamItemModel(this); |
diff --git a/src/citra_qt/debugger/graphics.h b/src/citra_qt/debugger/graphics.h index 36b25b81d..7d681b97d 100644 --- a/src/citra_qt/debugger/graphics.h +++ b/src/citra_qt/debugger/graphics.h | |||
| @@ -9,8 +9,8 @@ | |||
| 9 | 9 | ||
| 10 | #include "video_core/gpu_debugger.h" | 10 | #include "video_core/gpu_debugger.h" |
| 11 | 11 | ||
| 12 | class GPUCommandStreamItemModel : public QAbstractListModel, public GraphicsDebugger::DebuggerObserver | 12 | class GPUCommandStreamItemModel : public QAbstractListModel, |
| 13 | { | 13 | public GraphicsDebugger::DebuggerObserver { |
| 14 | Q_OBJECT | 14 | Q_OBJECT |
| 15 | 15 | ||
| 16 | public: | 16 | public: |
| @@ -32,8 +32,7 @@ private: | |||
| 32 | int command_count; | 32 | int command_count; |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | class GPUCommandStreamWidget : public QDockWidget | 35 | class GPUCommandStreamWidget : public QDockWidget { |
| 36 | { | ||
| 37 | Q_OBJECT | 36 | Q_OBJECT |
| 38 | 37 | ||
| 39 | public: | 38 | public: |
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.cpp b/src/citra_qt/debugger/graphics_breakpoint_observer.cpp index f134eef63..25a398ece 100644 --- a/src/citra_qt/debugger/graphics_breakpoint_observer.cpp +++ b/src/citra_qt/debugger/graphics_breakpoint_observer.cpp | |||
| @@ -8,25 +8,21 @@ | |||
| 8 | 8 | ||
| 9 | BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, | 9 | BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, |
| 10 | const QString& title, QWidget* parent) | 10 | const QString& title, QWidget* parent) |
| 11 | : QDockWidget(title, parent), BreakPointObserver(debug_context) | 11 | : QDockWidget(title, parent), BreakPointObserver(debug_context) { |
| 12 | { | ||
| 13 | qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); | 12 | qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); |
| 14 | 13 | ||
| 15 | connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed())); | 14 | connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed())); |
| 16 | 15 | ||
| 17 | // NOTE: This signal is emitted from a non-GUI thread, but connect() takes | 16 | // NOTE: This signal is emitted from a non-GUI thread, but connect() takes |
| 18 | // care of delaying its handling to the GUI thread. | 17 | // care of delaying its handling to the GUI thread. |
| 19 | connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), | 18 | connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event, void*)), this, |
| 20 | this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)), | 19 | SLOT(OnBreakPointHit(Pica::DebugContext::Event, void*)), Qt::BlockingQueuedConnection); |
| 21 | Qt::BlockingQueuedConnection); | ||
| 22 | } | 20 | } |
| 23 | 21 | ||
| 24 | void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) | 22 | void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) { |
| 25 | { | ||
| 26 | emit BreakPointHit(event, data); | 23 | emit BreakPointHit(event, data); |
| 27 | } | 24 | } |
| 28 | 25 | ||
| 29 | void BreakPointObserverDock::OnPicaResume() | 26 | void BreakPointObserverDock::OnPicaResume() { |
| 30 | { | ||
| 31 | emit Resumed(); | 27 | emit Resumed(); |
| 32 | } | 28 | } |
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.h b/src/citra_qt/debugger/graphics_breakpoint_observer.h index 02a0f4f4f..8d0871f27 100644 --- a/src/citra_qt/debugger/graphics_breakpoint_observer.h +++ b/src/citra_qt/debugger/graphics_breakpoint_observer.h | |||
| @@ -13,7 +13,8 @@ | |||
| 13 | * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while | 13 | * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while |
| 14 | * the widget usually wants to perform reactions in the GUI thread. | 14 | * the widget usually wants to perform reactions in the GUI thread. |
| 15 | */ | 15 | */ |
| 16 | class BreakPointObserverDock : public QDockWidget, protected Pica::DebugContext::BreakPointObserver { | 16 | class BreakPointObserverDock : public QDockWidget, |
| 17 | protected Pica::DebugContext::BreakPointObserver { | ||
| 17 | Q_OBJECT | 18 | Q_OBJECT |
| 18 | 19 | ||
| 19 | public: | 20 | public: |
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index fe66918a8..953840e7f 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp | |||
| @@ -16,39 +16,33 @@ | |||
| 16 | BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent) | 16 | BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent) |
| 17 | : QAbstractListModel(parent), context_weak(debug_context), | 17 | : QAbstractListModel(parent), context_weak(debug_context), |
| 18 | at_breakpoint(debug_context->at_breakpoint), | 18 | at_breakpoint(debug_context->at_breakpoint), |
| 19 | active_breakpoint(debug_context->active_breakpoint) | 19 | active_breakpoint(debug_context->active_breakpoint) { |
| 20 | { | ||
| 21 | |||
| 22 | } | 20 | } |
| 23 | 21 | ||
| 24 | int BreakPointModel::columnCount(const QModelIndex& parent) const | 22 | int BreakPointModel::columnCount(const QModelIndex& parent) const { |
| 25 | { | ||
| 26 | return 1; | 23 | return 1; |
| 27 | } | 24 | } |
| 28 | 25 | ||
| 29 | int BreakPointModel::rowCount(const QModelIndex& parent) const | 26 | int BreakPointModel::rowCount(const QModelIndex& parent) const { |
| 30 | { | ||
| 31 | return static_cast<int>(Pica::DebugContext::Event::NumEvents); | 27 | return static_cast<int>(Pica::DebugContext::Event::NumEvents); |
| 32 | } | 28 | } |
| 33 | 29 | ||
| 34 | QVariant BreakPointModel::data(const QModelIndex& index, int role) const | 30 | QVariant BreakPointModel::data(const QModelIndex& index, int role) const { |
| 35 | { | ||
| 36 | const auto event = static_cast<Pica::DebugContext::Event>(index.row()); | 31 | const auto event = static_cast<Pica::DebugContext::Event>(index.row()); |
| 37 | 32 | ||
| 38 | switch (role) { | 33 | switch (role) { |
| 39 | case Qt::DisplayRole: | 34 | case Qt::DisplayRole: { |
| 40 | { | ||
| 41 | if (index.column() == 0) { | 35 | if (index.column() == 0) { |
| 42 | static const std::map<Pica::DebugContext::Event, QString> map = { | 36 | static const std::map<Pica::DebugContext::Event, QString> map = { |
| 43 | { Pica::DebugContext::Event::PicaCommandLoaded, tr("Pica command loaded") }, | 37 | {Pica::DebugContext::Event::PicaCommandLoaded, tr("Pica command loaded")}, |
| 44 | { Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed") }, | 38 | {Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed")}, |
| 45 | { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") }, | 39 | {Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch")}, |
| 46 | { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") }, | 40 | {Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch")}, |
| 47 | { Pica::DebugContext::Event::VertexShaderInvocation, tr("Vertex shader invocation") }, | 41 | {Pica::DebugContext::Event::VertexShaderInvocation, tr("Vertex shader invocation")}, |
| 48 | { Pica::DebugContext::Event::IncomingDisplayTransfer, tr("Incoming display transfer") }, | 42 | {Pica::DebugContext::Event::IncomingDisplayTransfer, |
| 49 | { Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed") }, | 43 | tr("Incoming display transfer")}, |
| 50 | { Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped") } | 44 | {Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed")}, |
| 51 | }; | 45 | {Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped")}}; |
| 52 | 46 | ||
| 53 | DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents)); | 47 | DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents)); |
| 54 | return (map.find(event) != map.end()) ? map.at(event) : QString(); | 48 | return (map.find(event) != map.end()) ? map.at(event) : QString(); |
| @@ -57,23 +51,20 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const | |||
| 57 | break; | 51 | break; |
| 58 | } | 52 | } |
| 59 | 53 | ||
| 60 | case Qt::CheckStateRole: | 54 | case Qt::CheckStateRole: { |
| 61 | { | ||
| 62 | if (index.column() == 0) | 55 | if (index.column() == 0) |
| 63 | return data(index, Role_IsEnabled).toBool() ? Qt::Checked : Qt::Unchecked; | 56 | return data(index, Role_IsEnabled).toBool() ? Qt::Checked : Qt::Unchecked; |
| 64 | break; | 57 | break; |
| 65 | } | 58 | } |
| 66 | 59 | ||
| 67 | case Qt::BackgroundRole: | 60 | case Qt::BackgroundRole: { |
| 68 | { | ||
| 69 | if (at_breakpoint && index.row() == static_cast<int>(active_breakpoint)) { | 61 | if (at_breakpoint && index.row() == static_cast<int>(active_breakpoint)) { |
| 70 | return QBrush(QColor(0xE0, 0xE0, 0x10)); | 62 | return QBrush(QColor(0xE0, 0xE0, 0x10)); |
| 71 | } | 63 | } |
| 72 | break; | 64 | break; |
| 73 | } | 65 | } |
| 74 | 66 | ||
| 75 | case Role_IsEnabled: | 67 | case Role_IsEnabled: { |
| 76 | { | ||
| 77 | auto context = context_weak.lock(); | 68 | auto context = context_weak.lock(); |
| 78 | return context && context->breakpoints[(int)event].enabled; | 69 | return context && context->breakpoints[(int)event].enabled; |
| 79 | } | 70 | } |
| @@ -84,8 +75,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const | |||
| 84 | return QVariant(); | 75 | return QVariant(); |
| 85 | } | 76 | } |
| 86 | 77 | ||
| 87 | Qt::ItemFlags BreakPointModel::flags(const QModelIndex &index) const | 78 | Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const { |
| 88 | { | ||
| 89 | if (!index.isValid()) | 79 | if (!index.isValid()) |
| 90 | return 0; | 80 | return 0; |
| 91 | 81 | ||
| @@ -95,14 +85,11 @@ Qt::ItemFlags BreakPointModel::flags(const QModelIndex &index) const | |||
| 95 | return flags; | 85 | return flags; |
| 96 | } | 86 | } |
| 97 | 87 | ||
| 98 | 88 | bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) { | |
| 99 | bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) | ||
| 100 | { | ||
| 101 | const auto event = static_cast<Pica::DebugContext::Event>(index.row()); | 89 | const auto event = static_cast<Pica::DebugContext::Event>(index.row()); |
| 102 | 90 | ||
| 103 | switch (role) { | 91 | switch (role) { |
| 104 | case Qt::CheckStateRole: | 92 | case Qt::CheckStateRole: { |
| 105 | { | ||
| 106 | if (index.column() != 0) | 93 | if (index.column() != 0) |
| 107 | return false; | 94 | return false; |
| 108 | 95 | ||
| @@ -120,9 +107,7 @@ bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, i | |||
| 120 | return false; | 107 | return false; |
| 121 | } | 108 | } |
| 122 | 109 | ||
| 123 | 110 | void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event) { | |
| 124 | void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event) | ||
| 125 | { | ||
| 126 | auto context = context_weak.lock(); | 111 | auto context = context_weak.lock(); |
| 127 | if (!context) | 112 | if (!context) |
| 128 | return; | 113 | return; |
| @@ -133,8 +118,7 @@ void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event) | |||
| 133 | createIndex(static_cast<int>(event), 0)); | 118 | createIndex(static_cast<int>(event), 0)); |
| 134 | } | 119 | } |
| 135 | 120 | ||
| 136 | void BreakPointModel::OnResumed() | 121 | void BreakPointModel::OnResumed() { |
| 137 | { | ||
| 138 | auto context = context_weak.lock(); | 122 | auto context = context_weak.lock(); |
| 139 | if (!context) | 123 | if (!context) |
| 140 | return; | 124 | return; |
| @@ -145,12 +129,10 @@ void BreakPointModel::OnResumed() | |||
| 145 | active_breakpoint = context->active_breakpoint; | 129 | active_breakpoint = context->active_breakpoint; |
| 146 | } | 130 | } |
| 147 | 131 | ||
| 148 | 132 | GraphicsBreakPointsWidget::GraphicsBreakPointsWidget( | |
| 149 | GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context, | 133 | std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent) |
| 150 | QWidget* parent) | ||
| 151 | : QDockWidget(tr("Pica Breakpoints"), parent), | 134 | : QDockWidget(tr("Pica Breakpoints"), parent), |
| 152 | Pica::DebugContext::BreakPointObserver(debug_context) | 135 | Pica::DebugContext::BreakPointObserver(debug_context) { |
| 153 | { | ||
| 154 | setObjectName("PicaBreakPointsWidget"); | 136 | setObjectName("PicaBreakPointsWidget"); |
| 155 | 137 | ||
| 156 | status_text = new QLabel(tr("Emulation running")); | 138 | status_text = new QLabel(tr("Emulation running")); |
| @@ -165,23 +147,21 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug | |||
| 165 | 147 | ||
| 166 | qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); | 148 | qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); |
| 167 | 149 | ||
| 168 | connect(breakpoint_list, SIGNAL(doubleClicked(const QModelIndex&)), | 150 | connect(breakpoint_list, SIGNAL(doubleClicked(const QModelIndex&)), this, |
| 169 | this, SLOT(OnItemDoubleClicked(const QModelIndex&))); | 151 | SLOT(OnItemDoubleClicked(const QModelIndex&))); |
| 170 | 152 | ||
| 171 | connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested())); | 153 | connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested())); |
| 172 | 154 | ||
| 173 | connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), | 155 | connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event, void*)), this, |
| 174 | this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)), | 156 | SLOT(OnBreakPointHit(Pica::DebugContext::Event, void*)), Qt::BlockingQueuedConnection); |
| 175 | Qt::BlockingQueuedConnection); | ||
| 176 | connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed())); | 157 | connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed())); |
| 177 | 158 | ||
| 178 | connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), | 159 | connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event, void*)), breakpoint_model, |
| 179 | breakpoint_model, SLOT(OnBreakPointHit(Pica::DebugContext::Event)), | 160 | SLOT(OnBreakPointHit(Pica::DebugContext::Event)), Qt::BlockingQueuedConnection); |
| 180 | Qt::BlockingQueuedConnection); | ||
| 181 | connect(this, SIGNAL(Resumed()), breakpoint_model, SLOT(OnResumed())); | 161 | connect(this, SIGNAL(Resumed()), breakpoint_model, SLOT(OnResumed())); |
| 182 | 162 | ||
| 183 | connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)), | 163 | connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&, const QModelIndex&)), |
| 184 | breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))); | 164 | breakpoint_model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&))); |
| 185 | 165 | ||
| 186 | QWidget* main_widget = new QWidget; | 166 | QWidget* main_widget = new QWidget; |
| 187 | auto main_layout = new QVBoxLayout; | 167 | auto main_layout = new QVBoxLayout; |
| @@ -197,38 +177,32 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug | |||
| 197 | setWidget(main_widget); | 177 | setWidget(main_widget); |
| 198 | } | 178 | } |
| 199 | 179 | ||
| 200 | void GraphicsBreakPointsWidget::OnPicaBreakPointHit(Event event, void* data) | 180 | void GraphicsBreakPointsWidget::OnPicaBreakPointHit(Event event, void* data) { |
| 201 | { | ||
| 202 | // Process in GUI thread | 181 | // Process in GUI thread |
| 203 | emit BreakPointHit(event, data); | 182 | emit BreakPointHit(event, data); |
| 204 | } | 183 | } |
| 205 | 184 | ||
| 206 | void GraphicsBreakPointsWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) | 185 | void GraphicsBreakPointsWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) { |
| 207 | { | ||
| 208 | status_text->setText(tr("Emulation halted at breakpoint")); | 186 | status_text->setText(tr("Emulation halted at breakpoint")); |
| 209 | resume_button->setEnabled(true); | 187 | resume_button->setEnabled(true); |
| 210 | } | 188 | } |
| 211 | 189 | ||
| 212 | void GraphicsBreakPointsWidget::OnPicaResume() | 190 | void GraphicsBreakPointsWidget::OnPicaResume() { |
| 213 | { | ||
| 214 | // Process in GUI thread | 191 | // Process in GUI thread |
| 215 | emit Resumed(); | 192 | emit Resumed(); |
| 216 | } | 193 | } |
| 217 | 194 | ||
| 218 | void GraphicsBreakPointsWidget::OnResumed() | 195 | void GraphicsBreakPointsWidget::OnResumed() { |
| 219 | { | ||
| 220 | status_text->setText(tr("Emulation running")); | 196 | status_text->setText(tr("Emulation running")); |
| 221 | resume_button->setEnabled(false); | 197 | resume_button->setEnabled(false); |
| 222 | } | 198 | } |
| 223 | 199 | ||
| 224 | void GraphicsBreakPointsWidget::OnResumeRequested() | 200 | void GraphicsBreakPointsWidget::OnResumeRequested() { |
| 225 | { | ||
| 226 | if (auto context = context_weak.lock()) | 201 | if (auto context = context_weak.lock()) |
| 227 | context->Resume(); | 202 | context->Resume(); |
| 228 | } | 203 | } |
| 229 | 204 | ||
| 230 | void GraphicsBreakPointsWidget::OnItemDoubleClicked(const QModelIndex& index) | 205 | void GraphicsBreakPointsWidget::OnItemDoubleClicked(const QModelIndex& index) { |
| 231 | { | ||
| 232 | if (!index.isValid()) | 206 | if (!index.isValid()) |
| 233 | return; | 207 | return; |
| 234 | 208 | ||
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics_breakpoints_p.h index 251114d06..5f321ede2 100644 --- a/src/citra_qt/debugger/graphics_breakpoints_p.h +++ b/src/citra_qt/debugger/graphics_breakpoints_p.h | |||
| @@ -23,7 +23,7 @@ public: | |||
| 23 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; | 23 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; |
| 24 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; | 24 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
| 25 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | 25 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 26 | Qt::ItemFlags flags(const QModelIndex &index) const override; | 26 | Qt::ItemFlags flags(const QModelIndex& index) const override; |
| 27 | 27 | ||
| 28 | bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; | 28 | bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; |
| 29 | 29 | ||
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 3e0a0a145..daf1cf1de 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp | |||
| @@ -20,9 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | #include "common/vector_math.h" | 21 | #include "common/vector_math.h" |
| 22 | 22 | ||
| 23 | #include "video_core/debug_utils/debug_utils.h" | ||
| 23 | #include "video_core/pica.h" | 24 | #include "video_core/pica.h" |
| 24 | #include "video_core/pica_state.h" | 25 | #include "video_core/pica_state.h" |
| 25 | #include "video_core/debug_utils/debug_utils.h" | ||
| 26 | 26 | ||
| 27 | QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) { | 27 | QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) { |
| 28 | QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); | 28 | QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); |
| @@ -38,7 +38,8 @@ QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) { | |||
| 38 | 38 | ||
| 39 | class TextureInfoWidget : public QWidget { | 39 | class TextureInfoWidget : public QWidget { |
| 40 | public: | 40 | public: |
| 41 | TextureInfoWidget(u8* src, const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr) : QWidget(parent) { | 41 | TextureInfoWidget(u8* src, const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr) |
| 42 | : QWidget(parent) { | ||
| 42 | QLabel* image_widget = new QLabel; | 43 | QLabel* image_widget = new QLabel; |
| 43 | QPixmap image_pixmap = QPixmap::fromImage(LoadTexture(src, info)); | 44 | QPixmap image_pixmap = QPixmap::fromImage(LoadTexture(src, info)); |
| 44 | image_pixmap = image_pixmap.scaled(200, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation); | 45 | image_pixmap = image_pixmap.scaled(200, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation); |
| @@ -51,7 +52,6 @@ public: | |||
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) { | 54 | GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) { |
| 54 | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | int GPUCommandListModel::rowCount(const QModelIndex& parent) const { | 57 | int GPUCommandListModel::rowCount(const QModelIndex& parent) const { |
| @@ -70,7 +70,7 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { | |||
| 70 | 70 | ||
| 71 | if (role == Qt::DisplayRole) { | 71 | if (role == Qt::DisplayRole) { |
| 72 | QString content; | 72 | QString content; |
| 73 | switch ( index.column() ) { | 73 | switch (index.column()) { |
| 74 | case 0: | 74 | case 0: |
| 75 | return QString::fromLatin1(Pica::Regs::GetCommandName(write.cmd_id).c_str()); | 75 | return QString::fromLatin1(Pica::Regs::GetCommandName(write.cmd_id).c_str()); |
| 76 | case 1: | 76 | case 1: |
| @@ -88,9 +88,8 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { | |||
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientation, int role) const { | 90 | QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientation, int role) const { |
| 91 | switch(role) { | 91 | switch (role) { |
| 92 | case Qt::DisplayRole: | 92 | case Qt::DisplayRole: { |
| 93 | { | ||
| 94 | switch (section) { | 93 | switch (section) { |
| 95 | case 0: | 94 | case 0: |
| 96 | return tr("Command Name"); | 95 | return tr("Command Name"); |
| @@ -117,14 +116,14 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& | |||
| 117 | endResetModel(); | 116 | endResetModel(); |
| 118 | } | 117 | } |
| 119 | 118 | ||
| 120 | #define COMMAND_IN_RANGE(cmd_id, reg_name) \ | 119 | #define COMMAND_IN_RANGE(cmd_id, reg_name) \ |
| 121 | (cmd_id >= PICA_REG_INDEX(reg_name) && \ | 120 | (cmd_id >= PICA_REG_INDEX(reg_name) && \ |
| 122 | cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::g_state.regs.reg_name)) / 4) | 121 | cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::g_state.regs.reg_name)) / 4) |
| 123 | 122 | ||
| 124 | void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { | 123 | void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { |
| 125 | const unsigned int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); | 124 | const unsigned int command_id = |
| 126 | if (COMMAND_IN_RANGE(command_id, texture0) || | 125 | list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); |
| 127 | COMMAND_IN_RANGE(command_id, texture1) || | 126 | if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) || |
| 128 | COMMAND_IN_RANGE(command_id, texture2)) { | 127 | COMMAND_IN_RANGE(command_id, texture2)) { |
| 129 | 128 | ||
| 130 | unsigned index; | 129 | unsigned index; |
| @@ -148,9 +147,9 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { | |||
| 148 | void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { | 147 | void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { |
| 149 | QWidget* new_info_widget = nullptr; | 148 | QWidget* new_info_widget = nullptr; |
| 150 | 149 | ||
| 151 | const unsigned int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); | 150 | const unsigned int command_id = |
| 152 | if (COMMAND_IN_RANGE(command_id, texture0) || | 151 | list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); |
| 153 | COMMAND_IN_RANGE(command_id, texture1) || | 152 | if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) || |
| 154 | COMMAND_IN_RANGE(command_id, texture2)) { | 153 | COMMAND_IN_RANGE(command_id, texture2)) { |
| 155 | 154 | ||
| 156 | unsigned index; | 155 | unsigned index; |
| @@ -179,7 +178,8 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { | |||
| 179 | } | 178 | } |
| 180 | #undef COMMAND_IN_RANGE | 179 | #undef COMMAND_IN_RANGE |
| 181 | 180 | ||
| 182 | GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) { | 181 | GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) |
| 182 | : QDockWidget(tr("Pica Command List"), parent) { | ||
| 183 | setObjectName("Pica Command List"); | 183 | setObjectName("Pica Command List"); |
| 184 | GPUCommandListModel* model = new GPUCommandListModel(this); | 184 | GPUCommandListModel* model = new GPUCommandListModel(this); |
| 185 | 185 | ||
| @@ -191,23 +191,24 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi | |||
| 191 | list_widget->setRootIsDecorated(false); | 191 | list_widget->setRootIsDecorated(false); |
| 192 | list_widget->setUniformRowHeights(true); | 192 | list_widget->setUniformRowHeights(true); |
| 193 | 193 | ||
| 194 | #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) | 194 | #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) |
| 195 | list_widget->header()->setSectionResizeMode(QHeaderView::ResizeToContents); | 195 | list_widget->header()->setSectionResizeMode(QHeaderView::ResizeToContents); |
| 196 | #else | 196 | #else |
| 197 | list_widget->header()->setResizeMode(QHeaderView::ResizeToContents); | 197 | list_widget->header()->setResizeMode(QHeaderView::ResizeToContents); |
| 198 | #endif | 198 | #endif |
| 199 | 199 | ||
| 200 | connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), | 200 | connect(list_widget->selectionModel(), |
| 201 | this, SLOT(SetCommandInfo(const QModelIndex&))); | 201 | SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, |
| 202 | connect(list_widget, SIGNAL(doubleClicked(const QModelIndex&)), | 202 | SLOT(SetCommandInfo(const QModelIndex&))); |
| 203 | this, SLOT(OnCommandDoubleClicked(const QModelIndex&))); | 203 | connect(list_widget, SIGNAL(doubleClicked(const QModelIndex&)), this, |
| 204 | SLOT(OnCommandDoubleClicked(const QModelIndex&))); | ||
| 204 | 205 | ||
| 205 | toggle_tracing = new QPushButton(tr("Start Tracing")); | 206 | toggle_tracing = new QPushButton(tr("Start Tracing")); |
| 206 | QPushButton* copy_all = new QPushButton(tr("Copy All")); | 207 | QPushButton* copy_all = new QPushButton(tr("Copy All")); |
| 207 | 208 | ||
| 208 | connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); | 209 | connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); |
| 209 | connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), | 210 | connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), model, |
| 210 | model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); | 211 | SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); |
| 211 | 212 | ||
| 212 | connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard())); | 213 | connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard())); |
| 213 | 214 | ||
diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics_cmdlists.h index 8a2a294b9..b2242eca4 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.h +++ b/src/citra_qt/debugger/graphics_cmdlists.h | |||
| @@ -7,14 +7,13 @@ | |||
| 7 | #include <QAbstractListModel> | 7 | #include <QAbstractListModel> |
| 8 | #include <QDockWidget> | 8 | #include <QDockWidget> |
| 9 | 9 | ||
| 10 | #include "video_core/gpu_debugger.h" | ||
| 11 | #include "video_core/debug_utils/debug_utils.h" | 10 | #include "video_core/debug_utils/debug_utils.h" |
| 11 | #include "video_core/gpu_debugger.h" | ||
| 12 | 12 | ||
| 13 | class QPushButton; | 13 | class QPushButton; |
| 14 | class QTreeView; | 14 | class QTreeView; |
| 15 | 15 | ||
| 16 | class GPUCommandListModel : public QAbstractListModel | 16 | class GPUCommandListModel : public QAbstractListModel { |
| 17 | { | ||
| 18 | Q_OBJECT | 17 | Q_OBJECT |
| 19 | 18 | ||
| 20 | public: | 19 | public: |
| @@ -27,7 +26,8 @@ public: | |||
| 27 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; | 26 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; |
| 28 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; | 27 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
| 29 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | 28 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 30 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; | 29 | QVariant headerData(int section, Qt::Orientation orientation, |
| 30 | int role = Qt::DisplayRole) const override; | ||
| 31 | 31 | ||
| 32 | public slots: | 32 | public slots: |
| 33 | void OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace); | 33 | void OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace); |
| @@ -36,8 +36,7 @@ private: | |||
| 36 | Pica::DebugUtils::PicaTrace pica_trace; | 36 | Pica::DebugUtils::PicaTrace pica_trace; |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | class GPUCommandListWidget : public QDockWidget | 39 | class GPUCommandListWidget : public QDockWidget { |
| 40 | { | ||
| 41 | Q_OBJECT | 40 | Q_OBJECT |
| 42 | 41 | ||
| 43 | public: | 42 | public: |
diff --git a/src/citra_qt/debugger/graphics_surface.cpp b/src/citra_qt/debugger/graphics_surface.cpp index ac2d6f89b..839fca124 100644 --- a/src/citra_qt/debugger/graphics_surface.cpp +++ b/src/citra_qt/debugger/graphics_surface.cpp | |||
| @@ -17,18 +17,20 @@ | |||
| 17 | 17 | ||
| 18 | #include "common/color.h" | 18 | #include "common/color.h" |
| 19 | 19 | ||
| 20 | #include "core/memory.h" | ||
| 21 | #include "core/hw/gpu.h" | 20 | #include "core/hw/gpu.h" |
| 21 | #include "core/memory.h" | ||
| 22 | 22 | ||
| 23 | #include "video_core/pica.h" | 23 | #include "video_core/pica.h" |
| 24 | #include "video_core/pica_state.h" | 24 | #include "video_core/pica_state.h" |
| 25 | #include "video_core/utils.h" | 25 | #include "video_core/utils.h" |
| 26 | 26 | ||
| 27 | SurfacePicture::SurfacePicture(QWidget* parent, GraphicsSurfaceWidget* surface_widget_) : QLabel(parent), surface_widget(surface_widget_) {} | 27 | SurfacePicture::SurfacePicture(QWidget* parent, GraphicsSurfaceWidget* surface_widget_) |
| 28 | SurfacePicture::~SurfacePicture() {} | 28 | : QLabel(parent), surface_widget(surface_widget_) { |
| 29 | } | ||
| 30 | SurfacePicture::~SurfacePicture() { | ||
| 31 | } | ||
| 29 | 32 | ||
| 30 | void SurfacePicture::mousePressEvent(QMouseEvent* event) | 33 | void SurfacePicture::mousePressEvent(QMouseEvent* event) { |
| 31 | { | ||
| 32 | // Only do something while the left mouse button is held down | 34 | // Only do something while the left mouse button is held down |
| 33 | if (!(event->buttons() & Qt::LeftButton)) | 35 | if (!(event->buttons() & Qt::LeftButton)) |
| 34 | return; | 36 | return; |
| @@ -41,18 +43,15 @@ void SurfacePicture::mousePressEvent(QMouseEvent* event) | |||
| 41 | event->y() * pixmap()->height() / height()); | 43 | event->y() * pixmap()->height() / height()); |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 44 | void SurfacePicture::mouseMoveEvent(QMouseEvent* event) | 46 | void SurfacePicture::mouseMoveEvent(QMouseEvent* event) { |
| 45 | { | ||
| 46 | // We also want to handle the event if the user moves the mouse while holding down the LMB | 47 | // We also want to handle the event if the user moves the mouse while holding down the LMB |
| 47 | mousePressEvent(event); | 48 | mousePressEvent(event); |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | |||
| 51 | GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context, | 51 | GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context, |
| 52 | QWidget* parent) | 52 | QWidget* parent) |
| 53 | : BreakPointObserverDock(debug_context, tr("Pica Surface Viewer"), parent), | 53 | : BreakPointObserverDock(debug_context, tr("Pica Surface Viewer"), parent), |
| 54 | surface_source(Source::ColorBuffer) | 54 | surface_source(Source::ColorBuffer) { |
| 55 | { | ||
| 56 | setObjectName("PicaSurface"); | 55 | setObjectName("PicaSurface"); |
| 57 | 56 | ||
| 58 | surface_source_list = new QComboBox; | 57 | surface_source_list = new QComboBox; |
| @@ -124,13 +123,20 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> | |||
| 124 | 123 | ||
| 125 | // Connections | 124 | // Connections |
| 126 | connect(this, SIGNAL(Update()), this, SLOT(OnUpdate())); | 125 | connect(this, SIGNAL(Update()), this, SLOT(OnUpdate())); |
| 127 | connect(surface_source_list, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSurfaceSourceChanged(int))); | 126 | connect(surface_source_list, SIGNAL(currentIndexChanged(int)), this, |
| 128 | connect(surface_address_control, SIGNAL(ValueChanged(qint64)), this, SLOT(OnSurfaceAddressChanged(qint64))); | 127 | SLOT(OnSurfaceSourceChanged(int))); |
| 129 | connect(surface_width_control, SIGNAL(valueChanged(int)), this, SLOT(OnSurfaceWidthChanged(int))); | 128 | connect(surface_address_control, SIGNAL(ValueChanged(qint64)), this, |
| 130 | connect(surface_height_control, SIGNAL(valueChanged(int)), this, SLOT(OnSurfaceHeightChanged(int))); | 129 | SLOT(OnSurfaceAddressChanged(qint64))); |
| 131 | connect(surface_format_control, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSurfaceFormatChanged(int))); | 130 | connect(surface_width_control, SIGNAL(valueChanged(int)), this, |
| 132 | connect(surface_picker_x_control, SIGNAL(valueChanged(int)), this, SLOT(OnSurfacePickerXChanged(int))); | 131 | SLOT(OnSurfaceWidthChanged(int))); |
| 133 | connect(surface_picker_y_control, SIGNAL(valueChanged(int)), this, SLOT(OnSurfacePickerYChanged(int))); | 132 | connect(surface_height_control, SIGNAL(valueChanged(int)), this, |
| 133 | SLOT(OnSurfaceHeightChanged(int))); | ||
| 134 | connect(surface_format_control, SIGNAL(currentIndexChanged(int)), this, | ||
| 135 | SLOT(OnSurfaceFormatChanged(int))); | ||
| 136 | connect(surface_picker_x_control, SIGNAL(valueChanged(int)), this, | ||
| 137 | SLOT(OnSurfacePickerXChanged(int))); | ||
| 138 | connect(surface_picker_y_control, SIGNAL(valueChanged(int)), this, | ||
| 139 | SLOT(OnSurfacePickerYChanged(int))); | ||
| 134 | connect(save_surface, SIGNAL(clicked()), this, SLOT(SaveSurface())); | 140 | connect(save_surface, SIGNAL(clicked()), this, SLOT(SaveSurface())); |
| 135 | 141 | ||
| 136 | auto main_widget = new QWidget; | 142 | auto main_widget = new QWidget; |
| @@ -203,25 +209,21 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> | |||
| 203 | } | 209 | } |
| 204 | } | 210 | } |
| 205 | 211 | ||
| 206 | void GraphicsSurfaceWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) | 212 | void GraphicsSurfaceWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) { |
| 207 | { | ||
| 208 | emit Update(); | 213 | emit Update(); |
| 209 | widget()->setEnabled(true); | 214 | widget()->setEnabled(true); |
| 210 | } | 215 | } |
| 211 | 216 | ||
| 212 | void GraphicsSurfaceWidget::OnResumed() | 217 | void GraphicsSurfaceWidget::OnResumed() { |
| 213 | { | ||
| 214 | widget()->setEnabled(false); | 218 | widget()->setEnabled(false); |
| 215 | } | 219 | } |
| 216 | 220 | ||
| 217 | void GraphicsSurfaceWidget::OnSurfaceSourceChanged(int new_value) | 221 | void GraphicsSurfaceWidget::OnSurfaceSourceChanged(int new_value) { |
| 218 | { | ||
| 219 | surface_source = static_cast<Source>(new_value); | 222 | surface_source = static_cast<Source>(new_value); |
| 220 | emit Update(); | 223 | emit Update(); |
| 221 | } | 224 | } |
| 222 | 225 | ||
| 223 | void GraphicsSurfaceWidget::OnSurfaceAddressChanged(qint64 new_value) | 226 | void GraphicsSurfaceWidget::OnSurfaceAddressChanged(qint64 new_value) { |
| 224 | { | ||
| 225 | if (surface_address != new_value) { | 227 | if (surface_address != new_value) { |
| 226 | surface_address = static_cast<unsigned>(new_value); | 228 | surface_address = static_cast<unsigned>(new_value); |
| 227 | 229 | ||
| @@ -230,8 +232,7 @@ void GraphicsSurfaceWidget::OnSurfaceAddressChanged(qint64 new_value) | |||
| 230 | } | 232 | } |
| 231 | } | 233 | } |
| 232 | 234 | ||
| 233 | void GraphicsSurfaceWidget::OnSurfaceWidthChanged(int new_value) | 235 | void GraphicsSurfaceWidget::OnSurfaceWidthChanged(int new_value) { |
| 234 | { | ||
| 235 | if (surface_width != static_cast<unsigned>(new_value)) { | 236 | if (surface_width != static_cast<unsigned>(new_value)) { |
| 236 | surface_width = static_cast<unsigned>(new_value); | 237 | surface_width = static_cast<unsigned>(new_value); |
| 237 | 238 | ||
| @@ -240,8 +241,7 @@ void GraphicsSurfaceWidget::OnSurfaceWidthChanged(int new_value) | |||
| 240 | } | 241 | } |
| 241 | } | 242 | } |
| 242 | 243 | ||
| 243 | void GraphicsSurfaceWidget::OnSurfaceHeightChanged(int new_value) | 244 | void GraphicsSurfaceWidget::OnSurfaceHeightChanged(int new_value) { |
| 244 | { | ||
| 245 | if (surface_height != static_cast<unsigned>(new_value)) { | 245 | if (surface_height != static_cast<unsigned>(new_value)) { |
| 246 | surface_height = static_cast<unsigned>(new_value); | 246 | surface_height = static_cast<unsigned>(new_value); |
| 247 | 247 | ||
| @@ -250,8 +250,7 @@ void GraphicsSurfaceWidget::OnSurfaceHeightChanged(int new_value) | |||
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | void GraphicsSurfaceWidget::OnSurfaceFormatChanged(int new_value) | 253 | void GraphicsSurfaceWidget::OnSurfaceFormatChanged(int new_value) { |
| 254 | { | ||
| 255 | if (surface_format != static_cast<Format>(new_value)) { | 254 | if (surface_format != static_cast<Format>(new_value)) { |
| 256 | surface_format = static_cast<Format>(new_value); | 255 | surface_format = static_cast<Format>(new_value); |
| 257 | 256 | ||
| @@ -260,24 +259,21 @@ void GraphicsSurfaceWidget::OnSurfaceFormatChanged(int new_value) | |||
| 260 | } | 259 | } |
| 261 | } | 260 | } |
| 262 | 261 | ||
| 263 | void GraphicsSurfaceWidget::OnSurfacePickerXChanged(int new_value) | 262 | void GraphicsSurfaceWidget::OnSurfacePickerXChanged(int new_value) { |
| 264 | { | ||
| 265 | if (surface_picker_x != new_value) { | 263 | if (surface_picker_x != new_value) { |
| 266 | surface_picker_x = new_value; | 264 | surface_picker_x = new_value; |
| 267 | Pick(surface_picker_x, surface_picker_y); | 265 | Pick(surface_picker_x, surface_picker_y); |
| 268 | } | 266 | } |
| 269 | } | 267 | } |
| 270 | 268 | ||
| 271 | void GraphicsSurfaceWidget::OnSurfacePickerYChanged(int new_value) | 269 | void GraphicsSurfaceWidget::OnSurfacePickerYChanged(int new_value) { |
| 272 | { | ||
| 273 | if (surface_picker_y != new_value) { | 270 | if (surface_picker_y != new_value) { |
| 274 | surface_picker_y = new_value; | 271 | surface_picker_y = new_value; |
| 275 | Pick(surface_picker_x, surface_picker_y); | 272 | Pick(surface_picker_x, surface_picker_y); |
| 276 | } | 273 | } |
| 277 | } | 274 | } |
| 278 | 275 | ||
| 279 | void GraphicsSurfaceWidget::Pick(int x, int y) | 276 | void GraphicsSurfaceWidget::Pick(int x, int y) { |
| 280 | { | ||
| 281 | surface_picker_x_control->setValue(x); | 277 | surface_picker_x_control->setValue(x); |
| 282 | surface_picker_y_control->setValue(y); | 278 | surface_picker_y_control->setValue(y); |
| 283 | 279 | ||
| @@ -312,74 +308,63 @@ void GraphicsSurfaceWidget::Pick(int x, int y) | |||
| 312 | 308 | ||
| 313 | auto GetText = [offset](Format format, const u8* pixel) { | 309 | auto GetText = [offset](Format format, const u8* pixel) { |
| 314 | switch (format) { | 310 | switch (format) { |
| 315 | case Format::RGBA8: | 311 | case Format::RGBA8: { |
| 316 | { | ||
| 317 | auto value = Color::DecodeRGBA8(pixel) / 255.0f; | 312 | auto value = Color::DecodeRGBA8(pixel) / 255.0f; |
| 318 | return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4") | 313 | return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4") |
| 319 | .arg(QString::number(value.r(), 'f', 2)) | 314 | .arg(QString::number(value.r(), 'f', 2)) |
| 320 | .arg(QString::number(value.g(), 'f', 2)) | 315 | .arg(QString::number(value.g(), 'f', 2)) |
| 321 | .arg(QString::number(value.b(), 'f', 2)) | 316 | .arg(QString::number(value.b(), 'f', 2)) |
| 322 | .arg(QString::number(value.a(), 'f', 2)); | 317 | .arg(QString::number(value.a(), 'f', 2)); |
| 323 | } | 318 | } |
| 324 | case Format::RGB8: | 319 | case Format::RGB8: { |
| 325 | { | ||
| 326 | auto value = Color::DecodeRGB8(pixel) / 255.0f; | 320 | auto value = Color::DecodeRGB8(pixel) / 255.0f; |
| 327 | return QString("Red: %1, Green: %2, Blue: %3") | 321 | return QString("Red: %1, Green: %2, Blue: %3") |
| 328 | .arg(QString::number(value.r(), 'f', 2)) | 322 | .arg(QString::number(value.r(), 'f', 2)) |
| 329 | .arg(QString::number(value.g(), 'f', 2)) | 323 | .arg(QString::number(value.g(), 'f', 2)) |
| 330 | .arg(QString::number(value.b(), 'f', 2)); | 324 | .arg(QString::number(value.b(), 'f', 2)); |
| 331 | } | 325 | } |
| 332 | case Format::RGB5A1: | 326 | case Format::RGB5A1: { |
| 333 | { | ||
| 334 | auto value = Color::DecodeRGB5A1(pixel) / 255.0f; | 327 | auto value = Color::DecodeRGB5A1(pixel) / 255.0f; |
| 335 | return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4") | 328 | return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4") |
| 336 | .arg(QString::number(value.r(), 'f', 2)) | 329 | .arg(QString::number(value.r(), 'f', 2)) |
| 337 | .arg(QString::number(value.g(), 'f', 2)) | 330 | .arg(QString::number(value.g(), 'f', 2)) |
| 338 | .arg(QString::number(value.b(), 'f', 2)) | 331 | .arg(QString::number(value.b(), 'f', 2)) |
| 339 | .arg(QString::number(value.a(), 'f', 2)); | 332 | .arg(QString::number(value.a(), 'f', 2)); |
| 340 | } | 333 | } |
| 341 | case Format::RGB565: | 334 | case Format::RGB565: { |
| 342 | { | ||
| 343 | auto value = Color::DecodeRGB565(pixel) / 255.0f; | 335 | auto value = Color::DecodeRGB565(pixel) / 255.0f; |
| 344 | return QString("Red: %1, Green: %2, Blue: %3") | 336 | return QString("Red: %1, Green: %2, Blue: %3") |
| 345 | .arg(QString::number(value.r(), 'f', 2)) | 337 | .arg(QString::number(value.r(), 'f', 2)) |
| 346 | .arg(QString::number(value.g(), 'f', 2)) | 338 | .arg(QString::number(value.g(), 'f', 2)) |
| 347 | .arg(QString::number(value.b(), 'f', 2)); | 339 | .arg(QString::number(value.b(), 'f', 2)); |
| 348 | } | 340 | } |
| 349 | case Format::RGBA4: | 341 | case Format::RGBA4: { |
| 350 | { | ||
| 351 | auto value = Color::DecodeRGBA4(pixel) / 255.0f; | 342 | auto value = Color::DecodeRGBA4(pixel) / 255.0f; |
| 352 | return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4") | 343 | return QString("Red: %1, Green: %2, Blue: %3, Alpha: %4") |
| 353 | .arg(QString::number(value.r(), 'f', 2)) | 344 | .arg(QString::number(value.r(), 'f', 2)) |
| 354 | .arg(QString::number(value.g(), 'f', 2)) | 345 | .arg(QString::number(value.g(), 'f', 2)) |
| 355 | .arg(QString::number(value.b(), 'f', 2)) | 346 | .arg(QString::number(value.b(), 'f', 2)) |
| 356 | .arg(QString::number(value.a(), 'f', 2)); | 347 | .arg(QString::number(value.a(), 'f', 2)); |
| 357 | } | 348 | } |
| 358 | case Format::IA8: | 349 | case Format::IA8: |
| 359 | return QString("Index: %1, Alpha: %2") | 350 | return QString("Index: %1, Alpha: %2").arg(pixel[0]).arg(pixel[1]); |
| 360 | .arg(pixel[0]) | ||
| 361 | .arg(pixel[1]); | ||
| 362 | case Format::RG8: { | 351 | case Format::RG8: { |
| 363 | auto value = Color::DecodeRG8(pixel) / 255.0f; | 352 | auto value = Color::DecodeRG8(pixel) / 255.0f; |
| 364 | return QString("Red: %1, Green: %2") | 353 | return QString("Red: %1, Green: %2") |
| 365 | .arg(QString::number(value.r(), 'f', 2)) | 354 | .arg(QString::number(value.r(), 'f', 2)) |
| 366 | .arg(QString::number(value.g(), 'f', 2)); | 355 | .arg(QString::number(value.g(), 'f', 2)); |
| 367 | } | 356 | } |
| 368 | case Format::I8: | 357 | case Format::I8: |
| 369 | return QString("Index: %1").arg(*pixel); | 358 | return QString("Index: %1").arg(*pixel); |
| 370 | case Format::A8: | 359 | case Format::A8: |
| 371 | return QString("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2)); | 360 | return QString("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2)); |
| 372 | case Format::IA4: | 361 | case Format::IA4: |
| 373 | return QString("Index: %1, Alpha: %2") | 362 | return QString("Index: %1, Alpha: %2").arg(*pixel & 0xF).arg((*pixel & 0xF0) >> 4); |
| 374 | .arg(*pixel & 0xF) | 363 | case Format::I4: { |
| 375 | .arg((*pixel & 0xF0) >> 4); | ||
| 376 | case Format::I4: | ||
| 377 | { | ||
| 378 | u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; | 364 | u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; |
| 379 | return QString("Index: %1").arg(i); | 365 | return QString("Index: %1").arg(i); |
| 380 | } | 366 | } |
| 381 | case Format::A4: | 367 | case Format::A4: { |
| 382 | { | ||
| 383 | u8 a = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; | 368 | u8 a = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; |
| 384 | return QString("Alpha: %1").arg(QString::number(a / 15.0f, 'f', 2)); | 369 | return QString("Alpha: %1").arg(QString::number(a / 15.0f, 'f', 2)); |
| 385 | } | 370 | } |
| @@ -387,21 +372,20 @@ void GraphicsSurfaceWidget::Pick(int x, int y) | |||
| 387 | case Format::ETC1A4: | 372 | case Format::ETC1A4: |
| 388 | // TODO: Display block information or channel values? | 373 | // TODO: Display block information or channel values? |
| 389 | return QString("Compressed data"); | 374 | return QString("Compressed data"); |
| 390 | case Format::D16: | 375 | case Format::D16: { |
| 391 | { | ||
| 392 | auto value = Color::DecodeD16(pixel); | 376 | auto value = Color::DecodeD16(pixel); |
| 393 | return QString("Depth: %1").arg(QString::number(value / (float)0xFFFF, 'f', 4)); | 377 | return QString("Depth: %1").arg(QString::number(value / (float)0xFFFF, 'f', 4)); |
| 394 | } | 378 | } |
| 395 | case Format::D24: | 379 | case Format::D24: { |
| 396 | { | ||
| 397 | auto value = Color::DecodeD24(pixel); | 380 | auto value = Color::DecodeD24(pixel); |
| 398 | return QString("Depth: %1").arg(QString::number(value / (float)0xFFFFFF, 'f', 4)); | 381 | return QString("Depth: %1").arg(QString::number(value / (float)0xFFFFFF, 'f', 4)); |
| 399 | } | 382 | } |
| 400 | case Format::D24X8: | 383 | case Format::D24X8: |
| 401 | case Format::X24S8: | 384 | case Format::X24S8: { |
| 402 | { | ||
| 403 | auto values = Color::DecodeD24S8(pixel); | 385 | auto values = Color::DecodeD24S8(pixel); |
| 404 | return QString("Depth: %1, Stencil: %2").arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4)).arg(values[1]); | 386 | return QString("Depth: %1, Stencil: %2") |
| 387 | .arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4)) | ||
| 388 | .arg(values[1]); | ||
| 405 | } | 389 | } |
| 406 | case Format::Unknown: | 390 | case Format::Unknown: |
| 407 | return QString("Unknown format"); | 391 | return QString("Unknown format"); |
| @@ -422,18 +406,18 @@ void GraphicsSurfaceWidget::Pick(int x, int y) | |||
| 422 | nibbles.append(QString::number(nibble, 16).toUpper()); | 406 | nibbles.append(QString::number(nibble, 16).toUpper()); |
| 423 | } | 407 | } |
| 424 | 408 | ||
| 425 | surface_info_label->setText(QString("Raw: 0x%3\n(%4)").arg(nibbles).arg(GetText(surface_format, pixel))); | 409 | surface_info_label->setText( |
| 410 | QString("Raw: 0x%3\n(%4)").arg(nibbles).arg(GetText(surface_format, pixel))); | ||
| 426 | surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); | 411 | surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); |
| 427 | } | 412 | } |
| 428 | 413 | ||
| 429 | void GraphicsSurfaceWidget::OnUpdate() | 414 | void GraphicsSurfaceWidget::OnUpdate() { |
| 430 | { | ||
| 431 | QPixmap pixmap; | 415 | QPixmap pixmap; |
| 432 | 416 | ||
| 433 | switch (surface_source) { | 417 | switch (surface_source) { |
| 434 | case Source::ColorBuffer: | 418 | case Source::ColorBuffer: { |
| 435 | { | 419 | // TODO: Store a reference to the registers in the debug context instead of accessing them |
| 436 | // TODO: Store a reference to the registers in the debug context instead of accessing them directly... | 420 | // directly... |
| 437 | 421 | ||
| 438 | const auto& framebuffer = Pica::g_state.regs.framebuffer; | 422 | const auto& framebuffer = Pica::g_state.regs.framebuffer; |
| 439 | 423 | ||
| @@ -470,8 +454,7 @@ void GraphicsSurfaceWidget::OnUpdate() | |||
| 470 | break; | 454 | break; |
| 471 | } | 455 | } |
| 472 | 456 | ||
| 473 | case Source::DepthBuffer: | 457 | case Source::DepthBuffer: { |
| 474 | { | ||
| 475 | const auto& framebuffer = Pica::g_state.regs.framebuffer; | 458 | const auto& framebuffer = Pica::g_state.regs.framebuffer; |
| 476 | 459 | ||
| 477 | surface_address = framebuffer.GetDepthBufferPhysicalAddress(); | 460 | surface_address = framebuffer.GetDepthBufferPhysicalAddress(); |
| @@ -499,8 +482,7 @@ void GraphicsSurfaceWidget::OnUpdate() | |||
| 499 | break; | 482 | break; |
| 500 | } | 483 | } |
| 501 | 484 | ||
| 502 | case Source::StencilBuffer: | 485 | case Source::StencilBuffer: { |
| 503 | { | ||
| 504 | const auto& framebuffer = Pica::g_state.regs.framebuffer; | 486 | const auto& framebuffer = Pica::g_state.regs.framebuffer; |
| 505 | 487 | ||
| 506 | surface_address = framebuffer.GetDepthBufferPhysicalAddress(); | 488 | surface_address = framebuffer.GetDepthBufferPhysicalAddress(); |
| @@ -522,12 +504,14 @@ void GraphicsSurfaceWidget::OnUpdate() | |||
| 522 | 504 | ||
| 523 | case Source::Texture0: | 505 | case Source::Texture0: |
| 524 | case Source::Texture1: | 506 | case Source::Texture1: |
| 525 | case Source::Texture2: | 507 | case Source::Texture2: { |
| 526 | { | ||
| 527 | unsigned texture_index; | 508 | unsigned texture_index; |
| 528 | if (surface_source == Source::Texture0) texture_index = 0; | 509 | if (surface_source == Source::Texture0) |
| 529 | else if (surface_source == Source::Texture1) texture_index = 1; | 510 | texture_index = 0; |
| 530 | else if (surface_source == Source::Texture2) texture_index = 2; | 511 | else if (surface_source == Source::Texture1) |
| 512 | texture_index = 1; | ||
| 513 | else if (surface_source == Source::Texture2) | ||
| 514 | texture_index = 2; | ||
| 531 | else { | 515 | else { |
| 532 | qDebug() << "Unknown texture source " << static_cast<int>(surface_source); | 516 | qDebug() << "Unknown texture source " << static_cast<int>(surface_source); |
| 533 | break; | 517 | break; |
| @@ -547,8 +531,7 @@ void GraphicsSurfaceWidget::OnUpdate() | |||
| 547 | break; | 531 | break; |
| 548 | } | 532 | } |
| 549 | 533 | ||
| 550 | case Source::Custom: | 534 | case Source::Custom: { |
| 551 | { | ||
| 552 | // Keep user-specified values | 535 | // Keep user-specified values |
| 553 | break; | 536 | break; |
| 554 | } | 537 | } |
| @@ -613,7 +596,8 @@ void GraphicsSurfaceWidget::OnUpdate() | |||
| 613 | 596 | ||
| 614 | } else { | 597 | } else { |
| 615 | 598 | ||
| 616 | ASSERT_MSG(nibbles_per_pixel >= 2, "Depth decoder only supports formats with at least one byte per pixel"); | 599 | ASSERT_MSG(nibbles_per_pixel >= 2, |
| 600 | "Depth decoder only supports formats with at least one byte per pixel"); | ||
| 617 | unsigned bytes_per_pixel = nibbles_per_pixel / 2; | 601 | unsigned bytes_per_pixel = nibbles_per_pixel / 2; |
| 618 | 602 | ||
| 619 | for (unsigned int y = 0; y < surface_height; ++y) { | 603 | for (unsigned int y = 0; y < surface_height; ++y) { |
| @@ -621,34 +605,30 @@ void GraphicsSurfaceWidget::OnUpdate() | |||
| 621 | const u32 coarse_y = y & ~7; | 605 | const u32 coarse_y = y & ~7; |
| 622 | u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | 606 | u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; |
| 623 | const u8* pixel = buffer + offset; | 607 | const u8* pixel = buffer + offset; |
| 624 | Math::Vec4<u8> color = { 0, 0, 0, 0 }; | 608 | Math::Vec4<u8> color = {0, 0, 0, 0}; |
| 625 | 609 | ||
| 626 | switch(surface_format) { | 610 | switch (surface_format) { |
| 627 | case Format::D16: | 611 | case Format::D16: { |
| 628 | { | ||
| 629 | u32 data = Color::DecodeD16(pixel); | 612 | u32 data = Color::DecodeD16(pixel); |
| 630 | color.r() = data & 0xFF; | 613 | color.r() = data & 0xFF; |
| 631 | color.g() = (data >> 8) & 0xFF; | 614 | color.g() = (data >> 8) & 0xFF; |
| 632 | break; | 615 | break; |
| 633 | } | 616 | } |
| 634 | case Format::D24: | 617 | case Format::D24: { |
| 635 | { | ||
| 636 | u32 data = Color::DecodeD24(pixel); | 618 | u32 data = Color::DecodeD24(pixel); |
| 637 | color.r() = data & 0xFF; | 619 | color.r() = data & 0xFF; |
| 638 | color.g() = (data >> 8) & 0xFF; | 620 | color.g() = (data >> 8) & 0xFF; |
| 639 | color.b() = (data >> 16) & 0xFF; | 621 | color.b() = (data >> 16) & 0xFF; |
| 640 | break; | 622 | break; |
| 641 | } | 623 | } |
| 642 | case Format::D24X8: | 624 | case Format::D24X8: { |
| 643 | { | ||
| 644 | Math::Vec2<u32> data = Color::DecodeD24S8(pixel); | 625 | Math::Vec2<u32> data = Color::DecodeD24S8(pixel); |
| 645 | color.r() = data.x & 0xFF; | 626 | color.r() = data.x & 0xFF; |
| 646 | color.g() = (data.x >> 8) & 0xFF; | 627 | color.g() = (data.x >> 8) & 0xFF; |
| 647 | color.b() = (data.x >> 16) & 0xFF; | 628 | color.b() = (data.x >> 16) & 0xFF; |
| 648 | break; | 629 | break; |
| 649 | } | 630 | } |
| 650 | case Format::X24S8: | 631 | case Format::X24S8: { |
| 651 | { | ||
| 652 | Math::Vec2<u32> data = Color::DecodeD24S8(pixel); | 632 | Math::Vec2<u32> data = Color::DecodeD24S8(pixel); |
| 653 | color.r() = color.g() = color.b() = data.y; | 633 | color.r() = color.g() = color.b() = data.y; |
| 654 | break; | 634 | break; |
| @@ -661,7 +641,6 @@ void GraphicsSurfaceWidget::OnUpdate() | |||
| 661 | decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), 255)); | 641 | decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), 255)); |
| 662 | } | 642 | } |
| 663 | } | 643 | } |
| 664 | |||
| 665 | } | 644 | } |
| 666 | 645 | ||
| 667 | pixmap = QPixmap::fromImage(decoded_image); | 646 | pixmap = QPixmap::fromImage(decoded_image); |
| @@ -682,8 +661,10 @@ void GraphicsSurfaceWidget::SaveSurface() { | |||
| 682 | QString bin_filter = tr("Binary data (*.bin)"); | 661 | QString bin_filter = tr("Binary data (*.bin)"); |
| 683 | 662 | ||
| 684 | QString selectedFilter; | 663 | QString selectedFilter; |
| 685 | QString filename = QFileDialog::getSaveFileName(this, tr("Save Surface"), QString("texture-0x%1.png").arg(QString::number(surface_address, 16)), | 664 | QString filename = QFileDialog::getSaveFileName( |
| 686 | QString("%1;;%2").arg(png_filter, bin_filter), &selectedFilter); | 665 | this, tr("Save Surface"), |
| 666 | QString("texture-0x%1.png").arg(QString::number(surface_address, 16)), | ||
| 667 | QString("%1;;%2").arg(png_filter, bin_filter), &selectedFilter); | ||
| 687 | 668 | ||
| 688 | if (filename.isEmpty()) { | 669 | if (filename.isEmpty()) { |
| 689 | // If the user canceled the dialog, don't save anything. | 670 | // If the user canceled the dialog, don't save anything. |
| @@ -718,19 +699,19 @@ unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Forma | |||
| 718 | } | 699 | } |
| 719 | 700 | ||
| 720 | switch (format) { | 701 | switch (format) { |
| 721 | case Format::D24X8: | 702 | case Format::D24X8: |
| 722 | case Format::X24S8: | 703 | case Format::X24S8: |
| 723 | return 4 * 2; | 704 | return 4 * 2; |
| 724 | case Format::D24: | 705 | case Format::D24: |
| 725 | return 3 * 2; | 706 | return 3 * 2; |
| 726 | case Format::D16: | 707 | case Format::D16: |
| 727 | return 2 * 2; | 708 | return 2 * 2; |
| 728 | default: | 709 | default: |
| 729 | UNREACHABLE_MSG("GraphicsSurfaceWidget::BytesPerPixel: this " | 710 | UNREACHABLE_MSG("GraphicsSurfaceWidget::BytesPerPixel: this " |
| 730 | "should not be reached as this function should " | 711 | "should not be reached as this function should " |
| 731 | "be given a format which is in " | 712 | "be given a format which is in " |
| 732 | "GraphicsSurfaceWidget::Format. Instead got %i", | 713 | "GraphicsSurfaceWidget::Format. Instead got %i", |
| 733 | static_cast<int>(format)); | 714 | static_cast<int>(format)); |
| 734 | return 0; | 715 | return 0; |
| 735 | } | 716 | } |
| 736 | } | 717 | } |
diff --git a/src/citra_qt/debugger/graphics_surface.h b/src/citra_qt/debugger/graphics_surface.h index 7c7f50e38..5881ae60a 100644 --- a/src/citra_qt/debugger/graphics_surface.h +++ b/src/citra_qt/debugger/graphics_surface.h | |||
| @@ -15,8 +15,7 @@ class CSpinBox; | |||
| 15 | 15 | ||
| 16 | class GraphicsSurfaceWidget; | 16 | class GraphicsSurfaceWidget; |
| 17 | 17 | ||
| 18 | class SurfacePicture : public QLabel | 18 | class SurfacePicture : public QLabel { |
| 19 | { | ||
| 20 | Q_OBJECT | 19 | Q_OBJECT |
| 21 | 20 | ||
| 22 | public: | 21 | public: |
| @@ -29,7 +28,6 @@ protected slots: | |||
| 29 | 28 | ||
| 30 | private: | 29 | private: |
| 31 | GraphicsSurfaceWidget* surface_widget; | 30 | GraphicsSurfaceWidget* surface_widget; |
| 32 | |||
| 33 | }; | 31 | }; |
| 34 | 32 | ||
| 35 | class GraphicsSurfaceWidget : public BreakPointObserverDock { | 33 | class GraphicsSurfaceWidget : public BreakPointObserverDock { |
| @@ -38,43 +36,44 @@ class GraphicsSurfaceWidget : public BreakPointObserverDock { | |||
| 38 | using Event = Pica::DebugContext::Event; | 36 | using Event = Pica::DebugContext::Event; |
| 39 | 37 | ||
| 40 | enum class Source { | 38 | enum class Source { |
| 41 | ColorBuffer = 0, | 39 | ColorBuffer = 0, |
| 42 | DepthBuffer = 1, | 40 | DepthBuffer = 1, |
| 43 | StencilBuffer = 2, | 41 | StencilBuffer = 2, |
| 44 | Texture0 = 3, | 42 | Texture0 = 3, |
| 45 | Texture1 = 4, | 43 | Texture1 = 4, |
| 46 | Texture2 = 5, | 44 | Texture2 = 5, |
| 47 | Custom = 6, | 45 | Custom = 6, |
| 48 | }; | 46 | }; |
| 49 | 47 | ||
| 50 | enum class Format { | 48 | enum class Format { |
| 51 | // These must match the TextureFormat type! | 49 | // These must match the TextureFormat type! |
| 52 | RGBA8 = 0, | 50 | RGBA8 = 0, |
| 53 | RGB8 = 1, | 51 | RGB8 = 1, |
| 54 | RGB5A1 = 2, | 52 | RGB5A1 = 2, |
| 55 | RGB565 = 3, | 53 | RGB565 = 3, |
| 56 | RGBA4 = 4, | 54 | RGBA4 = 4, |
| 57 | IA8 = 5, | 55 | IA8 = 5, |
| 58 | RG8 = 6, ///< @note Also called HILO8 in 3DBrew. | 56 | RG8 = 6, ///< @note Also called HILO8 in 3DBrew. |
| 59 | I8 = 7, | 57 | I8 = 7, |
| 60 | A8 = 8, | 58 | A8 = 8, |
| 61 | IA4 = 9, | 59 | IA4 = 9, |
| 62 | I4 = 10, | 60 | I4 = 10, |
| 63 | A4 = 11, | 61 | A4 = 11, |
| 64 | ETC1 = 12, // compressed | 62 | ETC1 = 12, // compressed |
| 65 | ETC1A4 = 13, | 63 | ETC1A4 = 13, |
| 66 | MaxTextureFormat = 13, | 64 | MaxTextureFormat = 13, |
| 67 | D16 = 14, | 65 | D16 = 14, |
| 68 | D24 = 15, | 66 | D24 = 15, |
| 69 | D24X8 = 16, | 67 | D24X8 = 16, |
| 70 | X24S8 = 17, | 68 | X24S8 = 17, |
| 71 | Unknown = 18, | 69 | Unknown = 18, |
| 72 | }; | 70 | }; |
| 73 | 71 | ||
| 74 | static unsigned int NibblesPerPixel(Format format); | 72 | static unsigned int NibblesPerPixel(Format format); |
| 75 | 73 | ||
| 76 | public: | 74 | public: |
| 77 | GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr); | 75 | GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context, |
| 76 | QWidget* parent = nullptr); | ||
| 78 | void Pick(int x, int y); | 77 | void Pick(int x, int y); |
| 79 | 78 | ||
| 80 | public slots: | 79 | public slots: |
| @@ -97,7 +96,6 @@ signals: | |||
| 97 | void Update(); | 96 | void Update(); |
| 98 | 97 | ||
| 99 | private: | 98 | private: |
| 100 | |||
| 101 | QComboBox* surface_source_list; | 99 | QComboBox* surface_source_list; |
| 102 | CSpinBox* surface_address_control; | 100 | CSpinBox* surface_address_control; |
| 103 | QSpinBox* surface_width_control; | 101 | QSpinBox* surface_width_control; |
diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp index 9c80f7ec9..b6f638b60 100644 --- a/src/citra_qt/debugger/graphics_tracing.cpp +++ b/src/citra_qt/debugger/graphics_tracing.cpp | |||
| @@ -35,12 +35,16 @@ GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> | |||
| 35 | setObjectName("CiTracing"); | 35 | setObjectName("CiTracing"); |
| 36 | 36 | ||
| 37 | QPushButton* start_recording = new QPushButton(tr("Start Recording")); | 37 | QPushButton* start_recording = new QPushButton(tr("Start Recording")); |
| 38 | QPushButton* stop_recording = new QPushButton(QIcon::fromTheme("document-save"), tr("Stop and Save")); | 38 | QPushButton* stop_recording = |
| 39 | new QPushButton(QIcon::fromTheme("document-save"), tr("Stop and Save")); | ||
| 39 | QPushButton* abort_recording = new QPushButton(tr("Abort Recording")); | 40 | QPushButton* abort_recording = new QPushButton(tr("Abort Recording")); |
| 40 | 41 | ||
| 41 | connect(this, SIGNAL(SetStartTracingButtonEnabled(bool)), start_recording, SLOT(setVisible(bool))); | 42 | connect(this, SIGNAL(SetStartTracingButtonEnabled(bool)), start_recording, |
| 42 | connect(this, SIGNAL(SetStopTracingButtonEnabled(bool)), stop_recording, SLOT(setVisible(bool))); | 43 | SLOT(setVisible(bool))); |
| 43 | connect(this, SIGNAL(SetAbortTracingButtonEnabled(bool)), abort_recording, SLOT(setVisible(bool))); | 44 | connect(this, SIGNAL(SetStopTracingButtonEnabled(bool)), stop_recording, |
| 45 | SLOT(setVisible(bool))); | ||
| 46 | connect(this, SIGNAL(SetAbortTracingButtonEnabled(bool)), abort_recording, | ||
| 47 | SLOT(setVisible(bool))); | ||
| 44 | connect(start_recording, SIGNAL(clicked()), this, SLOT(StartRecording())); | 48 | connect(start_recording, SIGNAL(clicked()), this, SLOT(StartRecording())); |
| 45 | connect(stop_recording, SIGNAL(clicked()), this, SLOT(StopRecording())); | 49 | connect(stop_recording, SIGNAL(clicked()), this, SLOT(StopRecording())); |
| 46 | connect(abort_recording, SIGNAL(clicked()), this, SLOT(AbortRecording())); | 50 | connect(abort_recording, SIGNAL(clicked()), this, SLOT(AbortRecording())); |
| @@ -74,26 +78,31 @@ void GraphicsTracingWidget::StartRecording() { | |||
| 74 | std::array<u32, 4 * 16> default_attributes; | 78 | std::array<u32, 4 * 16> default_attributes; |
| 75 | for (unsigned i = 0; i < 16; ++i) { | 79 | for (unsigned i = 0; i < 16; ++i) { |
| 76 | for (unsigned comp = 0; comp < 3; ++comp) { | 80 | for (unsigned comp = 0; comp < 3; ++comp) { |
| 77 | default_attributes[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs_default_attributes[i][comp].ToFloat32()); | 81 | default_attributes[4 * i + comp] = |
| 82 | nihstro::to_float24(Pica::g_state.vs_default_attributes[i][comp].ToFloat32()); | ||
| 78 | } | 83 | } |
| 79 | } | 84 | } |
| 80 | 85 | ||
| 81 | std::array<u32, 4 * 96> vs_float_uniforms; | 86 | std::array<u32, 4 * 96> vs_float_uniforms; |
| 82 | for (unsigned i = 0; i < 96; ++i) | 87 | for (unsigned i = 0; i < 96; ++i) |
| 83 | for (unsigned comp = 0; comp < 3; ++comp) | 88 | for (unsigned comp = 0; comp < 3; ++comp) |
| 84 | vs_float_uniforms[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32()); | 89 | vs_float_uniforms[4 * i + comp] = |
| 90 | nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32()); | ||
| 85 | 91 | ||
| 86 | CiTrace::Recorder::InitialState state; | 92 | CiTrace::Recorder::InitialState state; |
| 87 | std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), std::back_inserter(state.gpu_registers)); | 93 | std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), |
| 88 | std::copy_n((u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), std::back_inserter(state.lcd_registers)); | 94 | std::back_inserter(state.gpu_registers)); |
| 89 | std::copy_n((u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), std::back_inserter(state.pica_registers)); | 95 | std::copy_n((u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), |
| 96 | std::back_inserter(state.lcd_registers)); | ||
| 97 | std::copy_n((u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), | ||
| 98 | std::back_inserter(state.pica_registers)); | ||
| 90 | boost::copy(default_attributes, std::back_inserter(state.default_attributes)); | 99 | boost::copy(default_attributes, std::back_inserter(state.default_attributes)); |
| 91 | boost::copy(shader_binary, std::back_inserter(state.vs_program_binary)); | 100 | boost::copy(shader_binary, std::back_inserter(state.vs_program_binary)); |
| 92 | boost::copy(swizzle_data, std::back_inserter(state.vs_swizzle_data)); | 101 | boost::copy(swizzle_data, std::back_inserter(state.vs_swizzle_data)); |
| 93 | boost::copy(vs_float_uniforms, std::back_inserter(state.vs_float_uniforms)); | 102 | boost::copy(vs_float_uniforms, std::back_inserter(state.vs_float_uniforms)); |
| 94 | //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary)); | 103 | // boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary)); |
| 95 | //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data)); | 104 | // boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data)); |
| 96 | //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms)); | 105 | // boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms)); |
| 97 | 106 | ||
| 98 | auto recorder = new CiTrace::Recorder(state); | 107 | auto recorder = new CiTrace::Recorder(state); |
| 99 | context->recorder = std::shared_ptr<CiTrace::Recorder>(recorder); | 108 | context->recorder = std::shared_ptr<CiTrace::Recorder>(recorder); |
| @@ -156,11 +165,12 @@ void GraphicsTracingWidget::OnEmulationStopping() { | |||
| 156 | if (!context) | 165 | if (!context) |
| 157 | return; | 166 | return; |
| 158 | 167 | ||
| 159 | |||
| 160 | if (context->recorder) { | 168 | if (context->recorder) { |
| 161 | auto reply = QMessageBox::question(this, tr("CiTracing still active"), | 169 | auto reply = |
| 162 | tr("A CiTrace is still being recorded. Do you want to save it? If not, all recorded data will be discarded."), | 170 | QMessageBox::question(this, tr("CiTracing still active"), |
| 163 | QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); | 171 | tr("A CiTrace is still being recorded. Do you want to save it? " |
| 172 | "If not, all recorded data will be discarded."), | ||
| 173 | QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); | ||
| 164 | 174 | ||
| 165 | if (reply == QMessageBox::Yes) { | 175 | if (reply == QMessageBox::Yes) { |
| 166 | StopRecording(); | 176 | StopRecording(); |
diff --git a/src/citra_qt/debugger/graphics_tracing.h b/src/citra_qt/debugger/graphics_tracing.h index 753dfa914..e04a3dac3 100644 --- a/src/citra_qt/debugger/graphics_tracing.h +++ b/src/citra_qt/debugger/graphics_tracing.h | |||
| @@ -12,7 +12,8 @@ class GraphicsTracingWidget : public BreakPointObserverDock { | |||
| 12 | Q_OBJECT | 12 | Q_OBJECT |
| 13 | 13 | ||
| 14 | public: | 14 | public: |
| 15 | GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr); | 15 | GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, |
| 16 | QWidget* parent = nullptr); | ||
| 16 | 17 | ||
| 17 | private slots: | 18 | private slots: |
| 18 | void StartRecording(); | 19 | void StartRecording(); |
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp index 391666d35..c49327f9c 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp | |||
| @@ -28,8 +28,8 @@ using nihstro::Instruction; | |||
| 28 | using nihstro::SourceRegister; | 28 | using nihstro::SourceRegister; |
| 29 | using nihstro::SwizzlePattern; | 29 | using nihstro::SwizzlePattern; |
| 30 | 30 | ||
| 31 | GraphicsVertexShaderModel::GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent): QAbstractTableModel(parent), par(parent) { | 31 | GraphicsVertexShaderModel::GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent) |
| 32 | 32 | : QAbstractTableModel(parent), par(parent) { | |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const { | 35 | int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const { |
| @@ -40,10 +40,10 @@ int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const { | |||
| 40 | return static_cast<int>(par->info.code.size()); | 40 | return static_cast<int>(par->info.code.size()); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const { | 43 | QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, |
| 44 | switch(role) { | 44 | int role) const { |
| 45 | case Qt::DisplayRole: | 45 | switch (role) { |
| 46 | { | 46 | case Qt::DisplayRole: { |
| 47 | if (section == 0) { | 47 | if (section == 0) { |
| 48 | return tr("Offset"); | 48 | return tr("Offset"); |
| 49 | } else if (section == 1) { | 49 | } else if (section == 1) { |
| @@ -69,8 +69,8 @@ static std::string SelectorToString(u32 selector) { | |||
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | // e.g. "-c92[a0.x].xyzw" | 71 | // e.g. "-c92[a0.x].xyzw" |
| 72 | static void print_input(std::ostringstream& output, const SourceRegister& input, | 72 | static void print_input(std::ostringstream& output, const SourceRegister& input, bool negate, |
| 73 | bool negate, const std::string& swizzle_mask, bool align = true, | 73 | const std::string& swizzle_mask, bool align = true, |
| 74 | const std::string& address_register_name = std::string()) { | 74 | const std::string& address_register_name = std::string()) { |
| 75 | if (align) | 75 | if (align) |
| 76 | output << std::setw(4) << std::right; | 76 | output << std::setw(4) << std::right; |
| @@ -83,20 +83,18 @@ static void print_input(std::ostringstream& output, const SourceRegister& input, | |||
| 83 | 83 | ||
| 84 | QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const { | 84 | QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const { |
| 85 | switch (role) { | 85 | switch (role) { |
| 86 | case Qt::DisplayRole: | 86 | case Qt::DisplayRole: { |
| 87 | { | ||
| 88 | switch (index.column()) { | 87 | switch (index.column()) { |
| 89 | case 0: | 88 | case 0: |
| 90 | if (par->info.HasLabel(index.row())) | 89 | if (par->info.HasLabel(index.row())) |
| 91 | return QString::fromStdString(par->info.GetLabel(index.row())); | 90 | return QString::fromStdString(par->info.GetLabel(index.row())); |
| 92 | 91 | ||
| 93 | return QString("%1").arg(4*index.row(), 4, 16, QLatin1Char('0')); | 92 | return QString("%1").arg(4 * index.row(), 4, 16, QLatin1Char('0')); |
| 94 | 93 | ||
| 95 | case 1: | 94 | case 1: |
| 96 | return QString("%1").arg(par->info.code[index.row()].hex, 8, 16, QLatin1Char('0')); | 95 | return QString("%1").arg(par->info.code[index.row()].hex, 8, 16, QLatin1Char('0')); |
| 97 | 96 | ||
| 98 | case 2: | 97 | case 2: { |
| 99 | { | ||
| 100 | std::ostringstream output; | 98 | std::ostringstream output; |
| 101 | output.flags(std::ios::uppercase); | 99 | output.flags(std::ios::uppercase); |
| 102 | 100 | ||
| @@ -117,8 +115,9 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 117 | const Instruction instr = par->info.code[index.row()]; | 115 | const Instruction instr = par->info.code[index.row()]; |
| 118 | const OpCode opcode = instr.opcode; | 116 | const OpCode opcode = instr.opcode; |
| 119 | const OpCode::Info opcode_info = opcode.GetInfo(); | 117 | const OpCode::Info opcode_info = opcode.GetInfo(); |
| 120 | const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd ? | 118 | const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd |
| 121 | instr.mad.operand_desc_id.Value() : instr.common.operand_desc_id.Value(); | 119 | ? instr.mad.operand_desc_id.Value() |
| 120 | : instr.common.operand_desc_id.Value(); | ||
| 122 | const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern; | 121 | const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern; |
| 123 | 122 | ||
| 124 | // longest known instruction name: "setemit " | 123 | // longest known instruction name: "setemit " |
| @@ -136,15 +135,14 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 136 | break; | 135 | break; |
| 137 | 136 | ||
| 138 | case OpCode::Type::Arithmetic: | 137 | case OpCode::Type::Arithmetic: |
| 139 | case OpCode::Type::MultiplyAdd: | 138 | case OpCode::Type::MultiplyAdd: { |
| 140 | { | ||
| 141 | // Use custom code for special instructions | 139 | // Use custom code for special instructions |
| 142 | switch (opcode.EffectiveOpCode()) { | 140 | switch (opcode.EffectiveOpCode()) { |
| 143 | case OpCode::Id::CMP: | 141 | case OpCode::Id::CMP: { |
| 144 | { | ||
| 145 | AlignToColumn(kOpcodeColumnWidth); | 142 | AlignToColumn(kOpcodeColumnWidth); |
| 146 | 143 | ||
| 147 | // NOTE: CMP always writes both cc components, so we do not consider the dest mask here. | 144 | // NOTE: CMP always writes both cc components, so we do not consider the dest |
| 145 | // mask here. | ||
| 148 | output << " cc.xy"; | 146 | output << " cc.xy"; |
| 149 | AlignToColumn(kOutputColumnWidth); | 147 | AlignToColumn(kOutputColumnWidth); |
| 150 | 148 | ||
| @@ -152,22 +150,29 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 152 | SourceRegister src2 = instr.common.GetSrc2(false); | 150 | SourceRegister src2 = instr.common.GetSrc2(false); |
| 153 | 151 | ||
| 154 | output << ' '; | 152 | output << ' '; |
| 155 | print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(0,1), false, instr.common.AddressRegisterName()); | 153 | print_input(output, src1, swizzle.negate_src1, |
| 156 | output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.x) << ' '; | 154 | swizzle.SelectorToString(false).substr(0, 1), false, |
| 157 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(0,1), false); | 155 | instr.common.AddressRegisterName()); |
| 156 | output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.x) | ||
| 157 | << ' '; | ||
| 158 | print_input(output, src2, swizzle.negate_src2, | ||
| 159 | swizzle.SelectorToString(true).substr(0, 1), false); | ||
| 158 | 160 | ||
| 159 | output << ", "; | 161 | output << ", "; |
| 160 | 162 | ||
| 161 | print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(1,1), false, instr.common.AddressRegisterName()); | 163 | print_input(output, src1, swizzle.negate_src1, |
| 162 | output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.y) << ' '; | 164 | swizzle.SelectorToString(false).substr(1, 1), false, |
| 163 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true).substr(1,1), false); | 165 | instr.common.AddressRegisterName()); |
| 166 | output << ' ' << instr.common.compare_op.ToString(instr.common.compare_op.y) | ||
| 167 | << ' '; | ||
| 168 | print_input(output, src2, swizzle.negate_src2, | ||
| 169 | swizzle.SelectorToString(true).substr(1, 1), false); | ||
| 164 | 170 | ||
| 165 | break; | 171 | break; |
| 166 | } | 172 | } |
| 167 | 173 | ||
| 168 | case OpCode::Id::MAD: | 174 | case OpCode::Id::MAD: |
| 169 | case OpCode::Id::MADI: | 175 | case OpCode::Id::MADI: { |
| 170 | { | ||
| 171 | AlignToColumn(kOpcodeColumnWidth); | 176 | AlignToColumn(kOpcodeColumnWidth); |
| 172 | 177 | ||
| 173 | bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); | 178 | bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); |
| @@ -175,34 +180,42 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 175 | SourceRegister src2 = instr.mad.GetSrc2(src_is_inverted); | 180 | SourceRegister src2 = instr.mad.GetSrc2(src_is_inverted); |
| 176 | SourceRegister src3 = instr.mad.GetSrc3(src_is_inverted); | 181 | SourceRegister src3 = instr.mad.GetSrc3(src_is_inverted); |
| 177 | 182 | ||
| 178 | output << std::setw(3) << std::right << instr.mad.dest.Value().GetName() << '.' << swizzle.DestMaskToString(); | 183 | output << std::setw(3) << std::right << instr.mad.dest.Value().GetName() << '.' |
| 184 | << swizzle.DestMaskToString(); | ||
| 179 | AlignToColumn(kOutputColumnWidth); | 185 | AlignToColumn(kOutputColumnWidth); |
| 180 | print_input(output, src1, swizzle.negate_src1, SelectorToString(swizzle.src1_selector)); | 186 | print_input(output, src1, swizzle.negate_src1, |
| 187 | SelectorToString(swizzle.src1_selector)); | ||
| 181 | AlignToColumn(kInputOperandColumnWidth); | 188 | AlignToColumn(kInputOperandColumnWidth); |
| 182 | if (src_is_inverted) { | 189 | if (src_is_inverted) { |
| 183 | print_input(output, src2, swizzle.negate_src2, SelectorToString(swizzle.src2_selector)); | 190 | print_input(output, src2, swizzle.negate_src2, |
| 191 | SelectorToString(swizzle.src2_selector)); | ||
| 184 | } else { | 192 | } else { |
| 185 | print_input(output, src2, swizzle.negate_src2, SelectorToString(swizzle.src2_selector), true, instr.mad.AddressRegisterName()); | 193 | print_input(output, src2, swizzle.negate_src2, |
| 194 | SelectorToString(swizzle.src2_selector), true, | ||
| 195 | instr.mad.AddressRegisterName()); | ||
| 186 | } | 196 | } |
| 187 | AlignToColumn(kInputOperandColumnWidth); | 197 | AlignToColumn(kInputOperandColumnWidth); |
| 188 | if (src_is_inverted) { | 198 | if (src_is_inverted) { |
| 189 | print_input(output, src3, swizzle.negate_src3, SelectorToString(swizzle.src3_selector), true, instr.mad.AddressRegisterName()); | 199 | print_input(output, src3, swizzle.negate_src3, |
| 200 | SelectorToString(swizzle.src3_selector), true, | ||
| 201 | instr.mad.AddressRegisterName()); | ||
| 190 | } else { | 202 | } else { |
| 191 | print_input(output, src3, swizzle.negate_src3, SelectorToString(swizzle.src3_selector)); | 203 | print_input(output, src3, swizzle.negate_src3, |
| 204 | SelectorToString(swizzle.src3_selector)); | ||
| 192 | } | 205 | } |
| 193 | AlignToColumn(kInputOperandColumnWidth); | 206 | AlignToColumn(kInputOperandColumnWidth); |
| 194 | break; | 207 | break; |
| 195 | } | 208 | } |
| 196 | 209 | ||
| 197 | default: | 210 | default: { |
| 198 | { | ||
| 199 | AlignToColumn(kOpcodeColumnWidth); | 211 | AlignToColumn(kOpcodeColumnWidth); |
| 200 | 212 | ||
| 201 | bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); | 213 | bool src_is_inverted = 0 != (opcode_info.subtype & OpCode::Info::SrcInversed); |
| 202 | 214 | ||
| 203 | if (opcode_info.subtype & OpCode::Info::Dest) { | 215 | if (opcode_info.subtype & OpCode::Info::Dest) { |
| 204 | // e.g. "r12.xy__" | 216 | // e.g. "r12.xy__" |
| 205 | output << std::setw(3) << std::right << instr.common.dest.Value().GetName() << '.' << swizzle.DestMaskToString(); | 217 | output << std::setw(3) << std::right << instr.common.dest.Value().GetName() |
| 218 | << '.' << swizzle.DestMaskToString(); | ||
| 206 | } else if (opcode_info.subtype == OpCode::Info::MOVA) { | 219 | } else if (opcode_info.subtype == OpCode::Info::MOVA) { |
| 207 | output << " a0." << swizzle.DestMaskToString(); | 220 | output << " a0." << swizzle.DestMaskToString(); |
| 208 | } | 221 | } |
| @@ -210,14 +223,18 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 210 | 223 | ||
| 211 | if (opcode_info.subtype & OpCode::Info::Src1) { | 224 | if (opcode_info.subtype & OpCode::Info::Src1) { |
| 212 | SourceRegister src1 = instr.common.GetSrc1(src_is_inverted); | 225 | SourceRegister src1 = instr.common.GetSrc1(src_is_inverted); |
| 213 | print_input(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false), true, instr.common.AddressRegisterName()); | 226 | print_input(output, src1, swizzle.negate_src1, |
| 227 | swizzle.SelectorToString(false), true, | ||
| 228 | instr.common.AddressRegisterName()); | ||
| 214 | AlignToColumn(kInputOperandColumnWidth); | 229 | AlignToColumn(kInputOperandColumnWidth); |
| 215 | } | 230 | } |
| 216 | 231 | ||
| 217 | // TODO: In some cases, the Address Register is used as an index for SRC2 instead of SRC1 | 232 | // TODO: In some cases, the Address Register is used as an index for SRC2 |
| 233 | // instead of SRC1 | ||
| 218 | if (opcode_info.subtype & OpCode::Info::Src2) { | 234 | if (opcode_info.subtype & OpCode::Info::Src2) { |
| 219 | SourceRegister src2 = instr.common.GetSrc2(src_is_inverted); | 235 | SourceRegister src2 = instr.common.GetSrc2(src_is_inverted); |
| 220 | print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(true)); | 236 | print_input(output, src2, swizzle.negate_src2, |
| 237 | swizzle.SelectorToString(true)); | ||
| 221 | AlignToColumn(kInputOperandColumnWidth); | 238 | AlignToColumn(kInputOperandColumnWidth); |
| 222 | } | 239 | } |
| 223 | break; | 240 | break; |
| @@ -228,8 +245,7 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 228 | } | 245 | } |
| 229 | 246 | ||
| 230 | case OpCode::Type::Conditional: | 247 | case OpCode::Type::Conditional: |
| 231 | case OpCode::Type::UniformFlowControl: | 248 | case OpCode::Type::UniformFlowControl: { |
| 232 | { | ||
| 233 | output << ' '; | 249 | output << ' '; |
| 234 | 250 | ||
| 235 | switch (opcode.EffectiveOpCode()) { | 251 | switch (opcode.EffectiveOpCode()) { |
| @@ -242,7 +258,8 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 242 | output << '('; | 258 | output << '('; |
| 243 | 259 | ||
| 244 | if (instr.flow_control.op != instr.flow_control.JustY) { | 260 | if (instr.flow_control.op != instr.flow_control.JustY) { |
| 245 | if (instr.flow_control.refx) output << '!'; | 261 | if (instr.flow_control.refx) |
| 262 | output << '!'; | ||
| 246 | output << "cc.x"; | 263 | output << "cc.x"; |
| 247 | } | 264 | } |
| 248 | 265 | ||
| @@ -253,7 +270,8 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 253 | } | 270 | } |
| 254 | 271 | ||
| 255 | if (instr.flow_control.op != instr.flow_control.JustX) { | 272 | if (instr.flow_control.op != instr.flow_control.JustX) { |
| 256 | if (instr.flow_control.refy) output << '!'; | 273 | if (instr.flow_control.refy) |
| 274 | output << '!'; | ||
| 257 | output << "cc.y"; | 275 | output << "cc.y"; |
| 258 | } | 276 | } |
| 259 | 277 | ||
| @@ -266,17 +284,23 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 266 | u32 target_addr_else = instr.flow_control.dest_offset; | 284 | u32 target_addr_else = instr.flow_control.dest_offset; |
| 267 | 285 | ||
| 268 | if (opcode_info.subtype & OpCode::Info::HasAlternative) { | 286 | if (opcode_info.subtype & OpCode::Info::HasAlternative) { |
| 269 | output << "else jump to 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex << (4 * instr.flow_control.dest_offset); | 287 | output << "else jump to 0x" << std::setw(4) << std::right |
| 288 | << std::setfill('0') << std::hex | ||
| 289 | << (4 * instr.flow_control.dest_offset); | ||
| 270 | } else if (opcode_info.subtype & OpCode::Info::HasExplicitDest) { | 290 | } else if (opcode_info.subtype & OpCode::Info::HasExplicitDest) { |
| 271 | output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex << (4 * instr.flow_control.dest_offset); | 291 | output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') |
| 292 | << std::hex << (4 * instr.flow_control.dest_offset); | ||
| 272 | } else { | 293 | } else { |
| 273 | // TODO: Handle other cases | 294 | // TODO: Handle other cases |
| 274 | output << "(unknown destination)"; | 295 | output << "(unknown destination)"; |
| 275 | } | 296 | } |
| 276 | 297 | ||
| 277 | if (opcode_info.subtype & OpCode::Info::HasFinishPoint) { | 298 | if (opcode_info.subtype & OpCode::Info::HasFinishPoint) { |
| 278 | output << " (return on 0x" << std::setw(4) << std::right << std::setfill('0') << std::hex | 299 | output << " (return on 0x" << std::setw(4) << std::right |
| 279 | << (4 * instr.flow_control.dest_offset + 4 * instr.flow_control.num_instructions) << ')'; | 300 | << std::setfill('0') << std::hex |
| 301 | << (4 * instr.flow_control.dest_offset + | ||
| 302 | 4 * instr.flow_control.num_instructions) | ||
| 303 | << ')'; | ||
| 280 | } | 304 | } |
| 281 | 305 | ||
| 282 | break; | 306 | break; |
| @@ -300,8 +324,7 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 300 | case Qt::FontRole: | 324 | case Qt::FontRole: |
| 301 | return GetMonospaceFont(); | 325 | return GetMonospaceFont(); |
| 302 | 326 | ||
| 303 | case Qt::BackgroundRole: | 327 | case Qt::BackgroundRole: { |
| 304 | { | ||
| 305 | // Highlight current instruction | 328 | // Highlight current instruction |
| 306 | int current_record_index = par->cycle_index->value(); | 329 | int current_record_index = par->cycle_index->value(); |
| 307 | if (current_record_index < static_cast<int>(par->debug_data.records.size())) { | 330 | if (current_record_index < static_cast<int>(par->debug_data.records.size())) { |
| @@ -319,10 +342,8 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 319 | return QBrush(QColor(192, 192, 192)); | 342 | return QBrush(QColor(192, 192, 192)); |
| 320 | } | 343 | } |
| 321 | 344 | ||
| 322 | |||
| 323 | // TODO: Draw arrows for each "reachable" instruction to visualize control flow | 345 | // TODO: Draw arrows for each "reachable" instruction to visualize control flow |
| 324 | 346 | ||
| 325 | |||
| 326 | default: | 347 | default: |
| 327 | break; | 348 | break; |
| 328 | } | 349 | } |
| @@ -331,23 +352,24 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 331 | } | 352 | } |
| 332 | 353 | ||
| 333 | void GraphicsVertexShaderWidget::DumpShader() { | 354 | void GraphicsVertexShaderWidget::DumpShader() { |
| 334 | QString filename = QFileDialog::getSaveFileName(this, tr("Save Shader Dump"), "shader_dump.shbin", | 355 | QString filename = QFileDialog::getSaveFileName( |
| 335 | tr("Shader Binary (*.shbin)")); | 356 | this, tr("Save Shader Dump"), "shader_dump.shbin", tr("Shader Binary (*.shbin)")); |
| 336 | 357 | ||
| 337 | if (filename.isEmpty()) { | 358 | if (filename.isEmpty()) { |
| 338 | // If the user canceled the dialog, don't dump anything. | 359 | // If the user canceled the dialog, don't dump anything. |
| 339 | return; | 360 | return; |
| 340 | } | 361 | } |
| 341 | 362 | ||
| 342 | auto& setup = Pica::g_state.vs; | 363 | auto& setup = Pica::g_state.vs; |
| 343 | auto& config = Pica::g_state.regs.vs; | 364 | auto& config = Pica::g_state.regs.vs; |
| 344 | 365 | ||
| 345 | Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup, Pica::g_state.regs.vs_output_attributes); | 366 | Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup, |
| 367 | Pica::g_state.regs.vs_output_attributes); | ||
| 346 | } | 368 | } |
| 347 | 369 | ||
| 348 | GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::DebugContext > debug_context, | 370 | GraphicsVertexShaderWidget::GraphicsVertexShaderWidget( |
| 349 | QWidget* parent) | 371 | std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent) |
| 350 | : BreakPointObserverDock(debug_context, "Pica Vertex Shader", parent) { | 372 | : BreakPointObserverDock(debug_context, "Pica Vertex Shader", parent) { |
| 351 | setObjectName("PicaVertexShader"); | 373 | setObjectName("PicaVertexShader"); |
| 352 | 374 | ||
| 353 | // Clear input vertex data so that it contains valid float values in case a debug shader | 375 | // Clear input vertex data so that it contains valid float values in case a debug shader |
| @@ -365,7 +387,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De | |||
| 365 | input_data[i]->setValidator(new QDoubleValidator(input_data[i])); | 387 | input_data[i]->setValidator(new QDoubleValidator(input_data[i])); |
| 366 | } | 388 | } |
| 367 | 389 | ||
| 368 | breakpoint_warning = new QLabel(tr("(data only available at vertex shader invocation breakpoints)")); | 390 | breakpoint_warning = |
| 391 | new QLabel(tr("(data only available at vertex shader invocation breakpoints)")); | ||
| 369 | 392 | ||
| 370 | // TODO: Add some button for jumping to the shader entry point | 393 | // TODO: Add some button for jumping to the shader entry point |
| 371 | 394 | ||
| @@ -442,7 +465,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De | |||
| 442 | 465 | ||
| 443 | // Set a minimum height so that the size of this label doesn't cause the rest of the bottom | 466 | // Set a minimum height so that the size of this label doesn't cause the rest of the bottom |
| 444 | // part of the UI to keep jumping up and down when cycling through instructions. | 467 | // part of the UI to keep jumping up and down when cycling through instructions. |
| 445 | instruction_description->setMinimumHeight(instruction_description->fontMetrics().lineSpacing() * 6); | 468 | instruction_description->setMinimumHeight(instruction_description->fontMetrics().lineSpacing() * |
| 469 | 6); | ||
| 446 | instruction_description->setAlignment(Qt::AlignLeft | Qt::AlignTop); | 470 | instruction_description->setAlignment(Qt::AlignLeft | Qt::AlignTop); |
| 447 | main_layout->addWidget(instruction_description); | 471 | main_layout->addWidget(instruction_description); |
| 448 | 472 | ||
| @@ -471,7 +495,8 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d | |||
| 471 | memcpy(&input_vertex, vertex_data, sizeof(input_vertex)); | 495 | memcpy(&input_vertex, vertex_data, sizeof(input_vertex)); |
| 472 | for (unsigned attr = 0; attr < 16; ++attr) { | 496 | for (unsigned attr = 0; attr < 16; ++attr) { |
| 473 | for (unsigned comp = 0; comp < 4; ++comp) { | 497 | for (unsigned comp = 0; comp < 4; ++comp) { |
| 474 | input_data[4 * attr + comp]->setText(QString("%1").arg(input_vertex.attr[attr][comp].ToFloat32())); | 498 | input_data[4 * attr + comp]->setText( |
| 499 | QString("%1").arg(input_vertex.attr[attr][comp].ToFloat32())); | ||
| 475 | } | 500 | } |
| 476 | } | 501 | } |
| 477 | breakpoint_warning->hide(); | 502 | breakpoint_warning->hide(); |
| @@ -498,10 +523,11 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d | |||
| 498 | info.swizzle_info.push_back({pattern}); | 523 | info.swizzle_info.push_back({pattern}); |
| 499 | 524 | ||
| 500 | u32 entry_point = Pica::g_state.regs.vs.main_offset; | 525 | u32 entry_point = Pica::g_state.regs.vs.main_offset; |
| 501 | info.labels.insert({ entry_point, "main" }); | 526 | info.labels.insert({entry_point, "main"}); |
| 502 | 527 | ||
| 503 | // Generate debug information | 528 | // Generate debug information |
| 504 | debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup); | 529 | debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config, |
| 530 | shader_setup); | ||
| 505 | 531 | ||
| 506 | // Reload widget state | 532 | // Reload widget state |
| 507 | for (int attr = 0; attr < num_attributes; ++attr) { | 533 | for (int attr = 0; attr < num_attributes; ++attr) { |
| @@ -537,29 +563,60 @@ void GraphicsVertexShaderWidget::OnCycleIndexChanged(int index) { | |||
| 537 | 563 | ||
| 538 | auto& record = debug_data.records[index]; | 564 | auto& record = debug_data.records[index]; |
| 539 | if (record.mask & Pica::Shader::DebugDataRecord::SRC1) | 565 | if (record.mask & Pica::Shader::DebugDataRecord::SRC1) |
| 540 | text += tr("SRC1: %1, %2, %3, %4\n").arg(record.src1.x.ToFloat32()).arg(record.src1.y.ToFloat32()).arg(record.src1.z.ToFloat32()).arg(record.src1.w.ToFloat32()); | 566 | text += tr("SRC1: %1, %2, %3, %4\n") |
| 567 | .arg(record.src1.x.ToFloat32()) | ||
| 568 | .arg(record.src1.y.ToFloat32()) | ||
| 569 | .arg(record.src1.z.ToFloat32()) | ||
| 570 | .arg(record.src1.w.ToFloat32()); | ||
| 541 | if (record.mask & Pica::Shader::DebugDataRecord::SRC2) | 571 | if (record.mask & Pica::Shader::DebugDataRecord::SRC2) |
| 542 | text += tr("SRC2: %1, %2, %3, %4\n").arg(record.src2.x.ToFloat32()).arg(record.src2.y.ToFloat32()).arg(record.src2.z.ToFloat32()).arg(record.src2.w.ToFloat32()); | 572 | text += tr("SRC2: %1, %2, %3, %4\n") |
| 573 | .arg(record.src2.x.ToFloat32()) | ||
| 574 | .arg(record.src2.y.ToFloat32()) | ||
| 575 | .arg(record.src2.z.ToFloat32()) | ||
| 576 | .arg(record.src2.w.ToFloat32()); | ||
| 543 | if (record.mask & Pica::Shader::DebugDataRecord::SRC3) | 577 | if (record.mask & Pica::Shader::DebugDataRecord::SRC3) |
| 544 | text += tr("SRC3: %1, %2, %3, %4\n").arg(record.src3.x.ToFloat32()).arg(record.src3.y.ToFloat32()).arg(record.src3.z.ToFloat32()).arg(record.src3.w.ToFloat32()); | 578 | text += tr("SRC3: %1, %2, %3, %4\n") |
| 579 | .arg(record.src3.x.ToFloat32()) | ||
| 580 | .arg(record.src3.y.ToFloat32()) | ||
| 581 | .arg(record.src3.z.ToFloat32()) | ||
| 582 | .arg(record.src3.w.ToFloat32()); | ||
| 545 | if (record.mask & Pica::Shader::DebugDataRecord::DEST_IN) | 583 | if (record.mask & Pica::Shader::DebugDataRecord::DEST_IN) |
| 546 | text += tr("DEST_IN: %1, %2, %3, %4\n").arg(record.dest_in.x.ToFloat32()).arg(record.dest_in.y.ToFloat32()).arg(record.dest_in.z.ToFloat32()).arg(record.dest_in.w.ToFloat32()); | 584 | text += tr("DEST_IN: %1, %2, %3, %4\n") |
| 585 | .arg(record.dest_in.x.ToFloat32()) | ||
| 586 | .arg(record.dest_in.y.ToFloat32()) | ||
| 587 | .arg(record.dest_in.z.ToFloat32()) | ||
| 588 | .arg(record.dest_in.w.ToFloat32()); | ||
| 547 | if (record.mask & Pica::Shader::DebugDataRecord::DEST_OUT) | 589 | if (record.mask & Pica::Shader::DebugDataRecord::DEST_OUT) |
| 548 | text += tr("DEST_OUT: %1, %2, %3, %4\n").arg(record.dest_out.x.ToFloat32()).arg(record.dest_out.y.ToFloat32()).arg(record.dest_out.z.ToFloat32()).arg(record.dest_out.w.ToFloat32()); | 590 | text += tr("DEST_OUT: %1, %2, %3, %4\n") |
| 591 | .arg(record.dest_out.x.ToFloat32()) | ||
| 592 | .arg(record.dest_out.y.ToFloat32()) | ||
| 593 | .arg(record.dest_out.z.ToFloat32()) | ||
| 594 | .arg(record.dest_out.w.ToFloat32()); | ||
| 549 | 595 | ||
| 550 | if (record.mask & Pica::Shader::DebugDataRecord::ADDR_REG_OUT) | 596 | if (record.mask & Pica::Shader::DebugDataRecord::ADDR_REG_OUT) |
| 551 | text += tr("Addres Registers: %1, %2\n").arg(record.address_registers[0]).arg(record.address_registers[1]); | 597 | text += tr("Addres Registers: %1, %2\n") |
| 598 | .arg(record.address_registers[0]) | ||
| 599 | .arg(record.address_registers[1]); | ||
| 552 | if (record.mask & Pica::Shader::DebugDataRecord::CMP_RESULT) | 600 | if (record.mask & Pica::Shader::DebugDataRecord::CMP_RESULT) |
| 553 | text += tr("Compare Result: %1, %2\n").arg(record.conditional_code[0] ? "true" : "false").arg(record.conditional_code[1] ? "true" : "false"); | 601 | text += tr("Compare Result: %1, %2\n") |
| 602 | .arg(record.conditional_code[0] ? "true" : "false") | ||
| 603 | .arg(record.conditional_code[1] ? "true" : "false"); | ||
| 554 | 604 | ||
| 555 | if (record.mask & Pica::Shader::DebugDataRecord::COND_BOOL_IN) | 605 | if (record.mask & Pica::Shader::DebugDataRecord::COND_BOOL_IN) |
| 556 | text += tr("Static Condition: %1\n").arg(record.cond_bool ? "true" : "false"); | 606 | text += tr("Static Condition: %1\n").arg(record.cond_bool ? "true" : "false"); |
| 557 | if (record.mask & Pica::Shader::DebugDataRecord::COND_CMP_IN) | 607 | if (record.mask & Pica::Shader::DebugDataRecord::COND_CMP_IN) |
| 558 | text += tr("Dynamic Conditions: %1, %2\n").arg(record.cond_cmp[0] ? "true" : "false").arg(record.cond_cmp[1] ? "true" : "false"); | 608 | text += tr("Dynamic Conditions: %1, %2\n") |
| 609 | .arg(record.cond_cmp[0] ? "true" : "false") | ||
| 610 | .arg(record.cond_cmp[1] ? "true" : "false"); | ||
| 559 | if (record.mask & Pica::Shader::DebugDataRecord::LOOP_INT_IN) | 611 | if (record.mask & Pica::Shader::DebugDataRecord::LOOP_INT_IN) |
| 560 | text += tr("Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4\n").arg(record.loop_int.x).arg(record.loop_int.y).arg(record.loop_int.z).arg(record.loop_int.w); | 612 | text += tr("Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4\n") |
| 561 | 613 | .arg(record.loop_int.x) | |
| 562 | text += tr("Instruction offset: 0x%1").arg(4 * record.instruction_offset, 4, 16, QLatin1Char('0')); | 614 | .arg(record.loop_int.y) |
| 615 | .arg(record.loop_int.z) | ||
| 616 | .arg(record.loop_int.w); | ||
| 617 | |||
| 618 | text += | ||
| 619 | tr("Instruction offset: 0x%1").arg(4 * record.instruction_offset, 4, 16, QLatin1Char('0')); | ||
| 563 | if (record.mask & Pica::Shader::DebugDataRecord::NEXT_INSTR) { | 620 | if (record.mask & Pica::Shader::DebugDataRecord::NEXT_INSTR) { |
| 564 | text += tr(" -> 0x%2").arg(4 * record.next_instruction, 4, 16, QLatin1Char('0')); | 621 | text += tr(" -> 0x%2").arg(4 * record.next_instruction, 4, 16, QLatin1Char('0')); |
| 565 | } else { | 622 | } else { |
| @@ -570,6 +627,7 @@ void GraphicsVertexShaderWidget::OnCycleIndexChanged(int index) { | |||
| 570 | 627 | ||
| 571 | // Emit model update notification and scroll to current instruction | 628 | // Emit model update notification and scroll to current instruction |
| 572 | QModelIndex instr_index = model->index(record.instruction_offset, 0); | 629 | QModelIndex instr_index = model->index(record.instruction_offset, 0); |
| 573 | emit model->dataChanged(instr_index, model->index(record.instruction_offset, model->columnCount())); | 630 | emit model->dataChanged(instr_index, |
| 631 | model->index(record.instruction_offset, model->columnCount())); | ||
| 574 | binary_list->scrollTo(instr_index, QAbstractItemView::EnsureVisible); | 632 | binary_list->scrollTo(instr_index, QAbstractItemView::EnsureVisible); |
| 575 | } | 633 | } |
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.h b/src/citra_qt/debugger/graphics_vertex_shader.h index 7f06f496a..96692d82c 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.h +++ b/src/citra_qt/debugger/graphics_vertex_shader.h | |||
| @@ -26,7 +26,8 @@ public: | |||
| 26 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; | 26 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; |
| 27 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; | 27 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
| 28 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | 28 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 29 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; | 29 | QVariant headerData(int section, Qt::Orientation orientation, |
| 30 | int role = Qt::DisplayRole) const override; | ||
| 30 | 31 | ||
| 31 | private: | 32 | private: |
| 32 | GraphicsVertexShaderWidget* par; | 33 | GraphicsVertexShaderWidget* par; |
| @@ -56,7 +57,9 @@ private slots: | |||
| 56 | /** | 57 | /** |
| 57 | * Reload widget based on the current PICA200 state | 58 | * Reload widget based on the current PICA200 state |
| 58 | * @param replace_vertex_data If true, invalidate all current vertex data | 59 | * @param replace_vertex_data If true, invalidate all current vertex data |
| 59 | * @param vertex_data New vertex data to use, as passed to OnBreakPointHit. May be nullptr to specify that no valid vertex data can be retrieved currently. Only used if replace_vertex_data is true. | 60 | * @param vertex_data New vertex data to use, as passed to OnBreakPointHit. May be nullptr to |
| 61 | * specify that no valid vertex data can be retrieved currently. Only used if | ||
| 62 | * replace_vertex_data is true. | ||
| 60 | */ | 63 | */ |
| 61 | void Reload(bool replace_vertex_data = false, void* vertex_data = nullptr); | 64 | void Reload(bool replace_vertex_data = false, void* vertex_data = nullptr); |
| 62 | 65 | ||
| @@ -66,9 +69,12 @@ private: | |||
| 66 | GraphicsVertexShaderModel* model; | 69 | GraphicsVertexShaderModel* model; |
| 67 | 70 | ||
| 68 | /// TODO: Move these into a single struct | 71 | /// TODO: Move these into a single struct |
| 69 | std::array<QLineEdit*, 4*16> input_data; // A text box for each of the 4 components of up to 16 vertex attributes | 72 | std::array<QLineEdit*, 4 * 16> |
| 70 | std::array<QWidget*, 16> input_data_container; // QWidget containing the QLayout containing each vertex attribute | 73 | input_data; // A text box for each of the 4 components of up to 16 vertex attributes |
| 71 | std::array<QLabel*, 16> input_data_mapping; // A QLabel denoting the shader input attribute which the vertex attribute maps to | 74 | std::array<QWidget*, 16> |
| 75 | input_data_container; // QWidget containing the QLayout containing each vertex attribute | ||
| 76 | std::array<QLabel*, 16> input_data_mapping; // A QLabel denoting the shader input attribute | ||
| 77 | // which the vertex attribute maps to | ||
| 72 | 78 | ||
| 73 | // Text to be shown when input vertex data is not retrievable | 79 | // Text to be shown when input vertex data is not retrievable |
| 74 | QLabel* breakpoint_warning; | 80 | QLabel* breakpoint_warning; |
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp index 17898f54b..97a377513 100644 --- a/src/citra_qt/debugger/profiler.cpp +++ b/src/citra_qt/debugger/profiler.cpp | |||
| @@ -22,57 +22,58 @@ | |||
| 22 | 22 | ||
| 23 | using namespace Common::Profiling; | 23 | using namespace Common::Profiling; |
| 24 | 24 | ||
| 25 | static QVariant GetDataForColumn(int col, const AggregatedDuration& duration) | 25 | static QVariant GetDataForColumn(int col, const AggregatedDuration& duration) { |
| 26 | { | ||
| 27 | static auto duration_to_float = [](Duration dur) -> float { | 26 | static auto duration_to_float = [](Duration dur) -> float { |
| 28 | using FloatMs = std::chrono::duration<float, std::chrono::milliseconds::period>; | 27 | using FloatMs = std::chrono::duration<float, std::chrono::milliseconds::period>; |
| 29 | return std::chrono::duration_cast<FloatMs>(dur).count(); | 28 | return std::chrono::duration_cast<FloatMs>(dur).count(); |
| 30 | }; | 29 | }; |
| 31 | 30 | ||
| 32 | switch (col) { | 31 | switch (col) { |
| 33 | case 1: return duration_to_float(duration.avg); | 32 | case 1: |
| 34 | case 2: return duration_to_float(duration.min); | 33 | return duration_to_float(duration.avg); |
| 35 | case 3: return duration_to_float(duration.max); | 34 | case 2: |
| 36 | default: return QVariant(); | 35 | return duration_to_float(duration.min); |
| 36 | case 3: | ||
| 37 | return duration_to_float(duration.max); | ||
| 38 | default: | ||
| 39 | return QVariant(); | ||
| 37 | } | 40 | } |
| 38 | } | 41 | } |
| 39 | 42 | ||
| 40 | ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent) | 43 | ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent) { |
| 41 | { | ||
| 42 | updateProfilingInfo(); | 44 | updateProfilingInfo(); |
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const | 47 | QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const { |
| 46 | { | ||
| 47 | if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { | 48 | if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { |
| 48 | switch (section) { | 49 | switch (section) { |
| 49 | case 0: return tr("Category"); | 50 | case 0: |
| 50 | case 1: return tr("Avg"); | 51 | return tr("Category"); |
| 51 | case 2: return tr("Min"); | 52 | case 1: |
| 52 | case 3: return tr("Max"); | 53 | return tr("Avg"); |
| 54 | case 2: | ||
| 55 | return tr("Min"); | ||
| 56 | case 3: | ||
| 57 | return tr("Max"); | ||
| 53 | } | 58 | } |
| 54 | } | 59 | } |
| 55 | 60 | ||
| 56 | return QVariant(); | 61 | return QVariant(); |
| 57 | } | 62 | } |
| 58 | 63 | ||
| 59 | QModelIndex ProfilerModel::index(int row, int column, const QModelIndex& parent) const | 64 | QModelIndex ProfilerModel::index(int row, int column, const QModelIndex& parent) const { |
| 60 | { | ||
| 61 | return createIndex(row, column); | 65 | return createIndex(row, column); |
| 62 | } | 66 | } |
| 63 | 67 | ||
| 64 | QModelIndex ProfilerModel::parent(const QModelIndex& child) const | 68 | QModelIndex ProfilerModel::parent(const QModelIndex& child) const { |
| 65 | { | ||
| 66 | return QModelIndex(); | 69 | return QModelIndex(); |
| 67 | } | 70 | } |
| 68 | 71 | ||
| 69 | int ProfilerModel::columnCount(const QModelIndex& parent) const | 72 | int ProfilerModel::columnCount(const QModelIndex& parent) const { |
| 70 | { | ||
| 71 | return 4; | 73 | return 4; |
| 72 | } | 74 | } |
| 73 | 75 | ||
| 74 | int ProfilerModel::rowCount(const QModelIndex& parent) const | 76 | int ProfilerModel::rowCount(const QModelIndex& parent) const { |
| 75 | { | ||
| 76 | if (parent.isValid()) { | 77 | if (parent.isValid()) { |
| 77 | return 0; | 78 | return 0; |
| 78 | } else { | 79 | } else { |
| @@ -80,8 +81,7 @@ int ProfilerModel::rowCount(const QModelIndex& parent) const | |||
| 80 | } | 81 | } |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | QVariant ProfilerModel::data(const QModelIndex& index, int role) const | 84 | QVariant ProfilerModel::data(const QModelIndex& index, int role) const { |
| 84 | { | ||
| 85 | if (role == Qt::DisplayRole) { | 85 | if (role == Qt::DisplayRole) { |
| 86 | if (index.row() == 0) { | 86 | if (index.row() == 0) { |
| 87 | if (index.column() == 0) { | 87 | if (index.column() == 0) { |
| @@ -101,14 +101,12 @@ QVariant ProfilerModel::data(const QModelIndex& index, int role) const | |||
| 101 | return QVariant(); | 101 | return QVariant(); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | void ProfilerModel::updateProfilingInfo() | 104 | void ProfilerModel::updateProfilingInfo() { |
| 105 | { | ||
| 106 | results = GetTimingResultsAggregator()->GetAggregatedResults(); | 105 | results = GetTimingResultsAggregator()->GetAggregatedResults(); |
| 107 | emit dataChanged(createIndex(0, 1), createIndex(rowCount() - 1, 3)); | 106 | emit dataChanged(createIndex(0, 1), createIndex(rowCount() - 1, 3)); |
| 108 | } | 107 | } |
| 109 | 108 | ||
| 110 | ProfilerWidget::ProfilerWidget(QWidget* parent) : QDockWidget(parent) | 109 | ProfilerWidget::ProfilerWidget(QWidget* parent) : QDockWidget(parent) { |
| 111 | { | ||
| 112 | ui.setupUi(this); | 110 | ui.setupUi(this); |
| 113 | 111 | ||
| 114 | model = new ProfilerModel(this); | 112 | model = new ProfilerModel(this); |
| @@ -118,8 +116,7 @@ ProfilerWidget::ProfilerWidget(QWidget* parent) : QDockWidget(parent) | |||
| 118 | connect(&update_timer, SIGNAL(timeout()), model, SLOT(updateProfilingInfo())); | 116 | connect(&update_timer, SIGNAL(timeout()), model, SLOT(updateProfilingInfo())); |
| 119 | } | 117 | } |
| 120 | 118 | ||
| 121 | void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable) | 119 | void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable) { |
| 122 | { | ||
| 123 | if (enable) { | 120 | if (enable) { |
| 124 | update_timer.start(100); | 121 | update_timer.start(100); |
| 125 | model->updateProfilingInfo(); | 122 | model->updateProfilingInfo(); |
| @@ -157,9 +154,7 @@ private: | |||
| 157 | 154 | ||
| 158 | #endif | 155 | #endif |
| 159 | 156 | ||
| 160 | MicroProfileDialog::MicroProfileDialog(QWidget* parent) | 157 | MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) { |
| 161 | : QWidget(parent, Qt::Dialog) | ||
| 162 | { | ||
| 163 | setObjectName("MicroProfile"); | 158 | setObjectName("MicroProfile"); |
| 164 | setWindowTitle(tr("MicroProfile")); | 159 | setWindowTitle(tr("MicroProfile")); |
| 165 | resize(1000, 600); | 160 | resize(1000, 600); |
| @@ -175,7 +170,8 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent) | |||
| 175 | layout->addWidget(widget); | 170 | layout->addWidget(widget); |
| 176 | setLayout(layout); | 171 | setLayout(layout); |
| 177 | 172 | ||
| 178 | // Configure focus so that widget is focusable and the dialog automatically forwards focus to it. | 173 | // Configure focus so that widget is focusable and the dialog automatically forwards focus to |
| 174 | // it. | ||
| 179 | setFocusProxy(widget); | 175 | setFocusProxy(widget); |
| 180 | widget->setFocusPolicy(Qt::StrongFocus); | 176 | widget->setFocusPolicy(Qt::StrongFocus); |
| 181 | widget->setFocus(); | 177 | widget->setFocus(); |
| @@ -207,7 +203,6 @@ void MicroProfileDialog::hideEvent(QHideEvent* ev) { | |||
| 207 | QWidget::hideEvent(ev); | 203 | QWidget::hideEvent(ev); |
| 208 | } | 204 | } |
| 209 | 205 | ||
| 210 | |||
| 211 | #if MICROPROFILE_ENABLED | 206 | #if MICROPROFILE_ENABLED |
| 212 | 207 | ||
| 213 | /// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the | 208 | /// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the |
| @@ -308,7 +303,8 @@ void MicroProfileDrawText(int x, int y, u32 hex_color, const char* text, u32 tex | |||
| 308 | } | 303 | } |
| 309 | } | 304 | } |
| 310 | 305 | ||
| 311 | void MicroProfileDrawBox(int left, int top, int right, int bottom, u32 hex_color, MicroProfileBoxType type) { | 306 | void MicroProfileDrawBox(int left, int top, int right, int bottom, u32 hex_color, |
| 307 | MicroProfileBoxType type) { | ||
| 312 | QColor color = QColor::fromRgba(hex_color); | 308 | QColor color = QColor::fromRgba(hex_color); |
| 313 | QBrush brush = color; | 309 | QBrush brush = color; |
| 314 | if (type == MicroProfileBoxTypeBar) { | 310 | if (type == MicroProfileBoxTypeBar) { |
| @@ -326,7 +322,7 @@ void MicroProfileDrawLine2D(u32 vertices_length, float* vertices, u32 hex_color) | |||
| 326 | static std::vector<QPointF> point_buf; | 322 | static std::vector<QPointF> point_buf; |
| 327 | 323 | ||
| 328 | for (u32 i = 0; i < vertices_length; ++i) { | 324 | for (u32 i = 0; i < vertices_length; ++i) { |
| 329 | point_buf.emplace_back(vertices[i*2 + 0], vertices[i*2 + 1]); | 325 | point_buf.emplace_back(vertices[i * 2 + 0], vertices[i * 2 + 1]); |
| 330 | } | 326 | } |
| 331 | 327 | ||
| 332 | // hex_color does not include an alpha, so it must be assumed to be 255 | 328 | // hex_color does not include an alpha, so it must be assumed to be 255 |
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h index 3b38ed8ec..d0a90fdee 100644 --- a/src/citra_qt/debugger/profiler.h +++ b/src/citra_qt/debugger/profiler.h | |||
| @@ -13,15 +13,16 @@ | |||
| 13 | #include "common/microprofile.h" | 13 | #include "common/microprofile.h" |
| 14 | #include "common/profiler_reporting.h" | 14 | #include "common/profiler_reporting.h" |
| 15 | 15 | ||
| 16 | class ProfilerModel : public QAbstractItemModel | 16 | class ProfilerModel : public QAbstractItemModel { |
| 17 | { | ||
| 18 | Q_OBJECT | 17 | Q_OBJECT |
| 19 | 18 | ||
| 20 | public: | 19 | public: |
| 21 | ProfilerModel(QObject* parent); | 20 | ProfilerModel(QObject* parent); |
| 22 | 21 | ||
| 23 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; | 22 | QVariant headerData(int section, Qt::Orientation orientation, |
| 24 | QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; | 23 | int role = Qt::DisplayRole) const override; |
| 24 | QModelIndex index(int row, int column, | ||
| 25 | const QModelIndex& parent = QModelIndex()) const override; | ||
| 25 | QModelIndex parent(const QModelIndex& child) const override; | 26 | QModelIndex parent(const QModelIndex& child) const override; |
| 26 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; | 27 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; |
| 27 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; | 28 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
| @@ -34,8 +35,7 @@ private: | |||
| 34 | Common::Profiling::AggregatedFrameResult results; | 35 | Common::Profiling::AggregatedFrameResult results; |
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| 37 | class ProfilerWidget : public QDockWidget | 38 | class ProfilerWidget : public QDockWidget { |
| 38 | { | ||
| 39 | Q_OBJECT | 39 | Q_OBJECT |
| 40 | 40 | ||
| 41 | public: | 41 | public: |
| @@ -51,7 +51,6 @@ private: | |||
| 51 | QTimer update_timer; | 51 | QTimer update_timer; |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | |||
| 55 | class MicroProfileDialog : public QWidget { | 54 | class MicroProfileDialog : public QWidget { |
| 56 | Q_OBJECT | 55 | Q_OBJECT |
| 57 | 56 | ||
diff --git a/src/citra_qt/debugger/ramview.cpp b/src/citra_qt/debugger/ramview.cpp index 02347e83a..63f2850e1 100644 --- a/src/citra_qt/debugger/ramview.cpp +++ b/src/citra_qt/debugger/ramview.cpp | |||
| @@ -4,12 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #include "citra_qt/debugger/ramview.h" | 5 | #include "citra_qt/debugger/ramview.h" |
| 6 | 6 | ||
| 7 | GRamView::GRamView(QWidget* parent) : QHexEdit(parent) | 7 | GRamView::GRamView(QWidget* parent) : QHexEdit(parent) { |
| 8 | { | ||
| 9 | } | 8 | } |
| 10 | 9 | ||
| 11 | void GRamView::OnCPUStepped() | 10 | void GRamView::OnCPUStepped() { |
| 12 | { | ||
| 13 | // TODO: QHexEdit doesn't show vertical scroll bars for > 10MB data streams... | 11 | // TODO: QHexEdit doesn't show vertical scroll bars for > 10MB data streams... |
| 14 | //setData(QByteArray((const char*)Mem_RAM,sizeof(Mem_RAM)/8)); | 12 | // setData(QByteArray((const char*)Mem_RAM,sizeof(Mem_RAM)/8)); |
| 15 | } | 13 | } |
diff --git a/src/citra_qt/debugger/ramview.h b/src/citra_qt/debugger/ramview.h index 0ef74586b..8043c59e8 100644 --- a/src/citra_qt/debugger/ramview.h +++ b/src/citra_qt/debugger/ramview.h | |||
| @@ -4,8 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "qhexedit.h" | 5 | #include "qhexedit.h" |
| 6 | 6 | ||
| 7 | class GRamView : public QHexEdit | 7 | class GRamView : public QHexEdit { |
| 8 | { | ||
| 9 | Q_OBJECT | 8 | Q_OBJECT |
| 10 | 9 | ||
| 11 | public: | 10 | public: |
diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp index 1bd0bfebc..82da0022f 100644 --- a/src/citra_qt/debugger/registers.cpp +++ b/src/citra_qt/debugger/registers.cpp | |||
| @@ -7,8 +7,8 @@ | |||
| 7 | #include "citra_qt/debugger/registers.h" | 7 | #include "citra_qt/debugger/registers.h" |
| 8 | #include "citra_qt/util/util.h" | 8 | #include "citra_qt/util/util.h" |
| 9 | 9 | ||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/arm/arm_interface.h" | 10 | #include "core/arm/arm_interface.h" |
| 11 | #include "core/core.h" | ||
| 12 | 12 | ||
| 13 | RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { | 13 | RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { |
| 14 | cpu_regs_ui.setupUi(this); | 14 | cpu_regs_ui.setupUi(this); |
| @@ -16,7 +16,8 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { | |||
| 16 | tree = cpu_regs_ui.treeWidget; | 16 | tree = cpu_regs_ui.treeWidget; |
| 17 | tree->addTopLevelItem(core_registers = new QTreeWidgetItem(QStringList(tr("Registers")))); | 17 | tree->addTopLevelItem(core_registers = new QTreeWidgetItem(QStringList(tr("Registers")))); |
| 18 | tree->addTopLevelItem(vfp_registers = new QTreeWidgetItem(QStringList(tr("VFP Registers")))); | 18 | tree->addTopLevelItem(vfp_registers = new QTreeWidgetItem(QStringList(tr("VFP Registers")))); |
| 19 | tree->addTopLevelItem(vfp_system_registers = new QTreeWidgetItem(QStringList(tr("VFP System Registers")))); | 19 | tree->addTopLevelItem(vfp_system_registers = |
| 20 | new QTreeWidgetItem(QStringList(tr("VFP System Registers")))); | ||
| 20 | tree->addTopLevelItem(cpsr = new QTreeWidgetItem(QStringList("CPSR"))); | 21 | tree->addTopLevelItem(cpsr = new QTreeWidgetItem(QStringList("CPSR"))); |
| 21 | 22 | ||
| 22 | for (int i = 0; i < 16; ++i) { | 23 | for (int i = 0; i < 16; ++i) { |
| @@ -63,10 +64,12 @@ void RegistersWidget::OnDebugModeEntered() { | |||
| 63 | return; | 64 | return; |
| 64 | 65 | ||
| 65 | for (int i = 0; i < core_registers->childCount(); ++i) | 66 | for (int i = 0; i < core_registers->childCount(); ++i) |
| 66 | core_registers->child(i)->setText(1, QString("0x%1").arg(Core::g_app_core->GetReg(i), 8, 16, QLatin1Char('0'))); | 67 | core_registers->child(i)->setText( |
| 68 | 1, QString("0x%1").arg(Core::g_app_core->GetReg(i), 8, 16, QLatin1Char('0'))); | ||
| 67 | 69 | ||
| 68 | for (int i = 0; i < vfp_registers->childCount(); ++i) | 70 | for (int i = 0; i < vfp_registers->childCount(); ++i) |
| 69 | vfp_registers->child(i)->setText(1, QString("0x%1").arg(Core::g_app_core->GetVFPReg(i), 8, 16, QLatin1Char('0'))); | 71 | vfp_registers->child(i)->setText( |
| 72 | 1, QString("0x%1").arg(Core::g_app_core->GetVFPReg(i), 8, 16, QLatin1Char('0'))); | ||
| 70 | 73 | ||
| 71 | UpdateCPSRValues(); | 74 | UpdateCPSRValues(); |
| 72 | UpdateVFPSystemRegisterValues(); | 75 | UpdateVFPSystemRegisterValues(); |
| @@ -130,21 +133,24 @@ void RegistersWidget::UpdateCPSRValues() { | |||
| 130 | const u32 cpsr_val = Core::g_app_core->GetCPSR(); | 133 | const u32 cpsr_val = Core::g_app_core->GetCPSR(); |
| 131 | 134 | ||
| 132 | cpsr->setText(1, QString("0x%1").arg(cpsr_val, 8, 16, QLatin1Char('0'))); | 135 | cpsr->setText(1, QString("0x%1").arg(cpsr_val, 8, 16, QLatin1Char('0'))); |
| 133 | cpsr->child(0)->setText(1, QString("b%1").arg(cpsr_val & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode | 136 | cpsr->child(0)->setText( |
| 134 | cpsr->child(1)->setText(1, QString::number((cpsr_val >> 5) & 1)); // T - State | 137 | 1, QString("b%1").arg(cpsr_val & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode |
| 135 | cpsr->child(2)->setText(1, QString::number((cpsr_val >> 6) & 1)); // F - FIQ disable | 138 | cpsr->child(1)->setText(1, QString::number((cpsr_val >> 5) & 1)); // T - State |
| 136 | cpsr->child(3)->setText(1, QString::number((cpsr_val >> 7) & 1)); // I - IRQ disable | 139 | cpsr->child(2)->setText(1, QString::number((cpsr_val >> 6) & 1)); // F - FIQ disable |
| 137 | cpsr->child(4)->setText(1, QString::number((cpsr_val >> 8) & 1)); // A - Imprecise abort | 140 | cpsr->child(3)->setText(1, QString::number((cpsr_val >> 7) & 1)); // I - IRQ disable |
| 138 | cpsr->child(5)->setText(1, QString::number((cpsr_val >> 9) & 1)); // E - Data endianess | 141 | cpsr->child(4)->setText(1, QString::number((cpsr_val >> 8) & 1)); // A - Imprecise abort |
| 139 | cpsr->child(6)->setText(1, QString::number((cpsr_val >> 10) & 0x3F)); // IT - If-Then state (DNM) | 142 | cpsr->child(5)->setText(1, QString::number((cpsr_val >> 9) & 1)); // E - Data endianess |
| 140 | cpsr->child(7)->setText(1, QString::number((cpsr_val >> 16) & 0xF)); // GE - Greater-than-or-Equal | 143 | cpsr->child(6)->setText(1, |
| 141 | cpsr->child(8)->setText(1, QString::number((cpsr_val >> 20) & 0xF)); // DNM - Do not modify | 144 | QString::number((cpsr_val >> 10) & 0x3F)); // IT - If-Then state (DNM) |
| 142 | cpsr->child(9)->setText(1, QString::number((cpsr_val >> 24) & 1)); // J - Jazelle | 145 | cpsr->child(7)->setText(1, |
| 143 | cpsr->child(10)->setText(1, QString::number((cpsr_val >> 27) & 1)); // Q - Saturation | 146 | QString::number((cpsr_val >> 16) & 0xF)); // GE - Greater-than-or-Equal |
| 144 | cpsr->child(11)->setText(1, QString::number((cpsr_val >> 28) & 1)); // V - Overflow | 147 | cpsr->child(8)->setText(1, QString::number((cpsr_val >> 20) & 0xF)); // DNM - Do not modify |
| 145 | cpsr->child(12)->setText(1, QString::number((cpsr_val >> 29) & 1)); // C - Carry/Borrow/Extend | 148 | cpsr->child(9)->setText(1, QString::number((cpsr_val >> 24) & 1)); // J - Jazelle |
| 146 | cpsr->child(13)->setText(1, QString::number((cpsr_val >> 30) & 1)); // Z - Zero | 149 | cpsr->child(10)->setText(1, QString::number((cpsr_val >> 27) & 1)); // Q - Saturation |
| 147 | cpsr->child(14)->setText(1, QString::number((cpsr_val >> 31) & 1)); // N - Negative/Less than | 150 | cpsr->child(11)->setText(1, QString::number((cpsr_val >> 28) & 1)); // V - Overflow |
| 151 | cpsr->child(12)->setText(1, QString::number((cpsr_val >> 29) & 1)); // C - Carry/Borrow/Extend | ||
| 152 | cpsr->child(13)->setText(1, QString::number((cpsr_val >> 30) & 1)); // Z - Zero | ||
| 153 | cpsr->child(14)->setText(1, QString::number((cpsr_val >> 31) & 1)); // N - Negative/Less than | ||
| 148 | } | 154 | } |
| 149 | 155 | ||
| 150 | void RegistersWidget::CreateVFPSystemRegisterChildren() { | 156 | void RegistersWidget::CreateVFPSystemRegisterChildren() { |
| @@ -188,9 +194,9 @@ void RegistersWidget::CreateVFPSystemRegisterChildren() { | |||
| 188 | } | 194 | } |
| 189 | 195 | ||
| 190 | void RegistersWidget::UpdateVFPSystemRegisterValues() { | 196 | void RegistersWidget::UpdateVFPSystemRegisterValues() { |
| 191 | const u32 fpscr_val = Core::g_app_core->GetVFPSystemReg(VFP_FPSCR); | 197 | const u32 fpscr_val = Core::g_app_core->GetVFPSystemReg(VFP_FPSCR); |
| 192 | const u32 fpexc_val = Core::g_app_core->GetVFPSystemReg(VFP_FPEXC); | 198 | const u32 fpexc_val = Core::g_app_core->GetVFPSystemReg(VFP_FPEXC); |
| 193 | const u32 fpinst_val = Core::g_app_core->GetVFPSystemReg(VFP_FPINST); | 199 | const u32 fpinst_val = Core::g_app_core->GetVFPSystemReg(VFP_FPINST); |
| 194 | const u32 fpinst2_val = Core::g_app_core->GetVFPSystemReg(VFP_FPINST2); | 200 | const u32 fpinst2_val = Core::g_app_core->GetVFPSystemReg(VFP_FPINST2); |
| 195 | 201 | ||
| 196 | QTreeWidgetItem* const fpscr = vfp_system_registers->child(0); | 202 | QTreeWidgetItem* const fpscr = vfp_system_registers->child(0); |
| @@ -228,6 +234,8 @@ void RegistersWidget::UpdateVFPSystemRegisterValues() { | |||
| 228 | fpexc->child(6)->setText(1, QString::number((fpexc_val >> 30) & 1)); | 234 | fpexc->child(6)->setText(1, QString::number((fpexc_val >> 30) & 1)); |
| 229 | fpexc->child(7)->setText(1, QString::number((fpexc_val >> 31) & 1)); | 235 | fpexc->child(7)->setText(1, QString::number((fpexc_val >> 31) & 1)); |
| 230 | 236 | ||
| 231 | vfp_system_registers->child(2)->setText(1, QString("0x%1").arg(fpinst_val, 8, 16, QLatin1Char('0'))); | 237 | vfp_system_registers->child(2)->setText( |
| 232 | vfp_system_registers->child(3)->setText(1, QString("0x%1").arg(fpinst2_val, 8, 16, QLatin1Char('0'))); | 238 | 1, QString("0x%1").arg(fpinst_val, 8, 16, QLatin1Char('0'))); |
| 239 | vfp_system_registers->child(3)->setText( | ||
| 240 | 1, QString("0x%1").arg(fpinst2_val, 8, 16, QLatin1Char('0'))); | ||
| 233 | } | 241 | } |
diff --git a/src/citra_qt/debugger/registers.h b/src/citra_qt/debugger/registers.h index cf27acc1c..cba601731 100644 --- a/src/citra_qt/debugger/registers.h +++ b/src/citra_qt/debugger/registers.h | |||
| @@ -10,8 +10,7 @@ class QTreeWidget; | |||
| 10 | class QTreeWidgetItem; | 10 | class QTreeWidgetItem; |
| 11 | class EmuThread; | 11 | class EmuThread; |
| 12 | 12 | ||
| 13 | class RegistersWidget : public QDockWidget | 13 | class RegistersWidget : public QDockWidget { |
| 14 | { | ||
| 15 | Q_OBJECT | 14 | Q_OBJECT |
| 16 | 15 | ||
| 17 | public: | 16 | public: |