diff --git a/src/pse/gpu.cpp b/src/pse/gpu.cpp index c227cf080..5a8345250 100644 --- a/src/pse/gpu.cpp +++ b/src/pse/gpu.cpp @@ -3,9 +3,15 @@ #include "common/state_wrapper.h" #include "dma.h" #include "interrupt_controller.h" +#include "stb_image_write.h" #include "system.h" Log_SetChannel(GPU); +bool GPU::DUMP_CPU_TO_VRAM_COPIES = false; +bool GPU::DUMP_VRAM_TO_CPU_COPIES = false; +static u32 s_cpu_to_vram_dump_id = 1; +static u32 s_vram_to_cpu_dump_id = 1; + GPU::GPU() = default; GPU::~GPU() = default; @@ -644,6 +650,12 @@ bool GPU::HandleCopyRectangleCPUToVRAMCommand() return true; } + if (DUMP_CPU_TO_VRAM_COPIES) + { + DumpVRAMToFile(SmallString::FromFormat("cpu_to_vram_copy_%u.png", s_cpu_to_vram_dump_id++), copy_width, copy_height, + sizeof(u16) * copy_width, &m_GP0_command[3], true); + } + FlushRender(); UpdateVRAM(dst_x, dst_y, copy_width, copy_height, &m_GP0_command[3]); return true; @@ -678,6 +690,12 @@ bool GPU::HandleCopyRectangleVRAMToCPUCommand() for (const u32 bits : temp) m_GPUREAD_buffer.push_back(bits); + if (DUMP_VRAM_TO_CPU_COPIES) + { + DumpVRAMToFile(SmallString::FromFormat("vram_to_cpu_copy_%u.png", s_cpu_to_vram_dump_id++), width, height, + sizeof(u16) * width, temp.data(), true); + } + // Is this correct? return true; } @@ -774,3 +792,26 @@ void GPU::TextureConfig::SetFromPaletteAttribute(u16 value) palette_attribute = value; page_changed = true; } + +bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha) +{ + std::vector rgba8_buf(width * height); + + const char* ptr_in = static_cast(buffer); + u32* ptr_out = rgba8_buf.data(); + for (u32 row = 0; row < height; row++) + { + const char* row_ptr_in = ptr_in; + + for (u32 col = 0; col < width; col++) + { + u16 src_col; + std::memcpy(&src_col, row_ptr_in, sizeof(u16)); + row_ptr_in += sizeof(u16); + *(ptr_out++) = RGBA5551ToRGBA8888(remove_alpha ? (src_col | u16(0x8000)) : src_col); + } + + ptr_in += stride; + } + return (stbi_write_png(filename, width, height, 4, rgba8_buf.data(), sizeof(u32) * width) != 0); +} diff --git a/src/pse/gpu.h b/src/pse/gpu.h index 1d63cbbd0..d5fd4025c 100644 --- a/src/pse/gpu.h +++ b/src/pse/gpu.h @@ -48,6 +48,36 @@ protected: return value; } + // Helper/format conversion functions. + static constexpr u32 RGBA5551ToRGBA8888(u16 color) + { + u8 r = Truncate8(color & 31); + u8 g = Truncate8((color >> 5) & 31); + u8 b = Truncate8((color >> 10) & 31); + u8 a = Truncate8((color >> 15) & 1); + + // 00012345 -> 1234545 + b = (b << 3) | (b & 0b111); + g = (g << 3) | (g & 0b111); + r = (r << 3) | (r & 0b111); + a = a ? 255 : 0; + + return ZeroExtend32(r) | (ZeroExtend32(g) << 8) | (ZeroExtend32(b) << 16) | (ZeroExtend32(a) << 24); + } + + static constexpr u16 RGBA8888ToRGBA5551(u32 color) + { + const u16 r = Truncate16((color >> 3) & 0x1Fu); + const u16 g = Truncate16((color >> 11) & 0x1Fu); + const u16 b = Truncate16((color >> 19) & 0x1Fu); + const u16 a = Truncate16((color >> 31) & 0x01u); + + return r | (g << 5) | (b << 10) | (a << 15); + } + + static bool DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, + bool remove_alpha); + enum class DMADirection : u32 { Off = 0, @@ -275,4 +305,8 @@ protected: std::vector m_GP0_command; std::deque m_GPUREAD_buffer; + + // debug options + static bool DUMP_CPU_TO_VRAM_COPIES; + static bool DUMP_VRAM_TO_CPU_COPIES; }; diff --git a/src/pse/gpu_hw.cpp b/src/pse/gpu_hw.cpp index 1cc25c35e..6ecfdfc0c 100644 --- a/src/pse/gpu_hw.cpp +++ b/src/pse/gpu_hw.cpp @@ -191,8 +191,8 @@ out vec4 v_col0; void main() { // 0..+1023 -> -1..1 - float pos_x = (float(a_pos.x) / 511.5) - 1.0; - float pos_y = (float(a_pos.y) / -255.5) + 1.0; + float pos_x = (float(a_pos.x) / 512.0) - 1.0; + float pos_y = (float(a_pos.y) / -256.0) + 1.0; gl_Position = vec4(pos_x, pos_y, 0.0, 1.0); v_col0 = a_col0; diff --git a/src/pse/gpu_hw_opengl.cpp b/src/pse/gpu_hw_opengl.cpp index 7c5df30bb..c0691832b 100644 --- a/src/pse/gpu_hw_opengl.cpp +++ b/src/pse/gpu_hw_opengl.cpp @@ -191,32 +191,6 @@ void GPU_HW_OpenGL::SetScissor() glScissor(x, y, width, height); } -inline u32 ConvertRGBA5551ToRGBA8888(u16 color) -{ - u8 r = Truncate8(color & 31); - u8 g = Truncate8((color >> 5) & 31); - u8 b = Truncate8((color >> 10) & 31); - u8 a = Truncate8((color >> 15) & 1); - - // 00012345 -> 1234545 - b = (b << 3) | (b & 0b111); - g = (g << 3) | (g & 0b111); - r = (r << 3) | (r & 0b111); - a = a ? 255 : 0; - - return ZeroExtend32(r) | (ZeroExtend32(g) << 8) | (ZeroExtend32(b) << 16) | (ZeroExtend32(a) << 24); -} - -inline u16 ConvertRGBA8888ToRGBA5551(u32 color) -{ - const u16 r = Truncate16((color >> 3) & 0x1Fu); - const u16 g = Truncate16((color >> 11) & 0x1Fu); - const u16 b = Truncate16((color >> 19) & 0x1Fu); - const u16 a = Truncate16((color >> 31) & 0x01u); - - return r | (g << 5) | (b << 10) | (a << 15); -} - void GPU_HW_OpenGL::UpdateDisplay() { GPU_HW::UpdateDisplay(); @@ -246,7 +220,7 @@ void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) std::memcpy(&src_col, source_row_ptr, sizeof(src_col)); source_row_ptr += sizeof(src_col); - const u16 dst_col = ConvertRGBA8888ToRGBA5551(src_col); + const u16 dst_col = RGBA8888ToRGBA5551(src_col); std::memcpy(dst_row_ptr, &dst_col, sizeof(dst_col)); dst_row_ptr += sizeof(dst_col); } @@ -286,7 +260,7 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* std::memcpy(&src_col, source_row_ptr, sizeof(src_col)); source_row_ptr += sizeof(src_col); - const u32 dst_col = ConvertRGBA5551ToRGBA8888(src_col); + const u32 dst_col = RGBA5551ToRGBA8888(src_col); rgba_data.push_back(dst_col); } diff --git a/src/pse/pse.vcxproj b/src/pse/pse.vcxproj index 2de5bf836..39a9efca8 100644 --- a/src/pse/pse.vcxproj +++ b/src/pse/pse.vcxproj @@ -70,6 +70,9 @@ {2f2a2b7b-60b3-478c-921e-3633b3c45c3f} + + {ed601289-ac1a-46b8-a8ed-17db9eb73423} + {b56ce698-7300-4fa5-9609-942f1d05c5a2} @@ -224,7 +227,7 @@ ENABLE_VOODOO=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -245,7 +248,7 @@ ENABLE_VOODOO=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -266,7 +269,7 @@ ENABLE_VOODOO=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) Default true false @@ -289,7 +292,7 @@ ENABLE_VOODOO=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) Default true false @@ -311,7 +314,7 @@ MaxSpeed true ENABLE_VOODOO=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -333,7 +336,7 @@ MaxSpeed true ENABLE_VOODOO=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true true stdcpp17 @@ -356,7 +359,7 @@ MaxSpeed true ENABLE_VOODOO=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -378,7 +381,7 @@ MaxSpeed true ENABLE_VOODOO=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\YBaseLib\Include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true true stdcpp17