diff --git a/src/pse/gpu.cpp b/src/pse/gpu.cpp index c3222fa48..1e1032b86 100644 --- a/src/pse/gpu.cpp +++ b/src/pse/gpu.cpp @@ -66,6 +66,22 @@ bool GPU::DoState(StateWrapper& sw) UpdateGPUSTAT(); } + if (!sw.DoMarker("GPU-VRAM")) + return false; + + if (sw.IsReading()) + { + std::vector vram; + sw.Do(&vram); + UpdateVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT, vram.data()); + } + else + { + std::vector vram(VRAM_WIDTH * VRAM_HEIGHT); + ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT, vram.data()); + sw.Do(&vram); + } + return !sw.HasError(); } @@ -476,6 +492,8 @@ void GPU::UpdateDisplay() m_system->IncrementFrameNumber(); } +void GPU::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) {} + void GPU::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) {} void GPU::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) {} diff --git a/src/pse/gpu.h b/src/pse/gpu.h index 180f55883..c2631b756 100644 --- a/src/pse/gpu.h +++ b/src/pse/gpu.h @@ -122,6 +122,7 @@ protected: // Rendering in the backend virtual void UpdateDisplay(); + virtual void ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer); virtual void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color); virtual void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data); virtual void DispatchRenderCommand(RenderCommand rc, u32 num_vertices); diff --git a/src/pse/gpu_hw_opengl.cpp b/src/pse/gpu_hw_opengl.cpp index 734a848c8..bf4dafd77 100644 --- a/src/pse/gpu_hw_opengl.cpp +++ b/src/pse/gpu_hw_opengl.cpp @@ -193,12 +193,55 @@ inline u32 ConvertRGBA5551ToRGBA8888(u16 color) 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(); m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT); } +void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) +{ + // we need to convert RGBA8 -> RGBA5551 + std::vector temp_buffer(width * height); + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer_fbo_id); + glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, temp_buffer.data()); + + // reverse copy because of lower-left origin + const u32 source_stride = width * sizeof(u32); + const u8* source_ptr = reinterpret_cast(temp_buffer.data()) + (source_stride * (height - 1)); + const u32 dst_stride = width * sizeof(u16); + u8* dst_ptr = static_cast(buffer); + for (u32 row = 0; row < height; row++) + { + const u8* source_row_ptr = source_ptr; + u8* dst_row_ptr = dst_ptr; + + for (u32 col = 0; col < width; col++) + { + u32 src_col; + std::memcpy(&src_col, source_row_ptr, sizeof(src_col)); + source_row_ptr += sizeof(src_col); + + const u16 dst_col = ConvertRGBA8888ToRGBA5551(src_col); + std::memcpy(dst_row_ptr, &dst_col, sizeof(dst_col)); + dst_row_ptr += sizeof(dst_col); + } + + source_ptr -= source_stride; + dst_ptr += dst_stride; + } +} + void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) { glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id); diff --git a/src/pse/gpu_hw_opengl.h b/src/pse/gpu_hw_opengl.h index 995d8bc96..bdfdb0f81 100644 --- a/src/pse/gpu_hw_opengl.h +++ b/src/pse/gpu_hw_opengl.h @@ -18,6 +18,7 @@ public: protected: void UpdateDisplay() override; + void ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) override; void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override; void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override; void UpdateTexturePageTexture() override;