GS/HW: Allow offsetting in to a target if full contained.

This commit is contained in:
refractionpcsx2 2025-01-26 16:35:49 +00:00 committed by Ty
parent 85bd46e457
commit b568e1387a
1 changed files with 31 additions and 1 deletions

View File

@ -1189,7 +1189,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
const u32* const clut = g_gs_renderer->m_mem.m_clut;
GSTexture* const gpu_clut = (psm_s.pal > 0) ? g_gs_renderer->m_mem.m_clut.GetGPUTexture() : nullptr;
const SourceRegion region = SourceRegion::Create(TEX0, CLAMP);
SourceRegion region = SourceRegion::Create(TEX0, CLAMP);
// Prevent everything going to rubbish if a game somehow sends a TW/TH above 10, and region isn't being used.
if ((TEX0.TW > 10 && !region.HasX()) || (TEX0.TH > 10 && !region.HasY()))
@ -1754,6 +1754,13 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
}
else
{
GSVector4i inside_block_boundary_rect = r;
inside_block_boundary_rect.x = (inside_block_boundary_rect.x + (psm_s.bs.x - 1)) & ~(psm_s.bs.x - 1);
inside_block_boundary_rect.y = (inside_block_boundary_rect.y + (psm_s.bs.y - 1)) & ~(psm_s.bs.y - 1);
// Round up to the nearst block boundary for lookup to avoid problems due to bilinear and inclusive rects.
inside_block_boundary_rect.z = inside_block_boundary_rect.z & ~(psm_s.bs.x - 1);
inside_block_boundary_rect.w = inside_block_boundary_rect.w & ~(psm_s.bs.y - 1);
// Some games, such as Tomb Raider: Underworld, and Destroy All Humans shift the texture pointer
// back behind the framebuffer, but then offset their texture coordinates to compensate. Why they
// do this, I have no idea... but it's usually only a page wide/high of an offset. Thankfully,
@ -1817,6 +1824,29 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
else
continue;
}
// Else read it back, might be our only choice. Ridge Racer writes to the right side of 0x1a40 for headlights, then tries to access it with the base of 0x9a0
// naturally, it misses here. But let's make sure the formats match well enough. coordinates could be too low by half a pixel when on the edge of the screen, so need a conservitive rect.
else if (bw == t->m_TEX0.TBW && GSLocalMemory::m_psm[psm].bpp == GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp && t->Inside(bp, bw, psm, inside_block_boundary_rect))
{
if (!t->HasValidBitsForFormat(psm, req_color, req_alpha, true))
continue;
GIFRegCLAMP fake_CLAMP;
fake_CLAMP.WMS = CLAMP_REGION_CLAMP;
fake_CLAMP.WMT = CLAMP_REGION_CLAMP;
fake_CLAMP.MINU = 0;
fake_CLAMP.MINV = 0;
fake_CLAMP.MAXV = std::min(static_cast<u32>(1u << TEX0.TH), 1022u);
fake_CLAMP.MAXU = std::min(static_cast<u32>(1u << TEX0.TW), 1022u);
region = SourceRegion::Create(TEX0, fake_CLAMP);
const GSVector4i custom_offset_rect = TranslateAlignedRectByPage(t, bp, psm, bw, block_boundary_rect);
x_offset = custom_offset_rect.x;
y_offset = custom_offset_rect.y;
dst = t;
tex_merge_rt = false;
found_t = true;
}
}
}
}