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