summaryrefslogtreecommitdiff
path: root/src/citra_qt/debugger/graphics/graphics_tracing.cpp
diff options
context:
space:
mode:
authorGravatar Lioncash2016-12-21 17:19:12 -0500
committerGravatar Lioncash2016-12-21 17:19:21 -0500
commit8309d0dade37684076ad530bfbca5d4ffc6d1f4d (patch)
treec7eb1050f664df4aad518c55b6648807b0cef2db /src/citra_qt/debugger/graphics/graphics_tracing.cpp
parentMerge pull request #2319 from yuriks/profile-scopes (diff)
downloadyuzu-8309d0dade37684076ad530bfbca5d4ffc6d1f4d.tar.gz
yuzu-8309d0dade37684076ad530bfbca5d4ffc6d1f4d.tar.xz
yuzu-8309d0dade37684076ad530bfbca5d4ffc6d1f4d.zip
citra-qt: Move graphics debugging code into its own folder
Keeps all graphics debugging stuff from cluttering up the root debugger folder
Diffstat (limited to 'src/citra_qt/debugger/graphics/graphics_tracing.cpp')
-rw-r--r--src/citra_qt/debugger/graphics/graphics_tracing.cpp178
1 files changed, 178 insertions, 0 deletions
diff --git a/src/citra_qt/debugger/graphics/graphics_tracing.cpp b/src/citra_qt/debugger/graphics/graphics_tracing.cpp
new file mode 100644
index 000000000..716ed50b8
--- /dev/null
+++ b/src/citra_qt/debugger/graphics/graphics_tracing.cpp
@@ -0,0 +1,178 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <array>
7#include <iterator>
8#include <memory>
9#include <QBoxLayout>
10#include <QComboBox>
11#include <QFileDialog>
12#include <QMessageBox>
13#include <QPushButton>
14#include <boost/range/algorithm/copy.hpp>
15#include "citra_qt/debugger/graphics/graphics_tracing.h"
16#include "common/common_types.h"
17#include "core/hw/gpu.h"
18#include "core/hw/lcd.h"
19#include "core/tracer/recorder.h"
20#include "nihstro/float24.h"
21#include "video_core/pica.h"
22#include "video_core/pica_state.h"
23
24GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
25 QWidget* parent)
26 : BreakPointObserverDock(debug_context, tr("CiTrace Recorder"), parent) {
27
28 setObjectName("CiTracing");
29
30 QPushButton* start_recording = new QPushButton(tr("Start Recording"));
31 QPushButton* stop_recording =
32 new QPushButton(QIcon::fromTheme("document-save"), tr("Stop and Save"));
33 QPushButton* abort_recording = new QPushButton(tr("Abort Recording"));
34
35 connect(this, SIGNAL(SetStartTracingButtonEnabled(bool)), start_recording,
36 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)));
41 connect(start_recording, SIGNAL(clicked()), this, SLOT(StartRecording()));
42 connect(stop_recording, SIGNAL(clicked()), this, SLOT(StopRecording()));
43 connect(abort_recording, SIGNAL(clicked()), this, SLOT(AbortRecording()));
44
45 stop_recording->setVisible(false);
46 abort_recording->setVisible(false);
47
48 auto main_widget = new QWidget;
49 auto main_layout = new QVBoxLayout;
50 {
51 auto sub_layout = new QHBoxLayout;
52 sub_layout->addWidget(start_recording);
53 sub_layout->addWidget(stop_recording);
54 sub_layout->addWidget(abort_recording);
55 main_layout->addLayout(sub_layout);
56 }
57 main_widget->setLayout(main_layout);
58 setWidget(main_widget);
59}
60
61void GraphicsTracingWidget::StartRecording() {
62 auto context = context_weak.lock();
63 if (!context)
64 return;
65
66 auto shader_binary = Pica::g_state.vs.program_code;
67 auto swizzle_data = Pica::g_state.vs.swizzle_data;
68
69 // Encode floating point numbers to 24-bit values
70 // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally.
71 std::array<u32, 4 * 16> default_attributes;
72 for (unsigned i = 0; i < 16; ++i) {
73 for (unsigned comp = 0; comp < 3; ++comp) {
74 default_attributes[4 * i + comp] =
75 nihstro::to_float24(Pica::g_state.vs_default_attributes[i][comp].ToFloat32());
76 }
77 }
78
79 std::array<u32, 4 * 96> vs_float_uniforms;
80 for (unsigned i = 0; i < 96; ++i)
81 for (unsigned comp = 0; comp < 3; ++comp)
82 vs_float_uniforms[4 * i + comp] =
83 nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32());
84
85 CiTrace::Recorder::InitialState state;
86 std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32),
87 std::back_inserter(state.gpu_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));
92 boost::copy(default_attributes, std::back_inserter(state.default_attributes));
93 boost::copy(shader_binary, std::back_inserter(state.vs_program_binary));
94 boost::copy(swizzle_data, std::back_inserter(state.vs_swizzle_data));
95 boost::copy(vs_float_uniforms, std::back_inserter(state.vs_float_uniforms));
96 // boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary));
97 // boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data));
98 // boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms));
99
100 auto recorder = new CiTrace::Recorder(state);
101 context->recorder = std::shared_ptr<CiTrace::Recorder>(recorder);
102
103 emit SetStartTracingButtonEnabled(false);
104 emit SetStopTracingButtonEnabled(true);
105 emit SetAbortTracingButtonEnabled(true);
106}
107
108void GraphicsTracingWidget::StopRecording() {
109 auto context = context_weak.lock();
110 if (!context)
111 return;
112
113 QString filename = QFileDialog::getSaveFileName(this, tr("Save CiTrace"), "citrace.ctf",
114 tr("CiTrace File (*.ctf)"));
115
116 if (filename.isEmpty()) {
117 // If the user canceled the dialog, keep recording
118 return;
119 }
120
121 context->recorder->Finish(filename.toStdString());
122 context->recorder = nullptr;
123
124 emit SetStopTracingButtonEnabled(false);
125 emit SetAbortTracingButtonEnabled(false);
126 emit SetStartTracingButtonEnabled(true);
127}
128
129void GraphicsTracingWidget::AbortRecording() {
130 auto context = context_weak.lock();
131 if (!context)
132 return;
133
134 context->recorder = nullptr;
135
136 emit SetStopTracingButtonEnabled(false);
137 emit SetAbortTracingButtonEnabled(false);
138 emit SetStartTracingButtonEnabled(true);
139}
140
141void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
142 widget()->setEnabled(true);
143}
144
145void GraphicsTracingWidget::OnResumed() {
146 widget()->setEnabled(false);
147}
148
149void GraphicsTracingWidget::OnEmulationStarting(EmuThread* emu_thread) {
150 // Disable tracing starting/stopping until a GPU breakpoint is reached
151 widget()->setEnabled(false);
152}
153
154void GraphicsTracingWidget::OnEmulationStopping() {
155 // TODO: Is it safe to access the context here?
156
157 auto context = context_weak.lock();
158 if (!context)
159 return;
160
161 if (context->recorder) {
162 auto reply =
163 QMessageBox::question(this, tr("CiTracing still active"),
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);
167
168 if (reply == QMessageBox::Yes) {
169 StopRecording();
170 } else {
171 AbortRecording();
172 }
173 }
174
175 // If the widget was disabled before, enable it now to allow starting
176 // tracing before starting the next emulation session
177 widget()->setEnabled(true);
178}