Skip to content

Commit

Permalink
GS/TC: Kill old target if the two are misaligned.
Browse files Browse the repository at this point in the history
  • Loading branch information
lightningterror committed Aug 5, 2024
1 parent 15dfc04 commit cc18340
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 13 deletions.
48 changes: 36 additions & 12 deletions pcsx2/GS/Renderers/HW/GSTextureCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2090,7 +2090,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe

std::swap(dst->m_texture, tex);
PreloadTarget(TEX0, size, GSVector2i(dst->m_valid.z, dst->m_valid.w), is_frame, preload,
preserve_target, draw_rect, dst);
preserve_target, draw_rect, dst, fbmask);
g_gs_device->StretchRect(tex, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), dst->m_texture,
GSVector4(dst->m_texture->GetRect()), false, false, false, true);
g_gs_device->Recycle(tex);
Expand Down Expand Up @@ -2356,7 +2356,7 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe
if (!dst) [[unlikely]]
return nullptr;

const bool was_clear = PreloadTarget(TEX0, size, valid_size, is_frame, preload, preserve_target, draw_rect, dst, src);
const bool was_clear = PreloadTarget(TEX0, size, valid_size, is_frame, preload, preserve_target, draw_rect, dst, fbmask, src);

dst->m_is_frame = is_frame;

Expand Down Expand Up @@ -2443,7 +2443,7 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe
}

bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, bool is_frame,
bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, GSTextureCache::Source* src)
bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, u32 fbmask, GSTextureCache::Source* src)
{
// In theory new textures contain invalidated data. Still in theory a new target
// must contains the content of the GS memory.
Expand Down Expand Up @@ -2605,6 +2605,28 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
if (dst != t && t->m_TEX0.TBW == dst->m_TEX0.TBW && t->m_TEX0.PSM == dst->m_TEX0.PSM && t->m_TEX0.TBW > 4)
if (t->Overlaps(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst->m_valid))
{
// If the two targets are misaligned, it's likely a relocation, so we can just kill the old target.
const bool full_coverage = (g_gs_renderer->m_primitive_covers_without_gaps == g_gs_renderer->NoGapsType::FullCover);
if (full_coverage && ((((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) % dst->m_TEX0.TBW) != 0))
{
const u32 temp_mask = fbmask &= GSLocalMemory::m_psm[dst->m_TEX0.PSM].fmsk;
if (temp_mask)
{
t->m_valid_rgb &= !!(temp_mask & 0x00FFFFFF);
t->m_valid_alpha_low &= !!(temp_mask & 0x0F000000);
t->m_valid_alpha_high &= !!(temp_mask & 0xF0000000);
i++;
}
else
{
InvalidateSourcesFromTarget(t);
i = list.erase(j);
delete t;
}

continue;
}

// could be overwriting a double buffer, so if it's the second half of it, just reduce the size down to half.
if (((((t->UnwrappedEndBlock() + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == dst->m_TEX0.TBP0)
{
Expand All @@ -2628,34 +2650,36 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
continue;
}

const int dst_offset = ((((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) / dst->m_TEX0.TBW) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y);
const int dst_offset_scaled = dst_offset * dst->m_scale;
const GSVector4i dst_rect = GSVector4i(t->m_valid.x, dst_offset, t->m_valid.z, dst_offset + overlapping_pages_height);
if (((!hw_clear && (preserve_target || preload)) || dst_rect.rintersect(draw_rect).rempty()) && dst->GetScale() == t->GetScale())
const int dst_offset_width = (((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) % dst->m_TEX0.TBW) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.x;
const int dst_offset_height = ((((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) / dst->m_TEX0.TBW) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y);
const int dst_offset_scaled_width = dst_offset_width * dst->m_scale;
const int dst_offset_scaled_height = dst_offset_height * dst->m_scale;
const GSVector4i dst_rect_scale = GSVector4i(t->m_valid.x, dst_offset_height, t->m_valid.z, dst_offset_height + overlapping_pages_height);
if (((!hw_clear && (preserve_target || preload)) || dst_rect_scale.rintersect(draw_rect).rempty()) && dst->GetScale() == t->GetScale())
{
const int copy_width = (t->m_texture->GetWidth()) > (dst->m_texture->GetWidth()) ? (dst->m_texture->GetWidth()) : t->m_texture->GetWidth();
const int copy_width = ((t->m_texture->GetWidth()) > (dst->m_texture->GetWidth()) ? (dst->m_texture->GetWidth()) : t->m_texture->GetWidth()) - dst_offset_scaled_width;
const int copy_height = overlapping_pages_height * t->m_scale;

GL_INS("RT double buffer copy from FBP 0x%x, %dx%d => %d,%d", t->m_TEX0.TBP0, copy_width, copy_height, 0, dst_offset_scaled);
GL_INS("RT double buffer copy from FBP 0x%x, %dx%d => %d,%d", t->m_TEX0.TBP0, copy_width, copy_height, 0, dst_offset_scaled_height);

pxAssert(copy_width <= dst->GetTexture()->GetWidth() && copy_height <= dst->GetTexture()->GetHeight() &&
copy_width <= t->GetTexture()->GetWidth() && copy_height <= t->GetTexture()->GetHeight());

pxAssert(dst_offset_scaled > 0);
pxAssert(dst_offset_scaled_height > 0);

// Clear the dirty first
dst->Update();
// Invalidate has been moved to after DrawPrims(), because we might kill the current sources' backing.
if (!t->m_valid_rgb || !(t->m_valid_alpha_high || t->m_valid_alpha_low) || t->m_scale != dst->m_scale)
{
const GSVector4 src_rect = GSVector4(0, 0, copy_width, copy_height) / (GSVector4(t->m_texture->GetSize()).xyxy());
const GSVector4 dst_rect = GSVector4(0, dst_offset, copy_width, dst_offset + copy_height);
const GSVector4 dst_rect = GSVector4(dst_offset_scaled_width, dst_offset_scaled_height, dst_offset_scaled_width + copy_width, dst_offset_scaled_width + copy_height);
g_gs_device->StretchRect(t->m_texture, src_rect, dst->m_texture, dst_rect, t->m_valid_rgb, t->m_valid_rgb, t->m_valid_rgb, t->m_valid_alpha_high || t->m_valid_alpha_low);
}
else
{
// Invalidate has been moved to after DrawPrims(), because we might kill the current sources' backing.
g_gs_device->CopyRect(t->m_texture, dst->m_texture, GSVector4i(0, 0, copy_width, copy_height), 0, dst_offset_scaled);
g_gs_device->CopyRect(t->m_texture, dst->m_texture, GSVector4i(0, 0, copy_width, copy_height), dst_offset_scaled_width, dst_offset_scaled_height);
}
}

Expand Down
2 changes: 1 addition & 1 deletion pcsx2/GS/Renderers/HW/GSTextureCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ class GSTextureCache
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t, bool half_right, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region);

bool PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, bool is_frame,
bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, GSTextureCache::Source* src = nullptr);
bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, u32 fbmask, GSTextureCache::Source* src = nullptr);

// Returns scaled texture size.
static GSVector2i ScaleRenderTargetSize(const GSVector2i& sz, float scale);
Expand Down

0 comments on commit cc18340

Please sign in to comment.