From da51d49d182f0da01997933d2b20ffe5454e0eb9 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 5 Nov 2019 22:12:37 +1000 Subject: [PATCH] GPU/HW: Track VRAM fills/writes in dirty rectangle instead of invalidating --- src/core/gpu_hw.cpp | 45 +++++++++++++++++++++++++------------- src/core/gpu_hw.h | 5 +++-- src/core/gpu_hw_d3d11.cpp | 9 +++++--- src/core/gpu_hw_opengl.cpp | 11 +++++----- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 2737ac140..216e570be 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -178,6 +178,21 @@ GPU_HW::BatchPrimitive GPU_HW::GetPrimitiveForCommand(RenderCommand rc) return BatchPrimitive::Triangles; } +void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) +{ + m_vram_dirty_rect.Include(Common::Rectangle::FromExtents(x, y, width, height)); +} + +void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) +{ + m_vram_dirty_rect.Include(Common::Rectangle::FromExtents(x, y, width, height)); +} + +void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) +{ + m_vram_dirty_rect.Include(Common::Rectangle::FromExtents(dst_x, dst_y, width, height)); +} + void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32* command_ptr) { TextureMode texture_mode; @@ -206,6 +221,21 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32 break; } + // texture page changed - check that the new page doesn't intersect the drawing area + if (m_render_state.IsTexturePageChanged()) + { + m_render_state.ClearTexturePageChangedFlag(); + if (m_vram_dirty_rect.Valid() && (m_render_state.GetTexturePageRectangle().Intersects(m_vram_dirty_rect) || + m_render_state.GetTexturePaletteRectangle().Intersects(m_vram_dirty_rect))) + { + if (!IsFlushed()) + FlushRender(); + + Log_WarningPrintf("Invalidating VRAM read cache due to drawing area overlap"); + m_vram_read_texture_dirty = true; + } + } + texture_mode = m_render_state.texture_mode; if (rc.raw_texture_enable) { @@ -219,21 +249,6 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32 texture_mode = TextureMode::Disabled; } - // texture page changed - check that the new page doesn't intersect the drawing area - if (m_render_state.IsTexturePageChanged()) - { - m_render_state.ClearTexturePageChangedFlag(); - if (m_vram_dirty_rect.Valid() && (m_render_state.GetTexturePageRectangle().Intersects(m_vram_dirty_rect) || - m_render_state.GetTexturePaletteRectangle().Intersects(m_vram_dirty_rect))) - { - if (!IsFlushed()) - FlushRender(); - - Log_WarningPrintf("Invalidating VRAM read cache due to drawing area overlap"); - m_vram_read_texture_dirty = true; - } - } - // has any state changed which requires a new batch? const TransparencyMode transparency_mode = rc.transparency_enable ? m_render_state.transparency_mode : TransparencyMode::Disabled; diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index f538fd192..2f02d3c2c 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -112,13 +112,14 @@ protected: virtual void MapBatchVertexPointer(u32 required_vertices) = 0; - void InvalidateVRAMReadTexture() { m_vram_read_texture_dirty = true; } - u32 GetBatchVertexSpace() const { return static_cast(m_batch_end_vertex_ptr - m_batch_current_vertex_ptr); } u32 GetBatchVertexCount() const { return static_cast(m_batch_current_vertex_ptr - m_batch_start_vertex_ptr); } bool IsFlushed() const { return m_batch_current_vertex_ptr == m_batch_start_vertex_ptr; } + 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 CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override; void DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32* command_ptr) override; void DrawRendererStats(bool is_idle_frame) override; diff --git a/src/core/gpu_hw_d3d11.cpp b/src/core/gpu_hw_d3d11.cpp index 137fbd662..cab792d41 100644 --- a/src/core/gpu_hw_d3d11.cpp +++ b/src/core/gpu_hw_d3d11.cpp @@ -595,6 +595,8 @@ void GPU_HW_D3D11::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) void GPU_HW_D3D11::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) { + GPU_HW::FillVRAM(x, y, width, height, color); + // drop precision unless true colour is enabled if (!m_true_color) color = RGBA5551ToRGBA8888(RGBA8888ToRGBA5551(color)); @@ -607,11 +609,12 @@ void GPU_HW_D3D11::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) DrawUtilityShader(m_fill_pixel_shader.Get(), uniforms, sizeof(uniforms)); RestoreGraphicsAPIState(); - InvalidateVRAMReadTexture(); } void GPU_HW_D3D11::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) { + GPU_HW::UpdateVRAM(x, y, width, height, data); + const u32 num_pixels = width * height; const auto map_result = m_texture_stream_buffer.Map(m_context.Get(), sizeof(u16), num_pixels * sizeof(u16)); std::memcpy(map_result.pointer, data, num_pixels * sizeof(u16)); @@ -626,11 +629,12 @@ void GPU_HW_D3D11::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* d DrawUtilityShader(m_vram_write_pixel_shader.Get(), uniforms, sizeof(uniforms)); RestoreGraphicsAPIState(); - InvalidateVRAMReadTexture(); } void GPU_HW_D3D11::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) { + GPU_HW::CopyVRAM(src_x, src_y, dst_x, dst_y, width, height); + src_x *= m_resolution_scale; src_y *= m_resolution_scale; dst_x *= m_resolution_scale; @@ -640,7 +644,6 @@ void GPU_HW_D3D11::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 widt const CD3D11_BOX src_box(src_x, src_y, 0, src_x + width, src_y + height, 1); m_context->CopySubresourceRegion(m_vram_texture, 0, dst_x, dst_y, 0, m_vram_texture, 0, &src_box); - InvalidateVRAMReadTexture(); } void GPU_HW_D3D11::UpdateVRAMReadTexture() diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index 19aa5c681..07b4beea0 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -547,6 +547,8 @@ void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) { + GPU_HW::FillVRAM(x, y, width, height, color); + // scale coordinates x *= m_resolution_scale; y *= m_resolution_scale; @@ -564,11 +566,12 @@ void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) glClear(GL_COLOR_BUFFER_BIT); SetScissorFromDrawingArea(); - InvalidateVRAMReadTexture(); } void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) { + GPU_HW::UpdateVRAM(x, y, width, height, data); + const u32 num_pixels = width * height; #if 0 const auto map_result = m_texture_stream_buffer->Map(sizeof(u32), num_pixels * sizeof(u32)); @@ -649,12 +652,12 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* SetScissorFromDrawingArea(); #endif - - InvalidateVRAMReadTexture(); } void GPU_HW_OpenGL::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) { + GPU_HW::CopyVRAM(src_x, src_y, dst_x, dst_y, width, height); + src_x *= m_resolution_scale; src_y *= m_resolution_scale; dst_x *= m_resolution_scale; @@ -671,8 +674,6 @@ void GPU_HW_OpenGL::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid glBlitFramebuffer(src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height, GL_COLOR_BUFFER_BIT, GL_NEAREST); glEnable(GL_SCISSOR_TEST); - - InvalidateVRAMReadTexture(); } void GPU_HW_OpenGL::UpdateVRAMReadTexture()