summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Tony Wasserka2014-08-16 14:06:40 +0200
committerGravatar Tony Wasserka2014-08-25 22:03:18 +0200
commitc4691b784bd7746c5845df00a82ea0909b37ec0f (patch)
tree635fa4cea0fa7c487217c8799cb90c45ebc12841 /src
parentPica/Math: Improved the design of the Vec2/Vec3/Vec4 classes and simplified r... (diff)
downloadyuzu-c4691b784bd7746c5845df00a82ea0909b37ec0f.tar.gz
yuzu-c4691b784bd7746c5845df00a82ea0909b37ec0f.tar.xz
yuzu-c4691b784bd7746c5845df00a82ea0909b37ec0f.zip
Pica: Add support for dumping textures.
Diffstat (limited to 'src')
-rw-r--r--src/citra/CMakeLists.txt2
-rw-r--r--src/citra_qt/CMakeLists.txt2
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp131
-rw-r--r--src/video_core/debug_utils/debug_utils.h2
-rw-r--r--src/video_core/pica.h45
5 files changed, 179 insertions, 3 deletions
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt
index b1ab67598..1cbe22cc0 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -12,7 +12,7 @@ add_executable(citra ${SRCS} ${HEADERS})
12if (APPLE) 12if (APPLE)
13 target_link_libraries(citra core common video_core iconv pthread ${COREFOUNDATION_LIBRARY} ${OPENGL_LIBRARIES} ${GLEW_LIBRARY} ${GLFW_LIBRARIES}) 13 target_link_libraries(citra core common video_core iconv pthread ${COREFOUNDATION_LIBRARY} ${OPENGL_LIBRARIES} ${GLEW_LIBRARY} ${GLFW_LIBRARIES})
14else() 14else()
15 target_link_libraries(citra core common video_core GLEW pthread X11 Xxf86vm Xi Xcursor ${OPENGL_LIBRARIES} ${GLFW_LIBRARIES} rt ${X11_Xrandr_LIB} ${X11_xv86vmode_LIB}) 15 target_link_libraries(citra core common video_core GLEW pthread X11 Xxf86vm Xi Xcursor ${OPENGL_LIBRARIES} ${GLFW_LIBRARIES} rt ${X11_Xrandr_LIB} ${X11_xv86vmode_LIB} ${PNG_LIBRARIES})
16endif() 16endif()
17 17
18#install(TARGETS citra RUNTIME DESTINATION ${bindir}) 18#install(TARGETS citra RUNTIME DESTINATION ${bindir})
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index ff1fbc460..8ad6759b7 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -47,7 +47,7 @@ else()
47 set(RT_LIBRARY rt) 47 set(RT_LIBRARY rt)
48endif() 48endif()
49 49
50target_link_libraries(citra-qt core common video_core qhexedit ${ICONV_LIBRARY} ${COREFOUNDATION_LIBRARY} ${QT_LIBRARIES} ${OPENGL_LIBRARIES} ${RT_LIBRARY} ${GLEW_LIBRARY}) 50target_link_libraries(citra-qt core common video_core qhexedit ${ICONV_LIBRARY} ${COREFOUNDATION_LIBRARY} ${QT_LIBRARIES} ${OPENGL_LIBRARIES} ${RT_LIBRARY} ${GLEW_LIBRARY} ${PNG_LIBRARIES})
51if(USE_QT5) 51if(USE_QT5)
52 target_link_libraries(citra-qt Qt5::Gui Qt5::Widgets Qt5::OpenGL) 52 target_link_libraries(citra-qt Qt5::Gui Qt5::Widgets Qt5::OpenGL)
53endif() 53endif()
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 1bbc0330c..753de41e8 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -3,10 +3,17 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <map>
6#include <fstream> 7#include <fstream>
7#include <mutex> 8#include <mutex>
8#include <string> 9#include <string>
9 10
11#ifdef HAVE_PNG
12#include <png.h>
13#endif
14
15#include "common/file_util.h"
16
10#include "video_core/pica.h" 17#include "video_core/pica.h"
11 18
12#include "debug_utils.h" 19#include "debug_utils.h"
@@ -315,6 +322,130 @@ std::unique_ptr<PicaTrace> FinishPicaTracing()
315 return std::move(ret); 322 return std::move(ret);
316} 323}
317 324
325void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
326 // NOTE: Permanently enabling this just trashes hard disks for no reason.
327 // Hence, this is currently disabled.
328 return;
329
330#ifndef HAVE_PNG
331 return;
332#else
333 if (!data)
334 return;
335
336 // Write data to file
337 static int dump_index = 0;
338 std::string filename = std::string("texture_dump") + std::to_string(++dump_index) + std::string(".png");
339 u32 row_stride = texture_config.width * 3;
340
341 u8* buf;
342
343 char title[] = "Citra texture dump";
344 char title_key[] = "Title";
345 png_structp png_ptr = nullptr;
346 png_infop info_ptr = nullptr;
347
348 // Open file for writing (binary mode)
349 File::IOFile fp(filename, "wb");
350
351 // Initialize write structure
352 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
353 if (png_ptr == nullptr) {
354 ERROR_LOG(GPU, "Could not allocate write struct\n");
355 goto finalise;
356
357 }
358
359 // Initialize info structure
360 info_ptr = png_create_info_struct(png_ptr);
361 if (info_ptr == nullptr) {
362 ERROR_LOG(GPU, "Could not allocate info struct\n");
363 goto finalise;
364 }
365
366 // Setup Exception handling
367 if (setjmp(png_jmpbuf(png_ptr))) {
368 ERROR_LOG(GPU, "Error during png creation\n");
369 goto finalise;
370 }
371
372 png_init_io(png_ptr, fp.GetHandle());
373
374 // Write header (8 bit colour depth)
375 png_set_IHDR(png_ptr, info_ptr, texture_config.width, texture_config.height,
376 8, PNG_COLOR_TYPE_RGB /*_ALPHA*/, PNG_INTERLACE_NONE,
377 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
378
379 png_text title_text;
380 title_text.compression = PNG_TEXT_COMPRESSION_NONE;
381 title_text.key = title_key;
382 title_text.text = title;
383 png_set_text(png_ptr, info_ptr, &title_text, 1);
384
385 png_write_info(png_ptr, info_ptr);
386
387 buf = new u8[row_stride * texture_config.height];
388 for (int y = 0; y < texture_config.height; ++y) {
389 for (int x = 0; x < texture_config.width; ++x) {
390 // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each
391 // of which is composed of four 2x2 subtiles each of which is composed of four texels.
392 // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g.
393 // texels are laid out in a 2x2 subtile like this:
394 // 2 3
395 // 0 1
396 //
397 // The full 8x8 tile has the texels arranged like this:
398 //
399 // 42 43 46 47 58 59 62 63
400 // 40 41 44 45 56 57 60 61
401 // 34 35 38 39 50 51 54 55
402 // 32 33 36 37 48 49 52 53
403 // 10 11 14 15 26 27 30 31
404 // 08 09 12 13 24 25 28 29
405 // 02 03 06 07 18 19 22 23
406 // 00 01 04 05 16 17 20 21
407 int texel_index_within_tile = 0;
408 for (int block_size_index = 0; block_size_index < 3; ++block_size_index) {
409 int sub_tile_width = 1 << block_size_index;
410 int sub_tile_height = 1 << block_size_index;
411
412 int sub_tile_index = (x & sub_tile_width) << block_size_index;
413 sub_tile_index += 2 * ((y & sub_tile_height) << block_size_index);
414 texel_index_within_tile += sub_tile_index;
415 }
416
417 const int block_width = 8;
418 const int block_height = 8;
419
420 int coarse_x = (x / block_width) * block_width;
421 int coarse_y = (y / block_height) * block_height;
422
423 u8* source_ptr = (u8*)data + coarse_x * block_height * 3 + coarse_y * row_stride + texel_index_within_tile * 3;
424 buf[3 * x + y * row_stride ] = source_ptr[2];
425 buf[3 * x + y * row_stride + 1] = source_ptr[1];
426 buf[3 * x + y * row_stride + 2] = source_ptr[0];
427 }
428 }
429
430 // Write image data
431 for (auto y = 0; y < texture_config.height; ++y)
432 {
433 u8* row_ptr = (u8*)buf + y * row_stride;
434 u8* ptr = row_ptr;
435 png_write_row(png_ptr, row_ptr);
436 }
437
438 delete[] buf;
439
440 // End write
441 png_write_end(png_ptr, nullptr);
442
443finalise:
444 if (info_ptr != nullptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
445 if (png_ptr != nullptr) png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
446#endif
447}
448
318} // namespace 449} // namespace
319 450
320} // namespace 451} // namespace
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 023500066..49b19b28a 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -59,6 +59,8 @@ bool IsPicaTracing();
59void OnPicaRegWrite(u32 id, u32 value); 59void OnPicaRegWrite(u32 id, u32 value);
60std::unique_ptr<PicaTrace> FinishPicaTracing(); 60std::unique_ptr<PicaTrace> FinishPicaTracing();
61 61
62void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data);
63
62} // namespace 64} // namespace
63 65
64} // namespace 66} // namespace
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index fe886c16f..f288615b8 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -94,7 +94,46 @@ struct Regs {
94 BitField<16, 16, u32> y; 94 BitField<16, 16, u32> y;
95 } viewport_corner; 95 } viewport_corner;
96 96
97 INSERT_PADDING_WORDS(0xa7); 97 INSERT_PADDING_WORDS(0x18);
98
99 struct TextureConfig {
100 INSERT_PADDING_WORDS(0x1);
101
102 union {
103 BitField< 0, 16, u32> height;
104 BitField<16, 16, u32> width;
105 };
106
107 INSERT_PADDING_WORDS(0x2);
108
109 u32 address;
110
111 u32 GetPhysicalAddress() {
112 return DecodeAddressRegister(address) - Memory::FCRAM_PADDR + Memory::HEAP_GSP_VADDR;
113 }
114
115 // texture1 and texture2 store the texture format directly after the address
116 // whereas texture0 inserts some additional flags inbetween.
117 // Hence, we store the format separately so that all other parameters can be described
118 // in a single structure.
119 };
120
121 enum class TextureFormat : u32 {
122 RGBA8 = 0,
123 RGB8 = 1,
124 RGBA5551 = 2,
125 RGB565 = 3,
126 RGBA4 = 4,
127
128 // TODO: Support for the other formats is not implemented, yet.
129 // Seems like they are luminance formats and compressed textures.
130 };
131
132 TextureConfig texture0;
133 INSERT_PADDING_WORDS(0x8);
134 BitField<0, 4, TextureFormat> texture0_format;
135
136 INSERT_PADDING_WORDS(0x81);
98 137
99 struct { 138 struct {
100 enum ColorFormat : u32 { 139 enum ColorFormat : u32 {
@@ -403,6 +442,8 @@ struct Regs {
403 ADD_FIELD(viewport_depth_range); 442 ADD_FIELD(viewport_depth_range);
404 ADD_FIELD(viewport_depth_far_plane); 443 ADD_FIELD(viewport_depth_far_plane);
405 ADD_FIELD(viewport_corner); 444 ADD_FIELD(viewport_corner);
445 ADD_FIELD(texture0);
446 ADD_FIELD(texture0_format);
406 ADD_FIELD(framebuffer); 447 ADD_FIELD(framebuffer);
407 ADD_FIELD(vertex_attributes); 448 ADD_FIELD(vertex_attributes);
408 ADD_FIELD(index_array); 449 ADD_FIELD(index_array);
@@ -460,6 +501,8 @@ ASSERT_REG_POSITION(viewport_depth_far_plane, 0x4e);
460ASSERT_REG_POSITION(vs_output_attributes[0], 0x50); 501ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);
461ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); 502ASSERT_REG_POSITION(vs_output_attributes[1], 0x51);
462ASSERT_REG_POSITION(viewport_corner, 0x68); 503ASSERT_REG_POSITION(viewport_corner, 0x68);
504ASSERT_REG_POSITION(texture0, 0x81);
505ASSERT_REG_POSITION(texture0_format, 0x8e);
463ASSERT_REG_POSITION(framebuffer, 0x110); 506ASSERT_REG_POSITION(framebuffer, 0x110);
464ASSERT_REG_POSITION(vertex_attributes, 0x200); 507ASSERT_REG_POSITION(vertex_attributes, 0x200);
465ASSERT_REG_POSITION(index_array, 0x227); 508ASSERT_REG_POSITION(index_array, 0x227);