GPU/HW: Split dirty rect into draw/write
Significant performance improvement in Persona 2.
This commit is contained in:
parent
5218ac6944
commit
23d5b20da6
|
@ -3,10 +3,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
@ -131,6 +131,10 @@ struct Rectangle
|
||||||
|
|
||||||
/// Tests whether the specified point is contained in the rectangle.
|
/// Tests whether the specified point is contained in the rectangle.
|
||||||
constexpr bool Contains(T x, T y) const { return (x >= left && x < right && y >= top && y < bottom); }
|
constexpr bool Contains(T x, T y) const { return (x >= left && x < right && y >= top && y < bottom); }
|
||||||
|
constexpr bool Contains(const Rectangle& rhs) const
|
||||||
|
{
|
||||||
|
return (left <= rhs.left && right >= rhs.right && top <= rhs.top && bottom >= rhs.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
/// Expands the bounds of the rectangle to contain the specified point.
|
/// Expands the bounds of the rectangle to contain the specified point.
|
||||||
constexpr void Include(T x, T y)
|
constexpr void Include(T x, T y)
|
||||||
|
|
|
@ -576,13 +576,14 @@ bool GPU_HW::IsUsingDownsampling() const
|
||||||
|
|
||||||
void GPU_HW::SetFullVRAMDirtyRectangle()
|
void GPU_HW::SetFullVRAMDirtyRectangle()
|
||||||
{
|
{
|
||||||
m_vram_dirty_rect.Set(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
m_vram_dirty_draw_rect.Set(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||||
m_draw_mode.SetTexturePageChanged();
|
m_draw_mode.SetTexturePageChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW::ClearVRAMDirtyRectangle()
|
void GPU_HW::ClearVRAMDirtyRectangle()
|
||||||
{
|
{
|
||||||
m_vram_dirty_rect.SetInvalid();
|
m_vram_dirty_draw_rect.SetInvalid();
|
||||||
|
m_vram_dirty_write_rect.SetInvalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<u32, u32> GPU_HW::GetEffectiveDisplayResolution(bool scaled /* = true */)
|
std::tuple<u32, u32> GPU_HW::GetEffectiveDisplayResolution(bool scaled /* = true */)
|
||||||
|
@ -1218,38 +1219,73 @@ GPU_HW::BatchRenderMode GPU_HW::BatchConfig::GetRenderMode() const
|
||||||
BatchRenderMode::TransparentAndOpaque;
|
BatchRenderMode::TransparentAndOpaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW::UpdateVRAMReadTexture()
|
void GPU_HW::UpdateVRAMReadTexture(bool drawn, bool written)
|
||||||
{
|
{
|
||||||
GL_SCOPE("UpdateVRAMReadTexture()");
|
GL_SCOPE("UpdateVRAMReadTexture()");
|
||||||
|
|
||||||
if (m_texpage_dirty)
|
const auto update = [this](Common::Rectangle<u32>& rect, u8 dbit) {
|
||||||
GL_INS("Texpage is no longer dirty");
|
if (m_texpage_dirty & dbit)
|
||||||
m_texpage_dirty = false;
|
|
||||||
|
|
||||||
const auto scaled_rect = m_vram_dirty_rect * m_resolution_scale;
|
|
||||||
if (m_vram_texture->IsMultisampled())
|
|
||||||
{
|
|
||||||
if (g_gpu_device->GetFeatures().partial_msaa_resolve)
|
|
||||||
{
|
{
|
||||||
g_gpu_device->ResolveTextureRegion(m_vram_read_texture.get(), scaled_rect.left, scaled_rect.top, 0, 0,
|
m_texpage_dirty &= ~dbit;
|
||||||
m_vram_texture.get(), scaled_rect.left, scaled_rect.top,
|
if (!m_texpage_dirty)
|
||||||
scaled_rect.GetWidth(), scaled_rect.GetHeight());
|
GL_INS_FMT("{} texpage is no longer dirty", (dbit & TEXPAGE_DIRTY_DRAWN_RECT) ? "DRAW" : "WRITE");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto scaled_rect = rect * m_resolution_scale;
|
||||||
|
if (m_vram_texture->IsMultisampled())
|
||||||
|
{
|
||||||
|
if (g_gpu_device->GetFeatures().partial_msaa_resolve)
|
||||||
|
{
|
||||||
|
g_gpu_device->ResolveTextureRegion(m_vram_read_texture.get(), scaled_rect.left, scaled_rect.top, 0, 0,
|
||||||
|
m_vram_texture.get(), scaled_rect.left, scaled_rect.top,
|
||||||
|
scaled_rect.GetWidth(), scaled_rect.GetHeight());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_gpu_device->ResolveTextureRegion(m_vram_read_texture.get(), 0, 0, 0, 0, m_vram_texture.get(), 0, 0,
|
||||||
|
m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_gpu_device->ResolveTextureRegion(m_vram_read_texture.get(), 0, 0, 0, 0, m_vram_texture.get(), 0, 0,
|
g_gpu_device->CopyTextureRegion(m_vram_read_texture.get(), scaled_rect.left, scaled_rect.top, 0, 0,
|
||||||
m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
|
m_vram_texture.get(), scaled_rect.left, scaled_rect.top, 0, 0,
|
||||||
|
scaled_rect.GetWidth(), scaled_rect.GetHeight());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_gpu_device->CopyTextureRegion(m_vram_read_texture.get(), scaled_rect.left, scaled_rect.top, 0, 0,
|
|
||||||
m_vram_texture.get(), scaled_rect.left, scaled_rect.top, 0, 0,
|
|
||||||
scaled_rect.GetWidth(), scaled_rect.GetHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_renderer_stats.num_vram_read_texture_updates++;
|
m_renderer_stats.num_vram_read_texture_updates++;
|
||||||
ClearVRAMDirtyRectangle();
|
rect.SetInvalid();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (drawn)
|
||||||
|
{
|
||||||
|
DebugAssert(m_vram_dirty_draw_rect.Valid());
|
||||||
|
GL_INS_FMT("Updating draw rect {},{} => {},{} ({}x{})", m_vram_dirty_draw_rect.left, m_vram_dirty_draw_rect.right,
|
||||||
|
m_vram_dirty_draw_rect.top, m_vram_dirty_draw_rect.bottom, m_vram_dirty_draw_rect.GetWidth(),
|
||||||
|
m_vram_dirty_draw_rect.GetHeight());
|
||||||
|
|
||||||
|
u8 dbits = TEXPAGE_DIRTY_DRAWN_RECT;
|
||||||
|
if (written && m_vram_dirty_draw_rect.Intersects(m_vram_dirty_write_rect))
|
||||||
|
{
|
||||||
|
DebugAssert(m_vram_dirty_write_rect.Valid());
|
||||||
|
GL_INS_FMT("Including write rect {},{} => {},{} ({}x{})", m_vram_dirty_write_rect.left,
|
||||||
|
m_vram_dirty_write_rect.right, m_vram_dirty_write_rect.top, m_vram_dirty_write_rect.bottom,
|
||||||
|
m_vram_dirty_write_rect.GetWidth(), m_vram_dirty_write_rect.GetHeight());
|
||||||
|
m_vram_dirty_draw_rect.Include(m_vram_dirty_write_rect);
|
||||||
|
m_vram_dirty_write_rect.SetInvalid();
|
||||||
|
dbits = TEXPAGE_DIRTY_DRAWN_RECT | TEXPAGE_DIRTY_WRITTEN_RECT;
|
||||||
|
written = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(m_vram_dirty_draw_rect, dbits);
|
||||||
|
}
|
||||||
|
if (written)
|
||||||
|
{
|
||||||
|
GL_INS_FMT("Updating write rect {},{} => {},{} ({}x{})", m_vram_dirty_write_rect.left,
|
||||||
|
m_vram_dirty_write_rect.right, m_vram_dirty_write_rect.top, m_vram_dirty_write_rect.bottom,
|
||||||
|
m_vram_dirty_write_rect.GetWidth(), m_vram_dirty_write_rect.GetHeight());
|
||||||
|
update(m_vram_dirty_write_rect, TEXPAGE_DIRTY_WRITTEN_RECT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW::UpdateDepthBufferFromMaskBit()
|
void GPU_HW::UpdateDepthBufferFromMaskBit()
|
||||||
|
@ -1675,7 +1711,7 @@ void GPU_HW::LoadVertices()
|
||||||
const u32 clip_bottom =
|
const u32 clip_bottom =
|
||||||
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
||||||
|
|
||||||
m_vram_dirty_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
m_vram_dirty_draw_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
||||||
AddDrawTriangleTicks(native_vertex_positions[0][0], native_vertex_positions[0][1],
|
AddDrawTriangleTicks(native_vertex_positions[0][0], native_vertex_positions[0][1],
|
||||||
native_vertex_positions[1][0], native_vertex_positions[1][1],
|
native_vertex_positions[1][0], native_vertex_positions[1][1],
|
||||||
native_vertex_positions[2][0], native_vertex_positions[2][1], rc.shading_enable,
|
native_vertex_positions[2][0], native_vertex_positions[2][1], rc.shading_enable,
|
||||||
|
@ -1709,7 +1745,7 @@ void GPU_HW::LoadVertices()
|
||||||
const u32 clip_bottom =
|
const u32 clip_bottom =
|
||||||
static_cast<u32>(std::clamp<s32>(max_y_123, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
static_cast<u32>(std::clamp<s32>(max_y_123, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
||||||
|
|
||||||
m_vram_dirty_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
m_vram_dirty_draw_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
||||||
AddDrawTriangleTicks(native_vertex_positions[2][0], native_vertex_positions[2][1],
|
AddDrawTriangleTicks(native_vertex_positions[2][0], native_vertex_positions[2][1],
|
||||||
native_vertex_positions[1][0], native_vertex_positions[1][1],
|
native_vertex_positions[1][0], native_vertex_positions[1][1],
|
||||||
native_vertex_positions[3][0], native_vertex_positions[3][1], rc.shading_enable,
|
native_vertex_positions[3][0], native_vertex_positions[3][1], rc.shading_enable,
|
||||||
|
@ -1831,7 +1867,7 @@ void GPU_HW::LoadVertices()
|
||||||
const u32 clip_bottom =
|
const u32 clip_bottom =
|
||||||
static_cast<u32>(std::clamp<s32>(pos_y + rectangle_height, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
static_cast<u32>(std::clamp<s32>(pos_y + rectangle_height, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
||||||
|
|
||||||
m_vram_dirty_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
m_vram_dirty_draw_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
||||||
AddDrawRectangleTicks(clip_right - clip_left, clip_bottom - clip_top, rc.texture_enable, rc.transparency_enable);
|
AddDrawRectangleTicks(clip_right - clip_left, clip_bottom - clip_top, rc.texture_enable, rc.transparency_enable);
|
||||||
|
|
||||||
if (m_sw_renderer)
|
if (m_sw_renderer)
|
||||||
|
@ -1894,7 +1930,7 @@ void GPU_HW::LoadVertices()
|
||||||
const u32 clip_bottom =
|
const u32 clip_bottom =
|
||||||
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
||||||
|
|
||||||
m_vram_dirty_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
m_vram_dirty_draw_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
||||||
AddDrawLineTicks(clip_right - clip_left, clip_bottom - clip_top, rc.shading_enable);
|
AddDrawLineTicks(clip_right - clip_left, clip_bottom - clip_top, rc.shading_enable);
|
||||||
|
|
||||||
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
|
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
|
||||||
|
@ -1961,7 +1997,7 @@ void GPU_HW::LoadVertices()
|
||||||
const u32 clip_bottom =
|
const u32 clip_bottom =
|
||||||
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
static_cast<u32>(std::clamp<s32>(max_y, m_drawing_area.top, m_drawing_area.bottom)) + 1u;
|
||||||
|
|
||||||
m_vram_dirty_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
m_vram_dirty_draw_rect.Include(clip_left, clip_right, clip_top, clip_bottom);
|
||||||
AddDrawLineTicks(clip_right - clip_left, clip_bottom - clip_top, rc.shading_enable);
|
AddDrawLineTicks(clip_right - clip_left, clip_bottom - clip_top, rc.shading_enable);
|
||||||
|
|
||||||
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
|
// TODO: Should we do a PGXP lookup here? Most lines are 2D.
|
||||||
|
@ -2023,15 +2059,15 @@ bool GPU_HW::BlitVRAMReplacementTexture(const TextureReplacementTexture* tex, u3
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW::IncludeVRAMDirtyRectangle(const Common::Rectangle<u32>& rect)
|
void GPU_HW::IncludeVRAMDirtyRectangle(Common::Rectangle<u32>& rect, const Common::Rectangle<u32>& new_rect)
|
||||||
{
|
{
|
||||||
m_vram_dirty_rect.Include(rect);
|
rect.Include(new_rect);
|
||||||
|
|
||||||
// the vram area can include the texture page, but the game can leave it as-is. in this case, set it as dirty so the
|
// the vram area can include the texture page, but the game can leave it as-is. in this case, set it as dirty so the
|
||||||
// shadow texture is updated
|
// shadow texture is updated
|
||||||
if (!m_draw_mode.IsTexturePageChanged() &&
|
if (!m_draw_mode.IsTexturePageChanged() &&
|
||||||
(m_draw_mode.mode_reg.GetTexturePageRectangle().Intersects(rect) ||
|
(m_draw_mode.mode_reg.GetTexturePageRectangle().Intersects(new_rect) ||
|
||||||
(m_draw_mode.mode_reg.IsUsingPalette() && m_draw_mode.GetTexturePaletteRectangle().Intersects(rect))))
|
(m_draw_mode.mode_reg.IsUsingPalette() && m_draw_mode.GetTexturePaletteRectangle().Intersects(new_rect))))
|
||||||
{
|
{
|
||||||
m_draw_mode.SetTexturePageChanged();
|
m_draw_mode.SetTexturePageChanged();
|
||||||
}
|
}
|
||||||
|
@ -2063,20 +2099,41 @@ ALWAYS_INLINE_RELEASE void GPU_HW::CheckForTexPageOverlap(u32 texpage, u32 min_u
|
||||||
{
|
{
|
||||||
m_current_uv_range.Include(vram_min_u, vram_max_u, vram_min_v, vram_max_v);
|
m_current_uv_range.Include(vram_min_u, vram_max_u, vram_min_v, vram_max_v);
|
||||||
|
|
||||||
DebugAssert(m_vram_dirty_rect.Valid());
|
bool update_drawn = false, update_written = false;
|
||||||
if (m_current_uv_range.Intersects(m_vram_dirty_rect))
|
if (m_texpage_dirty & TEXPAGE_DIRTY_DRAWN_RECT)
|
||||||
{
|
{
|
||||||
GL_INS_FMT("Updating VRAM cache due to UV {{{},{} => {},{}}} intersection with dirty {{{},{} => {},{}}}",
|
DebugAssert(m_vram_dirty_draw_rect.Valid());
|
||||||
m_current_uv_range.left, m_current_uv_range.top, m_current_uv_range.right, m_current_uv_range.bottom,
|
update_drawn = m_current_uv_range.Intersects(m_vram_dirty_draw_rect);
|
||||||
m_vram_dirty_rect.left, m_vram_dirty_rect.top, m_vram_dirty_rect.right, m_vram_dirty_rect.bottom);
|
if (update_drawn)
|
||||||
|
{
|
||||||
|
GL_INS_FMT("Updating VRAM cache due to UV {{{},{} => {},{}}} intersection with dirty DRAW {{{},{} => {},{}}}",
|
||||||
|
m_current_uv_range.left, m_current_uv_range.top, m_current_uv_range.right, m_current_uv_range.bottom,
|
||||||
|
m_vram_dirty_draw_rect.left, m_vram_dirty_draw_rect.top, m_vram_dirty_draw_rect.right,
|
||||||
|
m_vram_dirty_draw_rect.bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_texpage_dirty & TEXPAGE_DIRTY_WRITTEN_RECT)
|
||||||
|
{
|
||||||
|
DebugAssert(m_vram_dirty_write_rect.Valid());
|
||||||
|
update_written = m_current_uv_range.Intersects(m_vram_dirty_write_rect);
|
||||||
|
if (update_written)
|
||||||
|
{
|
||||||
|
GL_INS_FMT("Updating VRAM cache due to UV {{{},{} => {},{}}} intersection with dirty WRITE {{{},{} => {},{}}}",
|
||||||
|
m_current_uv_range.left, m_current_uv_range.top, m_current_uv_range.right, m_current_uv_range.bottom,
|
||||||
|
m_vram_dirty_write_rect.left, m_vram_dirty_write_rect.top, m_vram_dirty_write_rect.right,
|
||||||
|
m_vram_dirty_write_rect.bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_drawn || update_written)
|
||||||
|
{
|
||||||
if (GetBatchVertexCount() > 0)
|
if (GetBatchVertexCount() > 0)
|
||||||
{
|
{
|
||||||
FlushRender();
|
FlushRender();
|
||||||
EnsureVertexBufferSpaceForCurrentCommand();
|
EnsureVertexBufferSpaceForCurrentCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateVRAMReadTexture();
|
UpdateVRAMReadTexture(update_drawn, update_written);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2263,9 +2320,18 @@ void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||||
m_sw_renderer->PushCommand(cmd);
|
m_sw_renderer->PushCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GL_INS_FMT("Dirty draw area before: {},{} => {},{} ({}x{})", m_vram_dirty_draw_rect.left, m_vram_dirty_draw_rect.top,
|
||||||
|
m_vram_dirty_draw_rect.right, m_vram_dirty_draw_rect.bottom, m_vram_dirty_draw_rect.GetWidth(),
|
||||||
|
m_vram_dirty_draw_rect.GetHeight());
|
||||||
|
|
||||||
IncludeVRAMDirtyRectangle(
|
IncludeVRAMDirtyRectangle(
|
||||||
|
m_vram_dirty_draw_rect,
|
||||||
Common::Rectangle<u32>::FromExtents(x, y, width, height).Clamped(0, 0, VRAM_WIDTH, VRAM_HEIGHT));
|
Common::Rectangle<u32>::FromExtents(x, y, width, height).Clamped(0, 0, VRAM_WIDTH, VRAM_HEIGHT));
|
||||||
|
|
||||||
|
GL_INS_FMT("Dirty draw area after: {},{} => {},{} ({}x{})", m_vram_dirty_draw_rect.left, m_vram_dirty_draw_rect.top,
|
||||||
|
m_vram_dirty_draw_rect.right, m_vram_dirty_draw_rect.bottom, m_vram_dirty_draw_rect.GetWidth(),
|
||||||
|
m_vram_dirty_draw_rect.GetHeight());
|
||||||
|
|
||||||
const bool is_oversized = (((x + width) > VRAM_WIDTH || (y + height) > VRAM_HEIGHT));
|
const bool is_oversized = (((x + width) > VRAM_WIDTH || (y + height) > VRAM_HEIGHT));
|
||||||
g_gpu_device->SetPipeline(
|
g_gpu_device->SetPipeline(
|
||||||
m_vram_fill_pipelines[BoolToUInt8(is_oversized)][BoolToUInt8(IsInterlacedRenderingEnabled())].get());
|
m_vram_fill_pipelines[BoolToUInt8(is_oversized)][BoolToUInt8(IsInterlacedRenderingEnabled())].get());
|
||||||
|
@ -2354,7 +2420,7 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b
|
||||||
|
|
||||||
const Common::Rectangle<u32> bounds = GetVRAMTransferBounds(x, y, width, height);
|
const Common::Rectangle<u32> bounds = GetVRAMTransferBounds(x, y, width, height);
|
||||||
DebugAssert(bounds.right <= VRAM_WIDTH && bounds.bottom <= VRAM_HEIGHT);
|
DebugAssert(bounds.right <= VRAM_WIDTH && bounds.bottom <= VRAM_HEIGHT);
|
||||||
IncludeVRAMDirtyRectangle(bounds);
|
IncludeVRAMDirtyRectangle(m_vram_dirty_write_rect, bounds);
|
||||||
|
|
||||||
if (check_mask)
|
if (check_mask)
|
||||||
{
|
{
|
||||||
|
@ -2431,9 +2497,11 @@ void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32
|
||||||
{
|
{
|
||||||
const Common::Rectangle<u32> src_bounds = GetVRAMTransferBounds(src_x, src_y, width, height);
|
const Common::Rectangle<u32> src_bounds = GetVRAMTransferBounds(src_x, src_y, width, height);
|
||||||
const Common::Rectangle<u32> dst_bounds = GetVRAMTransferBounds(dst_x, dst_y, width, height);
|
const Common::Rectangle<u32> dst_bounds = GetVRAMTransferBounds(dst_x, dst_y, width, height);
|
||||||
if (m_vram_dirty_rect.Intersects(src_bounds))
|
const bool intersect_with_draw = m_vram_dirty_draw_rect.Intersects(src_bounds);
|
||||||
UpdateVRAMReadTexture();
|
const bool intersect_with_write = m_vram_dirty_write_rect.Intersects(src_bounds);
|
||||||
IncludeVRAMDirtyRectangle(dst_bounds);
|
if (intersect_with_draw || intersect_with_write)
|
||||||
|
UpdateVRAMReadTexture(intersect_with_draw, intersect_with_write);
|
||||||
|
IncludeVRAMDirtyRectangle(m_vram_dirty_draw_rect, dst_bounds);
|
||||||
|
|
||||||
struct VRAMCopyUBOData
|
struct VRAMCopyUBOData
|
||||||
{
|
{
|
||||||
|
@ -2481,11 +2549,16 @@ void GPU_HW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32
|
||||||
if (!g_gpu_device->GetFeatures().texture_copy_to_self || overlaps_with_self)
|
if (!g_gpu_device->GetFeatures().texture_copy_to_self || overlaps_with_self)
|
||||||
{
|
{
|
||||||
src_tex = m_vram_read_texture.get();
|
src_tex = m_vram_read_texture.get();
|
||||||
if (m_vram_dirty_rect.Intersects(Common::Rectangle<u32>::FromExtents(src_x, src_y, width, height)))
|
|
||||||
UpdateVRAMReadTexture();
|
const Common::Rectangle<u32> src_bounds = GetVRAMTransferBounds(src_x, src_y, width, height);
|
||||||
|
const bool intersect_with_draw = m_vram_dirty_draw_rect.Intersects(src_bounds);
|
||||||
|
const bool intersect_with_write = m_vram_dirty_write_rect.Intersects(src_bounds);
|
||||||
|
if (intersect_with_draw || intersect_with_write)
|
||||||
|
UpdateVRAMReadTexture(intersect_with_draw, intersect_with_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
IncludeVRAMDirtyRectangle(
|
IncludeVRAMDirtyRectangle(
|
||||||
|
m_vram_dirty_draw_rect,
|
||||||
Common::Rectangle<u32>::FromExtents(dst_x, dst_y, width, height).Clamped(0, 0, VRAM_WIDTH, VRAM_HEIGHT));
|
Common::Rectangle<u32>::FromExtents(dst_x, dst_y, width, height).Clamped(0, 0, VRAM_WIDTH, VRAM_HEIGHT));
|
||||||
|
|
||||||
if (m_GPUSTAT.check_mask_before_draw)
|
if (m_GPUSTAT.check_mask_before_draw)
|
||||||
|
@ -2529,21 +2602,30 @@ void GPU_HW::DispatchRenderCommand()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_vram_dirty_rect.Valid() && m_draw_mode.mode_reg.IsUsingPalette() &&
|
if (m_draw_mode.mode_reg.IsUsingPalette())
|
||||||
m_draw_mode.GetTexturePaletteRectangle().Intersects(m_vram_dirty_rect))
|
|
||||||
{
|
{
|
||||||
GL_INS("Palette in VRAM dirty area, flushing cache");
|
const Common::Rectangle<u32> palette_rect = m_draw_mode.GetTexturePaletteRectangle();
|
||||||
if (!IsFlushed())
|
const bool update_drawn = palette_rect.Intersects(m_vram_dirty_draw_rect);
|
||||||
FlushRender();
|
const bool update_written = palette_rect.Intersects(m_vram_dirty_write_rect);
|
||||||
|
if (update_drawn || update_written)
|
||||||
|
{
|
||||||
|
GL_INS("Palette in VRAM dirty area, flushing cache");
|
||||||
|
if (!IsFlushed())
|
||||||
|
FlushRender();
|
||||||
|
|
||||||
UpdateVRAMReadTexture();
|
UpdateVRAMReadTexture(update_drawn, update_written);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_vram_dirty_rect.Valid() && m_draw_mode.mode_reg.GetTexturePageRectangle().Intersects(m_vram_dirty_rect))
|
const Common::Rectangle<u32> page_rect = m_draw_mode.mode_reg.GetTexturePageRectangle();
|
||||||
|
u8 new_texpage_dirty = m_vram_dirty_draw_rect.Intersects(page_rect) ? TEXPAGE_DIRTY_DRAWN_RECT : 0;
|
||||||
|
new_texpage_dirty |= m_vram_dirty_write_rect.Intersects(page_rect) ? TEXPAGE_DIRTY_WRITTEN_RECT : 0;
|
||||||
|
|
||||||
|
if (new_texpage_dirty != 0)
|
||||||
{
|
{
|
||||||
GL_INS("Texpage is in dirty area, checking UV ranges");
|
GL_INS("Texpage is in dirty area, checking UV ranges");
|
||||||
|
m_texpage_dirty = new_texpage_dirty;
|
||||||
m_compute_uv_range = true;
|
m_compute_uv_range = true;
|
||||||
m_texpage_dirty = true;
|
|
||||||
m_current_uv_range.SetInvalid();
|
m_current_uv_range.SetInvalid();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2551,8 +2633,7 @@ void GPU_HW::DispatchRenderCommand()
|
||||||
m_compute_uv_range = m_clamp_uvs;
|
m_compute_uv_range = m_clamp_uvs;
|
||||||
if (m_texpage_dirty)
|
if (m_texpage_dirty)
|
||||||
GL_INS("Texpage is no longer dirty");
|
GL_INS("Texpage is no longer dirty");
|
||||||
|
m_texpage_dirty = 0;
|
||||||
m_texpage_dirty = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2669,6 +2750,10 @@ void GPU_HW::FlushRender()
|
||||||
GL_SCOPE_FMT("Hardware Draw {}", ++s_draw_number);
|
GL_SCOPE_FMT("Hardware Draw {}", ++s_draw_number);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
GL_INS_FMT("Dirty draw area: {},{} => {},{} ({}x{})", m_vram_dirty_draw_rect.left, m_vram_dirty_draw_rect.top,
|
||||||
|
m_vram_dirty_draw_rect.right, m_vram_dirty_draw_rect.bottom, m_vram_dirty_draw_rect.GetWidth(),
|
||||||
|
m_vram_dirty_draw_rect.GetHeight());
|
||||||
|
|
||||||
if (m_batch_ubo_dirty)
|
if (m_batch_ubo_dirty)
|
||||||
{
|
{
|
||||||
g_gpu_device->UploadUniformBuffer(&m_batch_ubo_data, sizeof(m_batch_ubo_data));
|
g_gpu_device->UploadUniformBuffer(&m_batch_ubo_data, sizeof(m_batch_ubo_data));
|
||||||
|
@ -2707,7 +2792,7 @@ void GPU_HW::UpdateDisplay()
|
||||||
{
|
{
|
||||||
if (IsUsingMultisampling())
|
if (IsUsingMultisampling())
|
||||||
{
|
{
|
||||||
UpdateVRAMReadTexture();
|
UpdateVRAMReadTexture(true, true);
|
||||||
SetDisplayTexture(m_vram_read_texture.get(), 0, 0, m_vram_read_texture->GetWidth(),
|
SetDisplayTexture(m_vram_read_texture.get(), 0, 0, m_vram_read_texture->GetWidth(),
|
||||||
m_vram_read_texture->GetHeight());
|
m_vram_read_texture->GetHeight());
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,12 @@ private:
|
||||||
MAX_VERTICES_FOR_RECTANGLE = 6 * (((MAX_PRIMITIVE_WIDTH + (TEXTURE_PAGE_WIDTH - 1)) / TEXTURE_PAGE_WIDTH) + 1u) *
|
MAX_VERTICES_FOR_RECTANGLE = 6 * (((MAX_PRIMITIVE_WIDTH + (TEXTURE_PAGE_WIDTH - 1)) / TEXTURE_PAGE_WIDTH) + 1u) *
|
||||||
(((MAX_PRIMITIVE_HEIGHT + (TEXTURE_PAGE_HEIGHT - 1)) / TEXTURE_PAGE_HEIGHT) + 1u)
|
(((MAX_PRIMITIVE_HEIGHT + (TEXTURE_PAGE_HEIGHT - 1)) / TEXTURE_PAGE_HEIGHT) + 1u)
|
||||||
};
|
};
|
||||||
|
enum : u8
|
||||||
|
{
|
||||||
|
TEXPAGE_DIRTY_DRAWN_RECT = (1 << 0),
|
||||||
|
TEXPAGE_DIRTY_WRITTEN_RECT = (1 << 1),
|
||||||
|
};
|
||||||
|
|
||||||
static_assert(GPUDevice::MIN_TEXEL_BUFFER_ELEMENTS >= (VRAM_WIDTH * VRAM_HEIGHT));
|
static_assert(GPUDevice::MIN_TEXEL_BUFFER_ELEMENTS >= (VRAM_WIDTH * VRAM_HEIGHT));
|
||||||
|
|
||||||
struct BatchVertex
|
struct BatchVertex
|
||||||
|
@ -134,7 +140,7 @@ private:
|
||||||
void PrintSettingsToLog();
|
void PrintSettingsToLog();
|
||||||
void CheckSettings();
|
void CheckSettings();
|
||||||
|
|
||||||
void UpdateVRAMReadTexture();
|
void UpdateVRAMReadTexture(bool drawn, bool written);
|
||||||
void UpdateDepthBufferFromMaskBit();
|
void UpdateDepthBufferFromMaskBit();
|
||||||
void ClearDepthBuffer();
|
void ClearDepthBuffer();
|
||||||
void SetScissor();
|
void SetScissor();
|
||||||
|
@ -150,7 +156,7 @@ private:
|
||||||
|
|
||||||
void SetFullVRAMDirtyRectangle();
|
void SetFullVRAMDirtyRectangle();
|
||||||
void ClearVRAMDirtyRectangle();
|
void ClearVRAMDirtyRectangle();
|
||||||
void IncludeVRAMDirtyRectangle(const Common::Rectangle<u32>& rect);
|
void IncludeVRAMDirtyRectangle(Common::Rectangle<u32>& rect, const Common::Rectangle<u32>& new_rect);
|
||||||
void CheckForTexPageOverlap(u32 texpage, u32 min_u, u32 min_v, u32 max_u, u32 max_v);
|
void CheckForTexPageOverlap(u32 texpage, u32 min_u, u32 min_v, u32 max_u, u32 max_v);
|
||||||
|
|
||||||
bool IsFlushed() const;
|
bool IsFlushed() const;
|
||||||
|
@ -249,7 +255,7 @@ private:
|
||||||
bool m_clamp_uvs = false;
|
bool m_clamp_uvs = false;
|
||||||
bool m_compute_uv_range = false;
|
bool m_compute_uv_range = false;
|
||||||
bool m_pgxp_depth_buffer = false;
|
bool m_pgxp_depth_buffer = false;
|
||||||
bool m_texpage_dirty = false;
|
u8 m_texpage_dirty = 0;
|
||||||
|
|
||||||
BatchConfig m_batch;
|
BatchConfig m_batch;
|
||||||
|
|
||||||
|
@ -258,7 +264,8 @@ private:
|
||||||
BatchUBOData m_batch_ubo_data = {};
|
BatchUBOData m_batch_ubo_data = {};
|
||||||
|
|
||||||
// Bounding box of VRAM area that the GPU has drawn into.
|
// Bounding box of VRAM area that the GPU has drawn into.
|
||||||
Common::Rectangle<u32> m_vram_dirty_rect;
|
Common::Rectangle<u32> m_vram_dirty_draw_rect;
|
||||||
|
Common::Rectangle<u32> m_vram_dirty_write_rect;
|
||||||
Common::Rectangle<u32> m_current_uv_range;
|
Common::Rectangle<u32> m_current_uv_range;
|
||||||
|
|
||||||
// [depth_test][render_mode][texture_mode][transparency_mode][dithering][interlacing]
|
// [depth_test][render_mode][texture_mode][transparency_mode][dithering][interlacing]
|
||||||
|
|
Loading…
Reference in New Issue