diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index ddc9ad429a..5c340dc87b 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -3358,6 +3358,15 @@ void GSRendererHW::Draw() if (ds->m_TEX0.TBP0 != z_address_info.ZBP || z_address_info.offset != static_cast(vertical_offset - z_vertical_offset)) g_texture_cache->InvalidateTemporaryZ(); + else if (!m_r.rintersect(z_address_info.rect_since + GSVector4i(0, z_address_info.offset, 0, z_address_info.offset)).rempty() && m_cached_ctx.TEST.ZTST > ZTST_ALWAYS) + { + GL_CACHE("RT in RT Updating Z copy on draw %d z_offset %d", s_n, z_address_info.offset); + GSVector4i dRect = GSVector4i(z_address_info.rect_since.x * ds->m_scale, (z_address_info.offset + z_address_info.rect_since.y) * ds->m_scale, (z_address_info.rect_since.z + (1.0f / ds->m_scale)) * ds->m_scale, (z_address_info.offset + z_address_info.rect_since.w + (1.0f / ds->m_scale)) * ds->m_scale); + g_gs_device->StretchRect(ds->m_texture, GSVector4(z_address_info.rect_since.x / static_cast(ds->m_unscaled_size.x), z_address_info.rect_since.y / static_cast(ds->m_unscaled_size.y), (z_address_info.rect_since.z + (1.0f / ds->m_scale)) / static_cast(ds->m_unscaled_size.x), (z_address_info.rect_since.w + (1.0f / ds->m_scale)) / static_cast(ds->m_unscaled_size.y)), g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); + g_perfmon.Put(GSPerfMon::TextureCopies, 1); + z_address_info.rect_since = GSVector4i::zero(); + g_texture_cache->SetTemporaryZInfo(z_address_info); + } } if (g_texture_cache->GetTemporaryZ() == nullptr) @@ -4267,10 +4276,11 @@ void GSRendererHW::Draw() GSTextureCache::TempZAddress z_address_info = g_texture_cache->GetTemporaryZInfo(); if (ds->m_TEX0.TBP0 == z_address_info.ZBP) { - GL_CACHE("RT in RT Updating Z copy on draw %d z_offset %d", s_n, z_address_info.offset); - GSVector4i dRect = GSVector4i(real_rect.x * ds->m_scale, (z_address_info.offset + real_rect.y) * ds->m_scale, (real_rect.z + (1.0f / ds->m_scale)) * ds->m_scale, (z_address_info.offset + real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale); - g_gs_device->StretchRect(ds->m_texture, GSVector4(real_rect.x / static_cast(ds->m_unscaled_size.x), real_rect.y / static_cast(ds->m_unscaled_size.y), (real_rect.z + (1.0f / ds->m_scale)) / static_cast(ds->m_unscaled_size.x), (real_rect.w + (1.0f / ds->m_scale)) / static_cast(ds->m_unscaled_size.y)), g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); - g_perfmon.Put(GSPerfMon::TextureCopies, 1); + if (z_address_info.rect_since.rempty()) + z_address_info.rect_since = real_rect; + else + z_address_info.rect_since = z_address_info.rect_since.runion(real_rect); + g_texture_cache->SetTemporaryZInfo(z_address_info); } } } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 21bf9f31d3..9085e39cc7 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -2259,6 +2259,15 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe { const GSLocalMemory::psm_t& s_psm = GSLocalMemory::m_psm[TEX0.PSM]; + // If it overlaps but the target is huge and the Z isn't offset, we need to split the buffer, so let's shrink this one down. + // 896 is just 448 * 2,just gives the buffer chance to be larger than normal, in case they do something like 640x640, or something ridiculous. + if (!is_shuffle && (ds && offset == 0 && (t->m_valid.w >= 896) && ((((t->m_end_block + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) <= bp)) + { + t->m_valid.w /= 2; + t->m_end_block = ((((t->m_end_block + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) - 1; + continue; + } + // I know what you're thinking, and I hate the guy who wrote it too (me). Project Snowblind, Tomb Raider etc decide to offset where they're drawing using a channel shuffle, and this gets messy, so best just to kill the old target. if (is_shuffle && src && src->m_TEX0.PSM == PSMT8 && GSRendererHW::GetInstance()->m_context->FRAME.FBW == 1 && t->m_last_draw != (GSState::s_n - 1) && src->m_from_target && (src->m_from_target->m_TEX0.TBP0 == src->m_TEX0.TBP0 || (((src->m_TEX0.TBP0 - src->m_from_target->m_TEX0.TBP0) >> 5) % std::max(src->m_from_target->m_TEX0.TBW, 1U) == 0)) && widthpage_offset && src->m_from_target != t) { @@ -7759,6 +7768,11 @@ void GSTextureCache::SetTemporaryZInfo(u32 address, u32 offset) { m_temporary_z_info.ZBP = address; m_temporary_z_info.offset = offset; + m_temporary_z_info.rect_since = GSVector4i::zero(); +} +void GSTextureCache::SetTemporaryZInfo(TempZAddress address_info) +{ + m_temporary_z_info = address_info; } void GSTextureCache::SetTemporaryZ(GSTexture* temp_z) diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 7f3c3bc4a1..d0c65423f7 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -210,6 +210,7 @@ public: { u32 ZBP; u32 offset; + GSVector4i rect_since; }; class Target : public Surface @@ -564,6 +565,7 @@ public: GSTexture* GetTemporaryZ(); TempZAddress GetTemporaryZInfo(); void SetTemporaryZInfo(u32 address, u32 offset); + void SetTemporaryZInfo(TempZAddress address_info); /// Invalidates a temporary Z, a partial copy only created from the current DS for the current draw when Z is not offset but RT is. void InvalidateTemporaryZ();