From c2baa7e83449ae141b1e042927ca108dcdfb80b7 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 5 Oct 2019 12:31:48 +1000 Subject: [PATCH] GPU: 24-bit display depth support --- src/core/gpu_hw.cpp | 62 ++++++++++++++++++++++++++++++++++++++ src/core/gpu_hw.h | 1 + src/core/gpu_hw_opengl.cpp | 44 ++++++++++++++++++++++++--- src/core/gpu_hw_opengl.h | 2 +- 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index c111ee332..80cd5ecdc 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -378,6 +378,68 @@ void main() return ss.str(); } +std::string GPU_HW::GenerateRGB24DecodeFragmentShader() +{ + std::stringstream ss; + GenerateShaderHeader(ss); + + ss << R"( +in vec2 v_tex0; +out vec4 o_col0; + +uniform sampler2D samp0; +uniform ivec2 u_base_coords; + +void main() +{ + // compute offset in dwords from the start of the 24-bit values + ivec2 base = ivec2(u_base_coords.x, u_base_coords.y + int(gl_FragCoord.y)); + int xoff = int(gl_FragCoord.x); + int dword_index = (xoff / 2) + (xoff / 4); + + // sample two adjacent dwords, or four 16-bit values as the 24-bit value will lie somewhere between these + uint s0 = RGBA8ToRGBA5551(texelFetch(samp0, ivec2(base.x + dword_index * 2 + 0, base.y), 0)); + uint s1 = RGBA8ToRGBA5551(texelFetch(samp0, ivec2(base.x + dword_index * 2 + 1, base.y), 0)); + uint s2 = RGBA8ToRGBA5551(texelFetch(samp0, ivec2(base.x + (dword_index + 1) * 2 + 0, base.y), 0)); + uint s3 = RGBA8ToRGBA5551(texelFetch(samp0, ivec2(base.x + (dword_index + 1) * 2 + 1, base.y), 0)); + + // select the bit for this pixel depending on its offset in the 4-pixel block + uint r, g, b; + switch (xoff & 3) + { + case 0: + r = s0 & 0xFFu; + g = s0 >> 8; + b = s1 & 0xFFu; + break; + + case 1: + r = s1 >> 8; + g = s2 & 0xFFu; + b = s2 >> 8; + break; + + case 2: + r = s1 & 0xFFu; + g = s1 >> 8; + b = s2 & 0xFFu; + break; + + case 3: + r = s2 >> 8; + g = s3 & 0xFFu; + b = s3 >> 8; + break; + } + + // and normalize + o_col0 = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255, 1.0); +} +)"; + + return ss.str(); +} + GPU_HW::HWRenderBatch::Primitive GPU_HW::GetPrimitiveForCommand(RenderCommand rc) { if (rc.primitive == Primitive::Line) diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index 43aed708a..200c14ddd 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -88,6 +88,7 @@ protected: bool blending); std::string GenerateScreenQuadVertexShader(); std::string GenerateFillFragmentShader(); + std::string GenerateRGB24DecodeFragmentShader(); u32 m_resolution_scale = 1; HWRenderBatch m_batch = {}; diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index f7cc8e5a9..c0e4cbc0f 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -300,6 +300,21 @@ bool GPU_HW_OpenGL::CompilePrograms() } } + // TODO: Use string_view + if (!m_reinterpret_rgb8_program.Compile(GenerateScreenQuadVertexShader().c_str(), + GenerateRGB24DecodeFragmentShader().c_str())) + { + return false; + } + m_reinterpret_rgb8_program.BindFragData(0, "o_col0"); + if (!m_reinterpret_rgb8_program.Link()) + return false; + + m_reinterpret_rgb8_program.Bind(); + m_reinterpret_rgb8_program.RegisterUniform("u_base_coords"); + m_reinterpret_rgb8_program.RegisterUniform("samp0"); + m_reinterpret_rgb8_program.Uniform1i(1, 0); + return true; } @@ -404,7 +419,6 @@ void GPU_HW_OpenGL::UpdateDisplay() const u32 texture_width = m_vram_texture->GetWidth(); const u32 texture_height = m_vram_texture->GetHeight(); - // TODO: 24-bit support. if (m_debug_options.show_vram) { m_system->GetHostInterface()->SetDisplayTexture(m_vram_texture.get(), 0, 0, texture_width, texture_height, 1.0f); @@ -419,9 +433,31 @@ void GPU_HW_OpenGL::UpdateDisplay() ((vram_offset_x + display_width) > texture_width) ? (texture_width - vram_offset_x) : display_width; const u32 copy_height = ((vram_offset_y + display_height) > texture_height) ? (texture_height - vram_offset_y) : display_height; - glCopyImageSubData(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, vram_offset_x, - texture_height - vram_offset_y - copy_height, 0, m_display_texture->GetGLId(), GL_TEXTURE_2D, 0, - 0, 0, 0, copy_width, copy_height, 1); + + if (m_GPUSTAT.display_area_color_depth_24) + { + glBindFramebuffer(GL_FRAMEBUFFER, m_display_fbo); + glViewport(0, 0, copy_width, copy_height); + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + m_reinterpret_rgb8_program.Bind(); + m_reinterpret_rgb8_program.Uniform2i(0, vram_offset_x, texture_height - vram_offset_y - copy_height); + m_vram_texture->Bind(); + glDrawArrays(GL_TRIANGLES, 0, 3); + + // restore state + glBindFramebuffer(GL_FRAMEBUFFER, m_vram_fbo); + glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight()); + glEnable(GL_SCISSOR_TEST); + if (m_last_transparency_enable) + glEnable(GL_BLEND); + } + else + { + glCopyImageSubData(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, vram_offset_x, + texture_height - vram_offset_y - copy_height, 0, m_display_texture->GetGLId(), GL_TEXTURE_2D, + 0, 0, 0, 0, copy_width, copy_height, 1); + } m_system->GetHostInterface()->SetDisplayTexture(m_display_texture.get(), 0, 0, copy_width, copy_height, DISPLAY_ASPECT_RATIO); diff --git a/src/core/gpu_hw_opengl.h b/src/core/gpu_hw_opengl.h index 37c5ef2f3..0dec54cdd 100644 --- a/src/core/gpu_hw_opengl.h +++ b/src/core/gpu_hw_opengl.h @@ -75,7 +75,7 @@ private: TransparencyMode m_last_transparency_mode = TransparencyMode::BackgroundMinusForeground; std::array, 3>, 2>, 2> m_render_programs; - std::array m_texture_page_programs; + GL::Program m_reinterpret_rgb8_program; GLStats m_stats = {}; GLStats m_last_stats = {};