diff --git a/src/common/gl_program.cpp b/src/common/gl_program.cpp index ef27dec29..7c033028b 100644 --- a/src/common/gl_program.cpp +++ b/src/common/gl_program.cpp @@ -79,7 +79,7 @@ void Program::BindDefaultAttributes() BindAttribute(2, "a_color"); } -void Program::BindFragData(GLuint index /*= 0*/, const char* name /*= "ocol0"*/) +void Program::BindFragData(GLuint index /*= 0*/, const char* name /*= "o_col0"*/) { glBindFragDataLocation(m_program_id, index, name); } diff --git a/src/common/gl_program.h b/src/common/gl_program.h index 1a92fc063..2f7cc3e5d 100644 --- a/src/common/gl_program.h +++ b/src/common/gl_program.h @@ -19,7 +19,7 @@ public: void BindAttribute(GLuint index, const char* name); void BindDefaultAttributes(); - void BindFragData(GLuint index = 0, const char* name = "ocol0"); + void BindFragData(GLuint index = 0, const char* name = "o_col0"); bool Link(); diff --git a/src/pse-sdl/sdl_interface.cpp b/src/pse-sdl/sdl_interface.cpp index daefd8f1e..ec714c572 100644 --- a/src/pse-sdl/sdl_interface.cpp +++ b/src/pse-sdl/sdl_interface.cpp @@ -116,18 +116,18 @@ void main() uniform sampler2D samp0; in vec2 v_tex0; -out vec4 ocol0; +out vec4 o_col0; void main() { - ocol0 = texture(samp0, v_tex0); + o_col0 = texture(samp0, v_tex0); } )"; if (!m_display_program.Compile(fullscreen_quad_vertex_shader, display_fragment_shader)) return false; - m_display_program.BindFragData(); + m_display_program.BindFragData(0, "o_col0"); if (!m_display_program.Link()) return false; diff --git a/src/pse/gpu.cpp b/src/pse/gpu.cpp index 7a2edc668..7cd705437 100644 --- a/src/pse/gpu.cpp +++ b/src/pse/gpu.cpp @@ -157,6 +157,13 @@ void GPU::WriteGP0(u32 value) case 0x00: // NOP break; + case 0x02: // Fill Rectnagle + { + if (!HandleFillRectangleCommand()) + return; + } + break; + case 0xA0: // Copy Rectangle CPU->VRAM { if (!HandleCopyRectangleCPUToVRAMCommand()) @@ -345,6 +352,25 @@ bool GPU::HandleRenderCommand() ZeroExtend32(words_per_vertex)); DispatchRenderCommand(rc, num_vertices); + UpdateDisplay(); + return true; +} + +bool GPU::HandleFillRectangleCommand() +{ + if (m_GP0_command.size() < 3) + return false; + + const u32 color = (m_GP0_command[0] & UINT32_C(0x00FFFFFF)) | UINT32_C(0xFF000000); + const u32 dst_x = m_GP0_command[1] & UINT32_C(0xFFFF); + const u32 dst_y = m_GP0_command[1] >> 16; + const u32 width = m_GP0_command[2] & UINT32_C(0xFFFF); + const u32 height = m_GP0_command[2] >> 16; + + Log_DebugPrintf("Fill VRAM rectangle offset=(%u,%u), size=(%u,%u)", dst_x, dst_y, width, height); + + FillVRAM(dst_x, dst_y, width, height, color); + UpdateDisplay(); return true; } @@ -374,6 +400,7 @@ bool GPU::HandleCopyRectangleCPUToVRAMCommand() FlushRender(); UpdateVRAM(dst_x, dst_y, copy_width, copy_height, &m_GP0_command[3]); + UpdateDisplay(); return true; } @@ -411,6 +438,8 @@ void GPU::UpdateDisplay() m_system->IncrementFrameNumber(); } +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) {} void GPU::DispatchRenderCommand(RenderCommand rc, u32 num_vertices) {} diff --git a/src/pse/gpu.h b/src/pse/gpu.h index 4fb9836c6..65fcc64f1 100644 --- a/src/pse/gpu.h +++ b/src/pse/gpu.h @@ -113,11 +113,13 @@ protected: // Rendering commands, returns false if not enough data is provided bool HandleRenderCommand(); + bool HandleFillRectangleCommand(); bool HandleCopyRectangleCPUToVRAMCommand(); bool HandleCopyRectangleVRAMToCPUCommand(); // Rendering in the backend virtual void UpdateDisplay(); + 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); virtual void FlushRender(); diff --git a/src/pse/gpu_hw.cpp b/src/pse/gpu_hw.cpp index f0b941f00..062108475 100644 --- a/src/pse/gpu_hw.cpp +++ b/src/pse/gpu_hw.cpp @@ -245,7 +245,7 @@ void main() return ss.str(); } -std::string GPU_HW::GenerateTexturePageProgram(TextureColorMode mode) +std::string GPU_HW::GenerateTexturePageFragmentShader(TextureColorMode mode) { const bool is_palette = (mode == GPU::TextureColorMode::Palette4Bit || mode == GPU::TextureColorMode::Palette8Bit); @@ -304,6 +304,24 @@ void main() return ss.str(); } +std::string GPU_HW::GenerateFillFragmentShader() +{ + std::stringstream ss; + GenerateShaderHeader(ss); + + ss << R"( +uniform vec4 fill_color; +out vec4 o_col0; + +void main() +{ + o_col0 = fill_color; +} +)"; + + return ss.str(); +} + void GPU_HW::UpdateTexturePageTexture() {} void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices) diff --git a/src/pse/gpu_hw.h b/src/pse/gpu_hw.h index aa054f4bb..32225f73c 100644 --- a/src/pse/gpu_hw.h +++ b/src/pse/gpu_hw.h @@ -19,13 +19,21 @@ protected: u16 texcoord; u16 padding; - static std::tuple DecodeTexcoord(u16 texcoord) + static constexpr std::tuple DecodeTexcoord(u16 texcoord) { return std::make_tuple(static_cast(texcoord), static_cast(texcoord >> 8)); } - static u16 EncodeTexcoord(u8 x, u8 y) { return ZeroExtend16(x) | (ZeroExtend16(y) << 8); } + static constexpr u16 EncodeTexcoord(u8 x, u8 y) { return ZeroExtend16(x) | (ZeroExtend16(y) << 8); } }; + static constexpr std::tuple RGBA8ToFloat(u32 rgba) + { + return std::make_tuple(static_cast(rgba & UINT32_C(0xFF)) * (1.0f / 255.0f), + static_cast((rgba >> 16) & UINT32_C(0xFF)) * (1.0f / 255.0f), + static_cast((rgba >> 8) & UINT32_C(0xFF)) * (1.0f / 255.0f), + static_cast(rgba >> 24) * (1.0f / 255.0f)); + } + virtual void UpdateTexturePageTexture(); bool IsFlushed() const { return !m_batch_vertices.empty(); } @@ -38,7 +46,8 @@ protected: std::string GenerateVertexShader(bool textured); std::string GenerateFragmentShader(bool textured, bool blending); std::string GenerateScreenQuadVertexShader(); - std::string GenerateTexturePageProgram(TextureColorMode mode); + std::string GenerateTexturePageFragmentShader(TextureColorMode mode); + std::string GenerateFillFragmentShader(); std::vector m_batch_vertices; RenderCommand m_batch_command = {}; diff --git a/src/pse/gpu_hw_opengl.cpp b/src/pse/gpu_hw_opengl.cpp index 256498564..734a848c8 100644 --- a/src/pse/gpu_hw_opengl.cpp +++ b/src/pse/gpu_hw_opengl.cpp @@ -110,7 +110,7 @@ bool GPU_HW_OpenGL::CompilePrograms() const std::string screen_quad_vs = GenerateScreenQuadVertexShader(); for (u32 palette_size = 0; palette_size < static_cast(m_texture_page_programs.size()); palette_size++) { - const std::string fs = GenerateTexturePageProgram(static_cast(palette_size)); + const std::string fs = GenerateTexturePageFragmentShader(static_cast(palette_size)); GL::Program& prog = m_texture_page_programs[palette_size]; if (!prog.Compile(screen_quad_vs.c_str(), fs.c_str())) @@ -199,6 +199,19 @@ void GPU_HW_OpenGL::UpdateDisplay() m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT); } +void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) +{ + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id); + + glEnable(GL_SCISSOR_TEST); + glScissor(x, VRAM_HEIGHT - y - height, width, height); + + const auto [r, g, b, a] = RGBA8ToFloat(color); + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); +} + void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) { std::vector rgba_data; diff --git a/src/pse/gpu_hw_opengl.h b/src/pse/gpu_hw_opengl.h index 35a7f090a..995d8bc96 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 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; void FlushRender() override;