diff options
Diffstat (limited to 'src/video_core/debug_utils')
| -rw-r--r-- | src/video_core/debug_utils/debug_utils.cpp | 131 | ||||
| -rw-r--r-- | src/video_core/debug_utils/debug_utils.h | 2 |
2 files changed, 133 insertions, 0 deletions
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 | ||
| 325 | void 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 | |||
| 443 | finalise: | ||
| 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(); | |||
| 59 | void OnPicaRegWrite(u32 id, u32 value); | 59 | void OnPicaRegWrite(u32 id, u32 value); |
| 60 | std::unique_ptr<PicaTrace> FinishPicaTracing(); | 60 | std::unique_ptr<PicaTrace> FinishPicaTracing(); |
| 61 | 61 | ||
| 62 | void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data); | ||
| 63 | |||
| 62 | } // namespace | 64 | } // namespace |
| 63 | 65 | ||
| 64 | } // namespace | 66 | } // namespace |