summaryrefslogtreecommitdiff
path: root/src/citra_qt/debugger/graphics_framebuffer.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2016-06-07 18:26:24 -0400
committerGravatar bunnei2016-06-07 18:26:24 -0400
commit98b1436b8bcbcf2b130b4b8d660e2c4f7ac1abe4 (patch)
tree150839a42b9b6458fe228b84b2405d4fc1f163df /src/citra_qt/debugger/graphics_framebuffer.cpp
parentMerge pull request #1873 from archshift/remove-config (diff)
parentcitra_qt: Replace 'Pica Framebuffer Debugger' with 'Pica Surface Viewer' (diff)
downloadyuzu-98b1436b8bcbcf2b130b4b8d660e2c4f7ac1abe4.tar.gz
yuzu-98b1436b8bcbcf2b130b4b8d660e2c4f7ac1abe4.tar.xz
yuzu-98b1436b8bcbcf2b130b4b8d660e2c4f7ac1abe4.zip
Merge pull request #1765 from JayFoxRox/debug-surface-viewer
Debugger: Pica surface viewer
Diffstat (limited to 'src/citra_qt/debugger/graphics_framebuffer.cpp')
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp356
1 files changed, 0 insertions, 356 deletions
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
deleted file mode 100644
index 68cff78b2..000000000
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
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 <QBoxLayout>
6#include <QComboBox>
7#include <QDebug>
8#include <QLabel>
9#include <QPushButton>
10#include <QSpinBox>
11
12#include "citra_qt/debugger/graphics_framebuffer.h"
13#include "citra_qt/util/spinbox.h"
14
15#include "common/color.h"
16
17#include "core/memory.h"
18#include "core/hw/gpu.h"
19
20#include "video_core/pica.h"
21#include "video_core/pica_state.h"
22#include "video_core/utils.h"
23
24GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context,
25 QWidget* parent)
26 : BreakPointObserverDock(debug_context, tr("Pica Framebuffer"), parent),
27 framebuffer_source(Source::PicaTarget)
28{
29 setObjectName("PicaFramebuffer");
30
31 framebuffer_source_list = new QComboBox;
32 framebuffer_source_list->addItem(tr("Active Render Target"));
33 framebuffer_source_list->addItem(tr("Active Depth Buffer"));
34 framebuffer_source_list->addItem(tr("Custom"));
35 framebuffer_source_list->setCurrentIndex(static_cast<int>(framebuffer_source));
36
37 framebuffer_address_control = new CSpinBox;
38 framebuffer_address_control->SetBase(16);
39 framebuffer_address_control->SetRange(0, 0xFFFFFFFF);
40 framebuffer_address_control->SetPrefix("0x");
41
42 framebuffer_width_control = new QSpinBox;
43 framebuffer_width_control->setMinimum(1);
44 framebuffer_width_control->setMaximum(std::numeric_limits<int>::max()); // TODO: Find actual maximum
45
46 framebuffer_height_control = new QSpinBox;
47 framebuffer_height_control->setMinimum(1);
48 framebuffer_height_control->setMaximum(std::numeric_limits<int>::max()); // TODO: Find actual maximum
49
50 framebuffer_format_control = new QComboBox;
51 framebuffer_format_control->addItem(tr("RGBA8"));
52 framebuffer_format_control->addItem(tr("RGB8"));
53 framebuffer_format_control->addItem(tr("RGB5A1"));
54 framebuffer_format_control->addItem(tr("RGB565"));
55 framebuffer_format_control->addItem(tr("RGBA4"));
56 framebuffer_format_control->addItem(tr("D16"));
57 framebuffer_format_control->addItem(tr("D24"));
58 framebuffer_format_control->addItem(tr("D24X8"));
59 framebuffer_format_control->addItem(tr("X24S8"));
60 framebuffer_format_control->addItem(tr("(unknown)"));
61
62 // TODO: This QLabel should shrink the image to the available space rather than just expanding...
63 framebuffer_picture_label = new QLabel;
64
65 auto enlarge_button = new QPushButton(tr("Enlarge"));
66
67 // Connections
68 connect(this, SIGNAL(Update()), this, SLOT(OnUpdate()));
69 connect(framebuffer_source_list, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFramebufferSourceChanged(int)));
70 connect(framebuffer_address_control, SIGNAL(ValueChanged(qint64)), this, SLOT(OnFramebufferAddressChanged(qint64)));
71 connect(framebuffer_width_control, SIGNAL(valueChanged(int)), this, SLOT(OnFramebufferWidthChanged(int)));
72 connect(framebuffer_height_control, SIGNAL(valueChanged(int)), this, SLOT(OnFramebufferHeightChanged(int)));
73 connect(framebuffer_format_control, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFramebufferFormatChanged(int)));
74
75 auto main_widget = new QWidget;
76 auto main_layout = new QVBoxLayout;
77 {
78 auto sub_layout = new QHBoxLayout;
79 sub_layout->addWidget(new QLabel(tr("Source:")));
80 sub_layout->addWidget(framebuffer_source_list);
81 main_layout->addLayout(sub_layout);
82 }
83 {
84 auto sub_layout = new QHBoxLayout;
85 sub_layout->addWidget(new QLabel(tr("Virtual Address:")));
86 sub_layout->addWidget(framebuffer_address_control);
87 main_layout->addLayout(sub_layout);
88 }
89 {
90 auto sub_layout = new QHBoxLayout;
91 sub_layout->addWidget(new QLabel(tr("Width:")));
92 sub_layout->addWidget(framebuffer_width_control);
93 main_layout->addLayout(sub_layout);
94 }
95 {
96 auto sub_layout = new QHBoxLayout;
97 sub_layout->addWidget(new QLabel(tr("Height:")));
98 sub_layout->addWidget(framebuffer_height_control);
99 main_layout->addLayout(sub_layout);
100 }
101 {
102 auto sub_layout = new QHBoxLayout;
103 sub_layout->addWidget(new QLabel(tr("Format:")));
104 sub_layout->addWidget(framebuffer_format_control);
105 main_layout->addLayout(sub_layout);
106 }
107 main_layout->addWidget(framebuffer_picture_label);
108 main_layout->addWidget(enlarge_button);
109 main_widget->setLayout(main_layout);
110 setWidget(main_widget);
111
112 // Load current data - TODO: Make sure this works when emulation is not running
113 if (debug_context && debug_context->at_breakpoint)
114 emit Update();
115 widget()->setEnabled(false); // TODO: Only enable if currently at breakpoint
116}
117
118void GraphicsFramebufferWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data)
119{
120 emit Update();
121 widget()->setEnabled(true);
122}
123
124void GraphicsFramebufferWidget::OnResumed()
125{
126 widget()->setEnabled(false);
127}
128
129void GraphicsFramebufferWidget::OnFramebufferSourceChanged(int new_value)
130{
131 framebuffer_source = static_cast<Source>(new_value);
132 emit Update();
133}
134
135void GraphicsFramebufferWidget::OnFramebufferAddressChanged(qint64 new_value)
136{
137 if (framebuffer_address != new_value) {
138 framebuffer_address = static_cast<unsigned>(new_value);
139
140 framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
141 emit Update();
142 }
143}
144
145void GraphicsFramebufferWidget::OnFramebufferWidthChanged(int new_value)
146{
147 if (framebuffer_width != static_cast<unsigned>(new_value)) {
148 framebuffer_width = static_cast<unsigned>(new_value);
149
150 framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
151 emit Update();
152 }
153}
154
155void GraphicsFramebufferWidget::OnFramebufferHeightChanged(int new_value)
156{
157 if (framebuffer_height != static_cast<unsigned>(new_value)) {
158 framebuffer_height = static_cast<unsigned>(new_value);
159
160 framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
161 emit Update();
162 }
163}
164
165void GraphicsFramebufferWidget::OnFramebufferFormatChanged(int new_value)
166{
167 if (framebuffer_format != static_cast<Format>(new_value)) {
168 framebuffer_format = static_cast<Format>(new_value);
169
170 framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
171 emit Update();
172 }
173}
174
175void GraphicsFramebufferWidget::OnUpdate()
176{
177 QPixmap pixmap;
178
179 switch (framebuffer_source) {
180 case Source::PicaTarget:
181 {
182 // TODO: Store a reference to the registers in the debug context instead of accessing them directly...
183
184 const auto& framebuffer = Pica::g_state.regs.framebuffer;
185
186 framebuffer_address = framebuffer.GetColorBufferPhysicalAddress();
187 framebuffer_width = framebuffer.GetWidth();
188 framebuffer_height = framebuffer.GetHeight();
189
190 switch (framebuffer.color_format) {
191 case Pica::Regs::ColorFormat::RGBA8:
192 framebuffer_format = Format::RGBA8;
193 break;
194
195 case Pica::Regs::ColorFormat::RGB8:
196 framebuffer_format = Format::RGB8;
197 break;
198
199 case Pica::Regs::ColorFormat::RGB5A1:
200 framebuffer_format = Format::RGB5A1;
201 break;
202
203 case Pica::Regs::ColorFormat::RGB565:
204 framebuffer_format = Format::RGB565;
205 break;
206
207 case Pica::Regs::ColorFormat::RGBA4:
208 framebuffer_format = Format::RGBA4;
209 break;
210
211 default:
212 framebuffer_format = Format::Unknown;
213 break;
214 }
215
216 break;
217 }
218
219 case Source::DepthBuffer:
220 {
221 const auto& framebuffer = Pica::g_state.regs.framebuffer;
222
223 framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress();
224 framebuffer_width = framebuffer.GetWidth();
225 framebuffer_height = framebuffer.GetHeight();
226
227 switch (framebuffer.depth_format) {
228 case Pica::Regs::DepthFormat::D16:
229 framebuffer_format = Format::D16;
230 break;
231
232 case Pica::Regs::DepthFormat::D24:
233 framebuffer_format = Format::D24;
234 break;
235
236 case Pica::Regs::DepthFormat::D24S8:
237 framebuffer_format = Format::D24X8;
238 break;
239
240 default:
241 framebuffer_format = Format::Unknown;
242 break;
243 }
244
245 break;
246 }
247
248 case Source::Custom:
249 {
250 // Keep user-specified values
251 break;
252 }
253
254 default:
255 qDebug() << "Unknown framebuffer source " << static_cast<int>(framebuffer_source);
256 break;
257 }
258
259 // TODO: Implement a good way to visualize alpha components!
260 // TODO: Unify this decoding code with the texture decoder
261 u32 bytes_per_pixel = GraphicsFramebufferWidget::BytesPerPixel(framebuffer_format);
262
263 QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32);
264 u8* buffer = Memory::GetPhysicalPointer(framebuffer_address);
265
266 for (unsigned int y = 0; y < framebuffer_height; ++y) {
267 for (unsigned int x = 0; x < framebuffer_width; ++x) {
268 const u32 coarse_y = y & ~7;
269 u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer_width * bytes_per_pixel;
270 const u8* pixel = buffer + offset;
271 Math::Vec4<u8> color = { 0, 0, 0, 0 };
272
273 switch (framebuffer_format) {
274 case Format::RGBA8:
275 color = Color::DecodeRGBA8(pixel);
276 break;
277 case Format::RGB8:
278 color = Color::DecodeRGB8(pixel);
279 break;
280 case Format::RGB5A1:
281 color = Color::DecodeRGB5A1(pixel);
282 break;
283 case Format::RGB565:
284 color = Color::DecodeRGB565(pixel);
285 break;
286 case Format::RGBA4:
287 color = Color::DecodeRGBA4(pixel);
288 break;
289 case Format::D16:
290 {
291 u32 data = Color::DecodeD16(pixel);
292 color.r() = data & 0xFF;
293 color.g() = (data >> 8) & 0xFF;
294 break;
295 }
296 case Format::D24:
297 {
298 u32 data = Color::DecodeD24(pixel);
299 color.r() = data & 0xFF;
300 color.g() = (data >> 8) & 0xFF;
301 color.b() = (data >> 16) & 0xFF;
302 break;
303 }
304 case Format::D24X8:
305 {
306 Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
307 color.r() = data.x & 0xFF;
308 color.g() = (data.x >> 8) & 0xFF;
309 color.b() = (data.x >> 16) & 0xFF;
310 break;
311 }
312 case Format::X24S8:
313 {
314 Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
315 color.r() = color.g() = color.b() = data.y;
316 break;
317 }
318 default:
319 qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format);
320 break;
321 }
322
323 decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), 255));
324 }
325 }
326 pixmap = QPixmap::fromImage(decoded_image);
327
328 framebuffer_address_control->SetValue(framebuffer_address);
329 framebuffer_width_control->setValue(framebuffer_width);
330 framebuffer_height_control->setValue(framebuffer_height);
331 framebuffer_format_control->setCurrentIndex(static_cast<int>(framebuffer_format));
332 framebuffer_picture_label->setPixmap(pixmap);
333}
334
335u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) {
336 switch (format) {
337 case Format::RGBA8:
338 case Format::D24X8:
339 case Format::X24S8:
340 return 4;
341 case Format::RGB8:
342 case Format::D24:
343 return 3;
344 case Format::RGB5A1:
345 case Format::RGB565:
346 case Format::RGBA4:
347 case Format::D16:
348 return 2;
349 default:
350 UNREACHABLE_MSG("GraphicsFramebufferWidget::BytesPerPixel: this "
351 "should not be reached as this function should "
352 "be given a format which is in "
353 "GraphicsFramebufferWidget::Format. Instead got %i",
354 static_cast<int>(format));
355 }
356}