summaryrefslogtreecommitdiff
path: root/src/citra_qt/debugger/profiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/citra_qt/debugger/profiler.cpp')
-rw-r--r--src/citra_qt/debugger/profiler.cpp202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index 89b28c2f4..5261d4836 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -2,9 +2,21 @@
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 <QMouseEvent>
6#include <QPainter>
7#include <QString>
8
5#include "profiler.h" 9#include "profiler.h"
6 10
11#include "citra_qt/util/util.h"
12
7#include "common/profiler_reporting.h" 13#include "common/profiler_reporting.h"
14#include "common/microprofile.h"
15
16// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the
17// non-Qt frontends don't need it (and don't implement the UI drawing hooks either).
18#define MICROPROFILEUI_IMPL 1
19#include "common/microprofileui.h"
8 20
9using namespace Common::Profiling; 21using namespace Common::Profiling;
10 22
@@ -136,3 +148,193 @@ void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable)
136 update_timer.stop(); 148 update_timer.stop();
137 } 149 }
138} 150}
151
152class MicroProfileWidget : public QWidget {
153public:
154 MicroProfileWidget(QWidget* parent = 0);
155
156protected:
157 void paintEvent(QPaintEvent* ev) override;
158 void showEvent(QShowEvent* ev) override;
159 void hideEvent(QHideEvent* ev) override;
160
161 void mouseMoveEvent(QMouseEvent* ev) override;
162 void mousePressEvent(QMouseEvent* ev) override;
163 void mouseReleaseEvent(QMouseEvent* ev) override;
164 void wheelEvent(QWheelEvent* ev) override;
165
166 void keyPressEvent(QKeyEvent* ev) override;
167 void keyReleaseEvent(QKeyEvent* ev) override;
168
169private:
170 /// This timer is used to redraw the widget's contents continuously. To save resources, it only
171 /// runs while the widget is visible.
172 QTimer update_timer;
173};
174
175MicroProfileDialog::MicroProfileDialog(QWidget* parent)
176 : QWidget(parent, Qt::Dialog)
177{
178 setObjectName("MicroProfile");
179 setWindowTitle(tr("MicroProfile"));
180 resize(1000, 600);
181 // Remove the "?" button from the titlebar and enable the maximize button
182 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::WindowMaximizeButtonHint);
183
184 MicroProfileWidget* widget = new MicroProfileWidget(this);
185
186 QLayout* layout = new QVBoxLayout(this);
187 layout->setContentsMargins(0, 0, 0, 0);
188 layout->addWidget(widget);
189 setLayout(layout);
190
191 // Configure focus so that widget is focusable and the dialog automatically forwards focus to it.
192 setFocusProxy(widget);
193 widget->setFocusPolicy(Qt::StrongFocus);
194 widget->setFocus();
195}
196
197QAction* MicroProfileDialog::toggleViewAction() {
198 if (toggle_view_action == nullptr) {
199 toggle_view_action = new QAction(windowTitle(), this);
200 toggle_view_action->setCheckable(true);
201 toggle_view_action->setChecked(isVisible());
202 connect(toggle_view_action, SIGNAL(toggled(bool)), SLOT(setVisible(bool)));
203 }
204
205 return toggle_view_action;
206}
207
208void MicroProfileDialog::showEvent(QShowEvent* ev) {
209 if (toggle_view_action) {
210 toggle_view_action->setChecked(isVisible());
211 }
212 QWidget::showEvent(ev);
213}
214
215void MicroProfileDialog::hideEvent(QHideEvent* ev) {
216 if (toggle_view_action) {
217 toggle_view_action->setChecked(isVisible());
218 }
219 QWidget::hideEvent(ev);
220}
221
222/// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the
223/// QPainter available inside the drawing callbacks.
224static QPainter* mp_painter = nullptr;
225
226MicroProfileWidget::MicroProfileWidget(QWidget* parent) : QWidget(parent) {
227 // Send mouse motion events even when not dragging.
228 setMouseTracking(true);
229
230 MicroProfileSetDisplayMode(1); // Timers screen
231 MicroProfileInitUI();
232
233 connect(&update_timer, SIGNAL(timeout()), SLOT(update()));
234}
235
236void MicroProfileWidget::paintEvent(QPaintEvent* ev) {
237 QPainter painter(this);
238
239 painter.setBackground(Qt::black);
240 painter.eraseRect(rect());
241
242 QFont font = GetMonospaceFont();
243 font.setPixelSize(MICROPROFILE_TEXT_HEIGHT);
244 painter.setFont(font);
245
246 mp_painter = &painter;
247 MicroProfileDraw(rect().width(), rect().height());
248 mp_painter = nullptr;
249}
250
251void MicroProfileWidget::showEvent(QShowEvent* ev) {
252 update_timer.start(15); // ~60 Hz
253 QWidget::showEvent(ev);
254}
255
256void MicroProfileWidget::hideEvent(QHideEvent* ev) {
257 update_timer.stop();
258 QWidget::hideEvent(ev);
259}
260
261void MicroProfileWidget::mouseMoveEvent(QMouseEvent* ev) {
262 MicroProfileMousePosition(ev->x(), ev->y(), 0);
263 ev->accept();
264}
265
266void MicroProfileWidget::mousePressEvent(QMouseEvent* ev) {
267 MicroProfileMousePosition(ev->x(), ev->y(), 0);
268 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
269 ev->accept();
270}
271
272void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) {
273 MicroProfileMousePosition(ev->x(), ev->y(), 0);
274 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
275 ev->accept();
276}
277
278void MicroProfileWidget::wheelEvent(QWheelEvent* ev) {
279 MicroProfileMousePosition(ev->x(), ev->y(), ev->delta() / 120);
280 ev->accept();
281}
282
283void MicroProfileWidget::keyPressEvent(QKeyEvent* ev) {
284 if (ev->key() == Qt::Key_Control) {
285 // Inform MicroProfile that the user is holding Ctrl.
286 MicroProfileModKey(1);
287 }
288 QWidget::keyPressEvent(ev);
289}
290
291void MicroProfileWidget::keyReleaseEvent(QKeyEvent* ev) {
292 if (ev->key() == Qt::Key_Control) {
293 MicroProfileModKey(0);
294 }
295 QWidget::keyReleaseEvent(ev);
296}
297
298// These functions are called by MicroProfileDraw to draw the interface elements on the screen.
299
300void MicroProfileDrawText(int x, int y, u32 hex_color, const char* text, u32 text_length) {
301 // hex_color does not include an alpha, so it must be assumed to be 255
302 mp_painter->setPen(QColor::fromRgb(hex_color));
303
304 // It's impossible to draw a string using a monospaced font with a fixed width per cell in a
305 // way that's reliable across different platforms and fonts as far as I (yuriks) can tell, so
306 // draw each character individually in order to precisely control the text advance.
307 for (u32 i = 0; i < text_length; ++i) {
308 // Position the text baseline 1 pixel above the bottom of the text cell, this gives nice
309 // vertical alignment of text for a wide range of tested fonts.
310 mp_painter->drawText(x, y + MICROPROFILE_TEXT_HEIGHT - 2, QChar(text[i]));
311 x += MICROPROFILE_TEXT_WIDTH + 1;
312 }
313}
314
315void MicroProfileDrawBox(int left, int top, int right, int bottom, u32 hex_color, MicroProfileBoxType type) {
316 QColor color = QColor::fromRgba(hex_color);
317 QBrush brush = color;
318 if (type == MicroProfileBoxTypeBar) {
319 QLinearGradient gradient(left, top, left, bottom);
320 gradient.setColorAt(0.f, color.lighter(125));
321 gradient.setColorAt(1.f, color.darker(125));
322 brush = gradient;
323 }
324 mp_painter->fillRect(left, top, right - left, bottom - top, brush);
325}
326
327void MicroProfileDrawLine2D(u32 vertices_length, float* vertices, u32 hex_color) {
328 // Temporary vector used to convert between the float array and QPointF. Marked static to reuse
329 // the allocation across calls.
330 static std::vector<QPointF> point_buf;
331
332 for (u32 i = 0; i < vertices_length; ++i) {
333 point_buf.emplace_back(vertices[i*2 + 0], vertices[i*2 + 1]);
334 }
335
336 // hex_color does not include an alpha, so it must be assumed to be 255
337 mp_painter->setPen(QColor::fromRgb(hex_color));
338 mp_painter->drawPolyline(point_buf.data(), vertices_length);
339 point_buf.clear();
340}