mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 15:45:42 +00:00
GPU/HW: Only copy the dirty area to the VRAM read texture
This commit is contained in:
parent
da51d49d18
commit
cc7483ad58
|
@ -87,6 +87,33 @@ struct Rectangle
|
||||||
|
|
||||||
#undef RELATIONAL_OPERATOR
|
#undef RELATIONAL_OPERATOR
|
||||||
|
|
||||||
|
// Arithmetic operators.
|
||||||
|
#define ARITHMETIC_OPERATOR(op) \
|
||||||
|
constexpr Rectangle& operator op##=(const T amount) \
|
||||||
|
{ \
|
||||||
|
left op## = amount; \
|
||||||
|
top op## = amount; \
|
||||||
|
right op## = amount; \
|
||||||
|
bottom op## = amount; \
|
||||||
|
} \
|
||||||
|
constexpr Rectangle operator op(const T amount) \
|
||||||
|
{ \
|
||||||
|
return Rectangle(left op amount, top op amount, right op amount, bottom op amount); \
|
||||||
|
}
|
||||||
|
|
||||||
|
ARITHMETIC_OPERATOR(+);
|
||||||
|
ARITHMETIC_OPERATOR(-);
|
||||||
|
ARITHMETIC_OPERATOR(*);
|
||||||
|
ARITHMETIC_OPERATOR(/);
|
||||||
|
ARITHMETIC_OPERATOR(%);
|
||||||
|
ARITHMETIC_OPERATOR(>>);
|
||||||
|
ARITHMETIC_OPERATOR(<<);
|
||||||
|
ARITHMETIC_OPERATOR(|);
|
||||||
|
ARITHMETIC_OPERATOR(&);
|
||||||
|
ARITHMETIC_OPERATOR(^);
|
||||||
|
|
||||||
|
#undef ARITHMETIC_OPERATOR
|
||||||
|
|
||||||
#ifdef _WINDEF_
|
#ifdef _WINDEF_
|
||||||
/// Casts this rectangle to a Win32 RECT structure if compatible.
|
/// Casts this rectangle to a Win32 RECT structure if compatible.
|
||||||
template<bool _ = true, typename = typename std::enable_if_t<std::is_same_v<T, s32> && _>>
|
template<bool _ = true, typename = typename std::enable_if_t<std::is_same_v<T, s32> && _>>
|
||||||
|
|
|
@ -385,9 +385,11 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsTexturePageChanged() const { return texture_page_changed; }
|
bool IsTexturePageChanged() const { return texture_page_changed; }
|
||||||
|
void SetTexturePageChanged() { texture_page_changed = true; }
|
||||||
void ClearTexturePageChangedFlag() { texture_page_changed = false; }
|
void ClearTexturePageChangedFlag() { texture_page_changed = false; }
|
||||||
|
|
||||||
bool IsTextureWindowChanged() const { return texture_window_changed; }
|
bool IsTextureWindowChanged() const { return texture_window_changed; }
|
||||||
|
void SetTextureWindowChanged() { texture_window_changed = true; }
|
||||||
void ClearTextureWindowChangedFlag() { texture_window_changed = false; }
|
void ClearTextureWindowChangedFlag() { texture_window_changed = false; }
|
||||||
|
|
||||||
void SetFromPolygonTexcoord(u32 texcoord0, u32 texcoord1);
|
void SetFromPolygonTexcoord(u32 texcoord0, u32 texcoord1);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "gpu_hw.h"
|
#include "gpu_hw.h"
|
||||||
#include "YBaseLib/Assert.h"
|
#include "YBaseLib/Assert.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
|
#include "common/state_wrapper.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
@ -11,15 +12,6 @@ GPU_HW::GPU_HW() = default;
|
||||||
|
|
||||||
GPU_HW::~GPU_HW() = default;
|
GPU_HW::~GPU_HW() = default;
|
||||||
|
|
||||||
void GPU_HW::Reset()
|
|
||||||
{
|
|
||||||
GPU::Reset();
|
|
||||||
|
|
||||||
m_batch = {};
|
|
||||||
m_batch_ubo_data = {};
|
|
||||||
m_batch_ubo_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GPU_HW::Initialize(HostDisplay* host_display, System* system, DMA* dma, InterruptController* interrupt_controller,
|
bool GPU_HW::Initialize(HostDisplay* host_display, System* system, DMA* dma, InterruptController* interrupt_controller,
|
||||||
Timers* timers)
|
Timers* timers)
|
||||||
{
|
{
|
||||||
|
@ -33,6 +25,29 @@ bool GPU_HW::Initialize(HostDisplay* host_display, System* system, DMA* dma, Int
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPU_HW::Reset()
|
||||||
|
{
|
||||||
|
GPU::Reset();
|
||||||
|
|
||||||
|
m_batch = {};
|
||||||
|
m_batch_ubo_data = {};
|
||||||
|
m_batch_ubo_dirty = true;
|
||||||
|
|
||||||
|
SetFullVRAMDirtyRectangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GPU_HW::DoState(StateWrapper& sw)
|
||||||
|
{
|
||||||
|
if (!GPU::DoState(sw))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// invalidate the whole VRAM read texture when loading state
|
||||||
|
if (sw.IsReading())
|
||||||
|
SetFullVRAMDirtyRectangle();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void GPU_HW::UpdateSettings()
|
void GPU_HW::UpdateSettings()
|
||||||
{
|
{
|
||||||
GPU::UpdateSettings();
|
GPU::UpdateSettings();
|
||||||
|
@ -228,11 +243,11 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32
|
||||||
if (m_vram_dirty_rect.Valid() && (m_render_state.GetTexturePageRectangle().Intersects(m_vram_dirty_rect) ||
|
if (m_vram_dirty_rect.Valid() && (m_render_state.GetTexturePageRectangle().Intersects(m_vram_dirty_rect) ||
|
||||||
m_render_state.GetTexturePaletteRectangle().Intersects(m_vram_dirty_rect)))
|
m_render_state.GetTexturePaletteRectangle().Intersects(m_vram_dirty_rect)))
|
||||||
{
|
{
|
||||||
|
Log_WarningPrintf("Invalidating VRAM read cache due to drawing area overlap");
|
||||||
if (!IsFlushed())
|
if (!IsFlushed())
|
||||||
FlushRender();
|
FlushRender();
|
||||||
|
|
||||||
Log_WarningPrintf("Invalidating VRAM read cache due to drawing area overlap");
|
UpdateVRAMReadTexture();
|
||||||
m_vram_read_texture_dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ public:
|
||||||
virtual bool Initialize(HostDisplay* host_display, System* system, DMA* dma,
|
virtual bool Initialize(HostDisplay* host_display, System* system, DMA* dma,
|
||||||
InterruptController* interrupt_controller, Timers* timers) override;
|
InterruptController* interrupt_controller, Timers* timers) override;
|
||||||
virtual void Reset() override;
|
virtual void Reset() override;
|
||||||
|
virtual bool DoState(StateWrapper& sw) override;
|
||||||
virtual void UpdateSettings() override;
|
virtual void UpdateSettings() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -111,6 +112,14 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void MapBatchVertexPointer(u32 required_vertices) = 0;
|
virtual void MapBatchVertexPointer(u32 required_vertices) = 0;
|
||||||
|
virtual void UpdateVRAMReadTexture() = 0;
|
||||||
|
|
||||||
|
void SetFullVRAMDirtyRectangle()
|
||||||
|
{
|
||||||
|
m_vram_dirty_rect.Set(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||||
|
m_render_state.SetTexturePageChanged();
|
||||||
|
}
|
||||||
|
void ClearVRAMDirtyRectangle() { m_vram_dirty_rect.SetInvalid(); }
|
||||||
|
|
||||||
u32 GetBatchVertexSpace() const { return static_cast<u32>(m_batch_end_vertex_ptr - m_batch_current_vertex_ptr); }
|
u32 GetBatchVertexSpace() const { return static_cast<u32>(m_batch_end_vertex_ptr - m_batch_current_vertex_ptr); }
|
||||||
u32 GetBatchVertexCount() const { return static_cast<u32>(m_batch_current_vertex_ptr - m_batch_start_vertex_ptr); }
|
u32 GetBatchVertexCount() const { return static_cast<u32>(m_batch_current_vertex_ptr - m_batch_start_vertex_ptr); }
|
||||||
|
@ -151,7 +160,6 @@ protected:
|
||||||
|
|
||||||
// Changed state
|
// Changed state
|
||||||
bool m_batch_ubo_dirty = true;
|
bool m_batch_ubo_dirty = true;
|
||||||
bool m_vram_read_texture_dirty = false;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum : u32
|
enum : u32
|
||||||
|
|
|
@ -184,7 +184,7 @@ bool GPU_HW_D3D11::CreateFramebuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_context->OMSetRenderTargets(1, m_vram_texture.GetD3DRTVArray(), nullptr);
|
m_context->OMSetRenderTargets(1, m_vram_texture.GetD3DRTVArray(), nullptr);
|
||||||
m_vram_read_texture_dirty = true;
|
SetFullVRAMDirtyRectangle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ void GPU_HW_D3D11::ClearFramebuffer()
|
||||||
{
|
{
|
||||||
static constexpr std::array<float, 4> color = {};
|
static constexpr std::array<float, 4> color = {};
|
||||||
m_context->ClearRenderTargetView(m_vram_texture.GetD3DRTV(), color.data());
|
m_context->ClearRenderTargetView(m_vram_texture.GetD3DRTV(), color.data());
|
||||||
m_vram_read_texture_dirty = true;
|
SetFullVRAMDirtyRectangle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_D3D11::DestroyFramebuffer()
|
void GPU_HW_D3D11::DestroyFramebuffer()
|
||||||
|
@ -491,9 +491,6 @@ void GPU_HW_D3D11::SetDrawState(BatchRenderMode render_mode)
|
||||||
UploadUniformBlock(&m_batch_ubo_data, sizeof(m_batch_ubo_data));
|
UploadUniformBlock(&m_batch_ubo_data, sizeof(m_batch_ubo_data));
|
||||||
m_batch_ubo_dirty = false;
|
m_batch_ubo_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_vram_read_texture_dirty)
|
|
||||||
UpdateVRAMReadTexture();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_D3D11::SetScissorFromDrawingArea()
|
void GPU_HW_D3D11::SetScissorFromDrawingArea()
|
||||||
|
@ -648,12 +645,13 @@ void GPU_HW_D3D11::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 widt
|
||||||
|
|
||||||
void GPU_HW_D3D11::UpdateVRAMReadTexture()
|
void GPU_HW_D3D11::UpdateVRAMReadTexture()
|
||||||
{
|
{
|
||||||
m_renderer_stats.num_vram_read_texture_updates++;
|
const auto scaled_rect = m_vram_dirty_rect * m_resolution_scale;
|
||||||
m_vram_read_texture_dirty = false;
|
const CD3D11_BOX src_box(scaled_rect.left, scaled_rect.top, 0, scaled_rect.right, scaled_rect.bottom, 1);
|
||||||
m_vram_dirty_rect.SetInvalid();
|
m_context->CopySubresourceRegion(m_vram_read_texture, 0, scaled_rect.left, scaled_rect.top, 0, m_vram_texture, 0,
|
||||||
|
&src_box);
|
||||||
|
|
||||||
const CD3D11_BOX src_box(0, 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1);
|
m_renderer_stats.num_vram_read_texture_updates++;
|
||||||
m_context->CopySubresourceRegion(m_vram_read_texture, 0, 0, 0, 0, m_vram_texture, 0, &src_box);
|
ClearVRAMDirtyRectangle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_D3D11::FlushRender()
|
void GPU_HW_D3D11::FlushRender()
|
||||||
|
|
|
@ -34,13 +34,13 @@ protected:
|
||||||
void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;
|
void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;
|
||||||
void FlushRender() override;
|
void FlushRender() override;
|
||||||
void MapBatchVertexPointer(u32 required_vertices) override;
|
void MapBatchVertexPointer(u32 required_vertices) override;
|
||||||
|
void UpdateVRAMReadTexture() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetCapabilities();
|
void SetCapabilities();
|
||||||
bool CreateFramebuffer();
|
bool CreateFramebuffer();
|
||||||
void ClearFramebuffer();
|
void ClearFramebuffer();
|
||||||
void DestroyFramebuffer();
|
void DestroyFramebuffer();
|
||||||
void UpdateVRAMReadTexture();
|
|
||||||
|
|
||||||
bool CreateVertexBuffer();
|
bool CreateVertexBuffer();
|
||||||
bool CreateUniformBuffer();
|
bool CreateUniformBuffer();
|
||||||
|
|
|
@ -169,7 +169,7 @@ void GPU_HW_OpenGL::CreateFramebuffer()
|
||||||
std::make_unique<GL::Texture>(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true);
|
std::make_unique<GL::Texture>(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true);
|
||||||
|
|
||||||
m_vram_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER);
|
m_vram_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER);
|
||||||
m_vram_read_texture_dirty = true;
|
SetFullVRAMDirtyRectangle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::ClearFramebuffer()
|
void GPU_HW_OpenGL::ClearFramebuffer()
|
||||||
|
@ -178,7 +178,7 @@ void GPU_HW_OpenGL::ClearFramebuffer()
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
m_vram_read_texture_dirty = true;
|
SetFullVRAMDirtyRectangle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::DestroyFramebuffer()
|
void GPU_HW_OpenGL::DestroyFramebuffer()
|
||||||
|
@ -352,9 +352,6 @@ void GPU_HW_OpenGL::SetDrawState(BatchRenderMode render_mode)
|
||||||
UploadUniformBlock(&m_batch_ubo_data, sizeof(m_batch_ubo_data));
|
UploadUniformBlock(&m_batch_ubo_data, sizeof(m_batch_ubo_data));
|
||||||
m_batch_ubo_dirty = false;
|
m_batch_ubo_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_vram_read_texture_dirty)
|
|
||||||
UpdateVRAMReadTexture();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::SetScissorFromDrawingArea()
|
void GPU_HW_OpenGL::SetScissorFromDrawingArea()
|
||||||
|
@ -678,13 +675,16 @@ void GPU_HW_OpenGL::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid
|
||||||
|
|
||||||
void GPU_HW_OpenGL::UpdateVRAMReadTexture()
|
void GPU_HW_OpenGL::UpdateVRAMReadTexture()
|
||||||
{
|
{
|
||||||
m_renderer_stats.num_vram_read_texture_updates++;
|
// TODO: Fallback blit path.
|
||||||
m_vram_read_texture_dirty = false;
|
const auto scaled_rect = m_vram_dirty_rect * m_resolution_scale;
|
||||||
m_vram_dirty_rect.SetInvalid();
|
const u32 flipped_y = m_vram_texture->GetHeight() - scaled_rect.top - scaled_rect.GetHeight();
|
||||||
|
|
||||||
// TODO: Fallback blit path, and partial updates.
|
glCopyImageSubData(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, scaled_rect.left, flipped_y, 0,
|
||||||
glCopyImageSubData(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, 0, 0, 0, m_vram_read_texture->GetGLId(),
|
m_vram_read_texture->GetGLId(), GL_TEXTURE_2D, 0, scaled_rect.left, flipped_y, 0,
|
||||||
GL_TEXTURE_2D, 0, 0, 0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), 1);
|
scaled_rect.GetWidth(), scaled_rect.GetHeight(), 1);
|
||||||
|
|
||||||
|
m_renderer_stats.num_vram_read_texture_updates++;
|
||||||
|
ClearVRAMDirtyRectangle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::FlushRender()
|
void GPU_HW_OpenGL::FlushRender()
|
||||||
|
|
|
@ -30,6 +30,7 @@ protected:
|
||||||
void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;
|
void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;
|
||||||
void FlushRender() override;
|
void FlushRender() override;
|
||||||
void MapBatchVertexPointer(u32 required_vertices) override;
|
void MapBatchVertexPointer(u32 required_vertices) override;
|
||||||
|
void UpdateVRAMReadTexture() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct GLStats
|
struct GLStats
|
||||||
|
@ -48,7 +49,6 @@ private:
|
||||||
void CreateFramebuffer();
|
void CreateFramebuffer();
|
||||||
void ClearFramebuffer();
|
void ClearFramebuffer();
|
||||||
void DestroyFramebuffer();
|
void DestroyFramebuffer();
|
||||||
void UpdateVRAMReadTexture();
|
|
||||||
|
|
||||||
void CreateVertexBuffer();
|
void CreateVertexBuffer();
|
||||||
void CreateUniformBuffer();
|
void CreateUniformBuffer();
|
||||||
|
|
Loading…
Reference in a new issue