Compare commits

...

3 Commits

Author SHA1 Message Date
refractionpcsx2
7ea33400a9 GS: Update the stored transfer rect if worked out to be different 2026-01-29 14:13:39 +01:00
refractionpcsx2
32a3e8e62d GS/HW: On EE->GS transfer only invalidate area actually transferred 2026-01-29 14:13:39 +01:00
refractionpcsx2
fa953d7bb3 GS/TC: Allow creation of target during GS->GS transfer with offset 2026-01-29 14:12:45 +01:00
2 changed files with 26 additions and 2 deletions

View File

@@ -1899,6 +1899,30 @@ void GSState::FlushWrite()
r = m_tr.rect;
// If the end isn't where it said it would be, we need to calculate the end point.
// Star Wars - The Clone Wars just sets the rect to 16x4095 then YOLO's about half a page, then kills the transfer.
// If we just nuke the whole lot, even though nothing has been transferred, we risk killing data we don't mean to.
if (m_tr.end < m_tr.total && GSIsHardwareRenderer())
{
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[m_tr.m_blit.DPSM];
// Convert to nibbles then back to bytes after, in case trbpp is 4.
const u32 in_data_pixel_count = (((len * 2) + ((psm_s.trbpp / 4) - 1)) / (psm_s.trbpp / 4));
const u32 rect_pixel_count = r.width() * r.height();
if (rect_pixel_count > in_data_pixel_count)
{
const int calculated_height = ((in_data_pixel_count + (r.width() - 1)) / r.width());
// Just setting the height should be okay...
r.w = std::max(r.y + calculated_height, psm_s.bs.y);
if (m_draw_transfers.size() > 0 && m_tr.m_blit.DBP == m_draw_transfers.back().blit.DBP)
{
m_draw_transfers.back().rect = r;
}
}
}
InvalidateVideoMem(m_env.BITBLTBUF, r);
const GSLocalMemory::writeImage wi = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].wi;

View File

@@ -5091,14 +5091,14 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
// We use dx/dy == 0 and the TBW check as a safeguard to make sure these go through to local memory.
// We can also recreate the target if it's previously been created in the height cache with a valid size.
// Good test case for this is the Xenosaga I cutscene transitions, or Gradius V.
if (src && !dst && ((dx == 0 && dy == 0 && ((static_cast<u32>(w) + 63) / 64) <= DBW) || HasTargetInHeightCache(DBP, DBW, DPSM, 10)))
if (src && !dst && ((((dx == 0 && dy == 0) || (dx == sx && dy == sy && DBW == src->m_TEX0.TBW)) && ((static_cast<u32>(w) + 63) / 64) <= DBW) || HasTargetInHeightCache(DBP, DBW, DPSM, 10)))
{
GIFRegTEX0 new_TEX0 = {};
new_TEX0.TBP0 = DBP;
new_TEX0.TBW = DBW;
new_TEX0.PSM = DPSM;
const GSVector2i target_size = GetTargetSize(DBP, DBW, DPSM, Common::AlignUpPow2(w, 64), h);
const GSVector2i target_size = (dx == 0 && dy == 0) ? GetTargetSize(DBP, DBW, DPSM, Common::AlignUpPow2(w, 64), h) : GSVector2i(src->m_valid.z, src->m_valid.w);
dst = LookupTarget(new_TEX0, target_size, src->m_scale, src->m_type);
if (!dst)
{