summaryrefslogtreecommitdiff
path: root/src/citra_qt/debugger/graphics_breakpoints.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/citra_qt/debugger/graphics_breakpoints.cpp')
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.cpp263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
new file mode 100644
index 000000000..9486f06cc
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -0,0 +1,263 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
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#include "graphics_breakpoints_p.hxx"
13
14BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent)
15 : QAbstractListModel(parent), context_weak(debug_context),
16 at_breakpoint(debug_context->at_breakpoint),
17 active_breakpoint(debug_context->active_breakpoint)
18{
19
20}
21
22int BreakPointModel::columnCount(const QModelIndex& parent) const
23{
24 return 2;
25}
26
27int BreakPointModel::rowCount(const QModelIndex& parent) const
28{
29 return static_cast<int>(Pica::DebugContext::Event::NumEvents);
30}
31
32QVariant BreakPointModel::data(const QModelIndex& index, int role) const
33{
34 const auto event = static_cast<Pica::DebugContext::Event>(index.row());
35
36 switch (role) {
37 case Qt::DisplayRole:
38 {
39 switch (index.column()) {
40 case 0:
41 {
42 static const std::map<Pica::DebugContext::Event, QString> map = {
43 { Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded") },
44 { Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed") },
45 { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") },
46 { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") },
47 { Pica::DebugContext::Event::VertexLoaded, tr("Vertex Loaded") }
48 };
49
50 _dbg_assert_(Debug_GPU, map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents));
51
52 return (map.find(event) != map.end()) ? map.at(event) : QString();
53 }
54
55 case 1:
56 return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled");
57
58 default:
59 break;
60 }
61
62 break;
63 }
64
65 case Qt::BackgroundRole:
66 {
67 if (at_breakpoint && index.row() == static_cast<int>(active_breakpoint)) {
68 return QBrush(QColor(0xE0, 0xE0, 0x10));
69 }
70 break;
71 }
72
73 case Role_IsEnabled:
74 {
75 auto context = context_weak.lock();
76 return context && context->breakpoints[event].enabled;
77 }
78
79 default:
80 break;
81 }
82 return QVariant();
83}
84
85QVariant BreakPointModel::headerData(int section, Qt::Orientation orientation, int role) const
86{
87 switch(role) {
88 case Qt::DisplayRole:
89 {
90 if (section == 0) {
91 return tr("Event");
92 } else if (section == 1) {
93 return tr("Status");
94 }
95
96 break;
97 }
98 }
99
100 return QVariant();
101}
102
103bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role)
104{
105 const auto event = static_cast<Pica::DebugContext::Event>(index.row());
106
107 switch (role) {
108 case Role_IsEnabled:
109 {
110 auto context = context_weak.lock();
111 if (!context)
112 return false;
113
114 context->breakpoints[event].enabled = value.toBool();
115 QModelIndex changed_index = createIndex(index.row(), 1);
116 emit dataChanged(changed_index, changed_index);
117 return true;
118 }
119 }
120
121 return false;
122}
123
124
125void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event)
126{
127 auto context = context_weak.lock();
128 if (!context)
129 return;
130
131 active_breakpoint = context->active_breakpoint;
132 at_breakpoint = context->at_breakpoint;
133 emit dataChanged(createIndex(static_cast<int>(event), 0),
134 createIndex(static_cast<int>(event), 1));
135}
136
137void BreakPointModel::OnResumed()
138{
139 auto context = context_weak.lock();
140 if (!context)
141 return;
142
143 at_breakpoint = context->at_breakpoint;
144 emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0),
145 createIndex(static_cast<int>(active_breakpoint), 1));
146 active_breakpoint = context->active_breakpoint;
147}
148
149
150GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
151 QWidget* parent)
152 : QDockWidget(tr("Pica Breakpoints"), parent),
153 Pica::DebugContext::BreakPointObserver(debug_context)
154{
155 setObjectName("PicaBreakPointsWidget");
156
157 status_text = new QLabel(tr("Emulation running"));
158 resume_button = new QPushButton(tr("Resume"));
159 resume_button->setEnabled(false);
160
161 breakpoint_model = new BreakPointModel(debug_context, this);
162 breakpoint_list = new QTreeView;
163 breakpoint_list->setModel(breakpoint_model);
164
165 toggle_breakpoint_button = new QPushButton(tr("Enable"));
166 toggle_breakpoint_button->setEnabled(false);
167
168 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
169
170 connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested()));
171
172 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
173 this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)),
174 Qt::BlockingQueuedConnection);
175 connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed()));
176
177 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
178 breakpoint_model, SLOT(OnBreakPointHit(Pica::DebugContext::Event)),
179 Qt::BlockingQueuedConnection);
180 connect(this, SIGNAL(Resumed()), breakpoint_model, SLOT(OnResumed()));
181
182 connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)),
183 breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)));
184
185 connect(breakpoint_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
186 this, SLOT(OnBreakpointSelectionChanged(QModelIndex)));
187
188 connect(toggle_breakpoint_button, SIGNAL(clicked()), this, SLOT(OnToggleBreakpointEnabled()));
189
190 QWidget* main_widget = new QWidget;
191 auto main_layout = new QVBoxLayout;
192 {
193 auto sub_layout = new QHBoxLayout;
194 sub_layout->addWidget(status_text);
195 sub_layout->addWidget(resume_button);
196 main_layout->addLayout(sub_layout);
197 }
198 main_layout->addWidget(breakpoint_list);
199 main_layout->addWidget(toggle_breakpoint_button);
200 main_widget->setLayout(main_layout);
201
202 setWidget(main_widget);
203}
204
205void GraphicsBreakPointsWidget::OnPicaBreakPointHit(Event event, void* data)
206{
207 // Process in GUI thread
208 emit BreakPointHit(event, data);
209}
210
211void GraphicsBreakPointsWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data)
212{
213 status_text->setText(tr("Emulation halted at breakpoint"));
214 resume_button->setEnabled(true);
215}
216
217void GraphicsBreakPointsWidget::OnPicaResume()
218{
219 // Process in GUI thread
220 emit Resumed();
221}
222
223void GraphicsBreakPointsWidget::OnResumed()
224{
225 status_text->setText(tr("Emulation running"));
226 resume_button->setEnabled(false);
227}
228
229void GraphicsBreakPointsWidget::OnResumeRequested()
230{
231 if (auto context = context_weak.lock())
232 context->Resume();
233}
234
235void GraphicsBreakPointsWidget::OnBreakpointSelectionChanged(const QModelIndex& index)
236{
237 if (!index.isValid()) {
238 toggle_breakpoint_button->setEnabled(false);
239 return;
240 }
241
242 toggle_breakpoint_button->setEnabled(true);
243 UpdateToggleBreakpointButton(index);
244}
245
246void GraphicsBreakPointsWidget::OnToggleBreakpointEnabled()
247{
248 QModelIndex index = breakpoint_list->selectionModel()->currentIndex();
249 bool new_state = !(breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool());
250
251 breakpoint_model->setData(index, new_state,
252 BreakPointModel::Role_IsEnabled);
253 UpdateToggleBreakpointButton(index);
254}
255
256void GraphicsBreakPointsWidget::UpdateToggleBreakpointButton(const QModelIndex& index)
257{
258 if (true == breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()) {
259 toggle_breakpoint_button->setText(tr("Disable"));
260 } else {
261 toggle_breakpoint_button->setText(tr("Enable"));
262 }
263}