summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra_qt/CMakeLists.txt2
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.cpp253
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.hxx78
-rw-r--r--src/citra_qt/main.cpp6
4 files changed, 339 insertions, 0 deletions
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 7bf44197d..999724102 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -8,6 +8,7 @@ set(SRCS
8 debugger/callstack.cpp 8 debugger/callstack.cpp
9 debugger/disassembler.cpp 9 debugger/disassembler.cpp
10 debugger/graphics.cpp 10 debugger/graphics.cpp
11 debugger/graphics_breakpoints.cpp
11 debugger/graphics_cmdlists.cpp 12 debugger/graphics_cmdlists.cpp
12 debugger/ramview.cpp 13 debugger/ramview.cpp
13 debugger/registers.cpp 14 debugger/registers.cpp
@@ -24,6 +25,7 @@ set(HEADERS
24 debugger/callstack.hxx 25 debugger/callstack.hxx
25 debugger/disassembler.hxx 26 debugger/disassembler.hxx
26 debugger/graphics.hxx 27 debugger/graphics.hxx
28 debugger/graphics_breakpoints.hxx
27 debugger/graphics_cmdlists.hxx 29 debugger/graphics_cmdlists.hxx
28 debugger/ramview.hxx 30 debugger/ramview.hxx
29 debugger/registers.hxx 31 debugger/registers.hxx
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
new file mode 100644
index 000000000..2f41d5f77
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -0,0 +1,253 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <QMetaType>
6#include <QPushButton>
7#include <QTreeWidget>
8#include <QVBoxLayout>
9#include <QLabel>
10
11#include "graphics_breakpoints.hxx"
12
13BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent)
14 : QAbstractListModel(parent), context_weak(debug_context),
15 at_breakpoint(debug_context->at_breakpoint),
16 active_breakpoint(debug_context->active_breakpoint)
17{
18
19}
20
21int BreakPointModel::columnCount(const QModelIndex& parent) const
22{
23 return 2;
24}
25
26int BreakPointModel::rowCount(const QModelIndex& parent) const
27{
28 return static_cast<int>(Pica::DebugContext::Event::NumEvents);
29}
30
31QVariant BreakPointModel::data(const QModelIndex& index, int role) const
32{
33 const auto event = static_cast<Pica::DebugContext::Event>(index.row());
34
35 switch (role) {
36 case Qt::DisplayRole:
37 {
38 if (index.column() == 0) {
39 std::map<Pica::DebugContext::Event, QString> map;
40 map.insert({Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded")});
41 map.insert({Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed")});
42 map.insert({Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incomming primitive batch")});
43 map.insert({Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch")});
44
45 _dbg_assert_(GPU, map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents));
46
47 return map[event];
48 } else if (index.column() == 1) {
49 return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled");
50 }
51
52 break;
53 }
54
55 case Qt::BackgroundRole:
56 {
57 if (at_breakpoint && index.row() == static_cast<int>(active_breakpoint)) {
58 return QBrush(QColor(0xE0, 0xE0, 0x10));
59 }
60 break;
61 }
62
63 case Role_IsEnabled:
64 {
65 auto context = context_weak.lock();
66 return context && context->breakpoints[event].enabled;
67 }
68
69 default:
70 break;
71 }
72 return QVariant();
73}
74
75QVariant BreakPointModel::headerData(int section, Qt::Orientation orientation, int role) const
76{
77 switch(role) {
78 case Qt::DisplayRole:
79 {
80 if (section == 0) {
81 return tr("Event");
82 } else if (section == 1) {
83 return tr("Status");
84 }
85
86 break;
87 }
88 }
89
90 return QVariant();
91}
92
93bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role)
94{
95 const auto event = static_cast<Pica::DebugContext::Event>(index.row());
96
97 switch (role) {
98 case Role_IsEnabled:
99 {
100 auto context = context_weak.lock();
101 if (!context)
102 return false;
103
104 context->breakpoints[event].enabled = value.toBool();
105 QModelIndex changed_index = createIndex(index.row(), 1);
106 emit dataChanged(changed_index, changed_index);
107 return true;
108 }
109 }
110
111 return false;
112}
113
114
115void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event)
116{
117 auto context = context_weak.lock();
118 if (!context)
119 return;
120
121 active_breakpoint = context->active_breakpoint;
122 at_breakpoint = context->at_breakpoint;
123 emit dataChanged(createIndex(static_cast<int>(event), 0),
124 createIndex(static_cast<int>(event), 1));
125}
126
127void BreakPointModel::OnResumed()
128{
129 auto context = context_weak.lock();
130 if (!context)
131 return;
132
133 at_breakpoint = context->at_breakpoint;
134 emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0),
135 createIndex(static_cast<int>(active_breakpoint), 1));
136 active_breakpoint = context->active_breakpoint;
137}
138
139
140GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
141 QWidget* parent)
142 : QDockWidget(tr("Pica Breakpoints"), parent),
143 Pica::DebugContext::BreakPointObserver(debug_context)
144{
145 setObjectName("PicaBreakPointsWidget");
146
147 status_text = new QLabel(tr("Emulation running"));
148 resume_button = new QPushButton(tr("Resume"));
149 resume_button->setEnabled(false);
150
151 breakpoint_model = new BreakPointModel(debug_context, this);
152 breakpoint_list = new QTreeView;
153 breakpoint_list->setModel(breakpoint_model);
154
155 toggle_breakpoint_button = new QPushButton(tr("Enable"));
156 toggle_breakpoint_button->setEnabled(false);
157
158 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
159
160 connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested()));
161
162 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
163 this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)),
164 Qt::BlockingQueuedConnection);
165 connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed()));
166
167 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
168 breakpoint_model, SLOT(OnBreakPointHit(Pica::DebugContext::Event)),
169 Qt::BlockingQueuedConnection);
170 connect(this, SIGNAL(Resumed()), breakpoint_model, SLOT(OnResumed()));
171
172 connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)),
173 breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)));
174
175 connect(breakpoint_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
176 this, SLOT(OnBreakpointSelectionChanged(QModelIndex)));
177
178 connect(toggle_breakpoint_button, SIGNAL(clicked()), this, SLOT(OnToggleBreakpointEnabled()));
179
180 QWidget* main_widget = new QWidget;
181 auto main_layout = new QVBoxLayout;
182 {
183 auto sub_layout = new QHBoxLayout;
184 sub_layout->addWidget(status_text);
185 sub_layout->addWidget(resume_button);
186 main_layout->addLayout(sub_layout);
187 }
188 main_layout->addWidget(breakpoint_list);
189 main_layout->addWidget(toggle_breakpoint_button);
190 main_widget->setLayout(main_layout);
191
192 setWidget(main_widget);
193}
194
195void GraphicsBreakPointsWidget::OnPicaBreakPointHit(Event event, void* data)
196{
197 // Process in GUI thread
198 emit BreakPointHit(event, data);
199}
200
201void GraphicsBreakPointsWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data)
202{
203 status_text->setText(tr("Emulation halted at breakpoint"));
204 resume_button->setEnabled(true);
205}
206
207void GraphicsBreakPointsWidget::OnPicaResume()
208{
209 // Process in GUI thread
210 emit Resumed();
211}
212
213void GraphicsBreakPointsWidget::OnResumed()
214{
215 status_text->setText(tr("Emulation running"));
216 resume_button->setEnabled(false);
217}
218
219void GraphicsBreakPointsWidget::OnResumeRequested()
220{
221 if (auto context = context_weak.lock())
222 context->Resume();
223}
224
225void GraphicsBreakPointsWidget::OnBreakpointSelectionChanged(const QModelIndex& index)
226{
227 if (!index.isValid()) {
228 toggle_breakpoint_button->setEnabled(false);
229 return;
230 }
231
232 toggle_breakpoint_button->setEnabled(true);
233 UpdateToggleBreakpointButton(index);
234}
235
236void GraphicsBreakPointsWidget::OnToggleBreakpointEnabled()
237{
238 QModelIndex index = breakpoint_list->selectionModel()->currentIndex();
239 bool new_state = !(breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool());
240
241 breakpoint_model->setData(index, new_state,
242 BreakPointModel::Role_IsEnabled);
243 UpdateToggleBreakpointButton(index);
244}
245
246void GraphicsBreakPointsWidget::UpdateToggleBreakpointButton(const QModelIndex& index)
247{
248 if (true == breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()) {
249 toggle_breakpoint_button->setText(tr("Disable"));
250 } else {
251 toggle_breakpoint_button->setText(tr("Enable"));
252 }
253}
diff --git a/src/citra_qt/debugger/graphics_breakpoints.hxx b/src/citra_qt/debugger/graphics_breakpoints.hxx
new file mode 100644
index 000000000..edc41283e
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_breakpoints.hxx
@@ -0,0 +1,78 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include <QAbstractListModel>
10#include <QDockWidget>
11
12#include "video_core/debug_utils/debug_utils.h"
13
14class QLabel;
15class QPushButton;
16class QTreeView;
17
18class BreakPointModel : public QAbstractListModel {
19 Q_OBJECT
20
21public:
22 enum {
23 Role_IsEnabled = Qt::UserRole,
24 };
25
26 BreakPointModel(std::shared_ptr<Pica::DebugContext> context, QObject* parent);
27
28 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
29 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
30 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
31 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
32
33 bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
34
35public slots:
36 void OnBreakPointHit(Pica::DebugContext::Event event);
37 void OnResumed();
38
39private:
40 bool at_breakpoint;
41 Pica::DebugContext::Event active_breakpoint;
42 std::weak_ptr<Pica::DebugContext> context_weak;
43};
44
45class GraphicsBreakPointsWidget : public QDockWidget, Pica::DebugContext::BreakPointObserver {
46 Q_OBJECT
47
48 using Event = Pica::DebugContext::Event;
49
50public:
51 GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
52 QWidget* parent = nullptr);
53
54 void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
55 void OnPicaResume() override;
56
57public slots:
58 void OnBreakPointHit(Pica::DebugContext::Event event, void* data);
59 void OnResumeRequested();
60 void OnResumed();
61 void OnBreakpointSelectionChanged(const QModelIndex&);
62 void OnToggleBreakpointEnabled();
63
64signals:
65 void Resumed();
66 void BreakPointHit(Pica::DebugContext::Event event, void* data);
67 void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
68
69private:
70 void UpdateToggleBreakpointButton(const QModelIndex& index);
71
72 QLabel* status_text;
73 QPushButton* resume_button;
74 QPushButton* toggle_breakpoint_button;
75
76 BreakPointModel* breakpoint_model;
77 QTreeView* breakpoint_list;
78};
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 869826e61..84afe59d8 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -20,6 +20,7 @@
20#include "debugger/callstack.hxx" 20#include "debugger/callstack.hxx"
21#include "debugger/ramview.hxx" 21#include "debugger/ramview.hxx"
22#include "debugger/graphics.hxx" 22#include "debugger/graphics.hxx"
23#include "debugger/graphics_breakpoints.hxx"
23#include "debugger/graphics_cmdlists.hxx" 24#include "debugger/graphics_cmdlists.hxx"
24 25
25#include "core/settings.h" 26#include "core/settings.h"
@@ -69,12 +70,17 @@ GMainWindow::GMainWindow()
69 addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget); 70 addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget);
70 graphicsCommandsWidget->hide(); 71 graphicsCommandsWidget->hide();
71 72
73 auto graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(Pica::g_debug_context, this);
74 addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
75 graphicsBreakpointsWidget->hide();
76
72 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); 77 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
73 debug_menu->addAction(disasmWidget->toggleViewAction()); 78 debug_menu->addAction(disasmWidget->toggleViewAction());
74 debug_menu->addAction(registersWidget->toggleViewAction()); 79 debug_menu->addAction(registersWidget->toggleViewAction());
75 debug_menu->addAction(callstackWidget->toggleViewAction()); 80 debug_menu->addAction(callstackWidget->toggleViewAction());
76 debug_menu->addAction(graphicsWidget->toggleViewAction()); 81 debug_menu->addAction(graphicsWidget->toggleViewAction());
77 debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); 82 debug_menu->addAction(graphicsCommandsWidget->toggleViewAction());
83 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
78 84
79 // Set default UI state 85 // Set default UI state
80 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half 86 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half