GS/HW: Only update dirty if intersects + fix tex is rt regions

This commit is contained in:
refractionpcsx2 2023-12-16 16:53:50 +00:00
parent 3230287a5f
commit c552d717ff
3 changed files with 146 additions and 49 deletions

View File

@ -804,7 +804,20 @@ bool GSRendererHW::IsPossibleChannelShuffle() const
const int mask = (((m_vt.m_max.p - m_vt.m_min.p) <= GSVector4(64.0f)).mask() & 0x3); const int mask = (((m_vt.m_max.p - m_vt.m_min.p) <= GSVector4(64.0f)).mask() & 0x3);
if (mask == 0x3) // single_page if (mask == 0x3) // single_page
return true; {
const GSVertex* v = &m_vertex.buff[0];
const int draw_width = std::abs(v[1].XYZ.X - v[0].XYZ.X) >> 4;
const int draw_height = std::abs(v[1].XYZ.Y - v[0].XYZ.Y) >> 4;
const bool mask_clamp = (m_cached_ctx.CLAMP.WMS | m_cached_ctx.CLAMP.WMT) & 0x2;
const bool draw_match = (draw_height == 2) || (draw_width == 8);
if (draw_match || mask_clamp)
return true;
else
return false;
}
else if (mask != 0x1) // Not a single page in width. else if (mask != 0x1) // Not a single page in width.
return false; return false;
@ -813,7 +826,18 @@ bool GSRendererHW::IsPossibleChannelShuffle() const
if (m_cached_ctx.TEX0.TBW == (m_cached_ctx.FRAME.FBW * 2) && if (m_cached_ctx.TEX0.TBW == (m_cached_ctx.FRAME.FBW * 2) &&
GSLocalMemory::IsPageAligned(m_cached_ctx.FRAME.PSM, GSVector4i(m_vt.m_min.p.upld(m_vt.m_max.p)))) GSLocalMemory::IsPageAligned(m_cached_ctx.FRAME.PSM, GSVector4i(m_vt.m_min.p.upld(m_vt.m_max.p))))
{ {
return true; const GSVertex* v = &m_vertex.buff[0];
const int draw_width = std::abs(v[1].XYZ.X - v[0].XYZ.X) >> 4;
const int draw_height = std::abs(v[1].XYZ.Y - v[0].XYZ.Y) >> 4;
const bool mask_clamp = (m_cached_ctx.CLAMP.WMS | m_cached_ctx.CLAMP.WMT) & 0x2;
const bool draw_match = (draw_height == 2) || (draw_width == 8);
if (draw_match || mask_clamp)
return true;
else
return false;
} }
return false; return false;
@ -2195,7 +2219,7 @@ void GSRendererHW::Draw()
} }
GIFRegTEX0 FRAME_TEX0; GIFRegTEX0 FRAME_TEX0;
bool rt_32bit = false; bool shuffle_target = false;
if (!no_rt && m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0 && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) if (!no_rt && m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0 && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16)
{ {
// FBW is going to be wrong for channel shuffling into a new target, so take it from the source. // FBW is going to be wrong for channel shuffling into a new target, so take it from the source.
@ -2208,11 +2232,24 @@ void GSRendererHW::Draw()
fm); fm);
if (tgt) if (tgt)
rt_32bit = tgt->m_32_bits_fmt; shuffle_target = tgt->m_32_bits_fmt;
else
{
const GSVertex* v = &m_vertex.buff[0];
const int first_x = ((v[0].XYZ.X - m_context->XYOFFSET.OFX) + 8) >> 4;
const int first_u = PRIM->FST ? ((v[0].U + 8) >> 4) : static_cast<int>(((1 << m_cached_ctx.TEX0.TW) * (v[0].ST.S / v[1].RGBAQ.Q)) + 0.5f);
const int second_u = PRIM->FST ? ((v[1].U + 8) >> 4) : static_cast<int>(((1 << m_cached_ctx.TEX0.TW) * (v[1].ST.S / v[1].RGBAQ.Q)) + 0.5f);
const bool shuffle_coords = (first_x ^ first_u) & 8;
const int draw_width = std::abs(v[1].XYZ.X - v[0].XYZ.X) >> 4;
const int read_width = std::abs(second_u - first_u);
shuffle_target = shuffle_coords && draw_width == 8 && draw_width == read_width;
}
tgt = nullptr; tgt = nullptr;
} }
const bool possible_shuffle = ((rt_32bit && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) || m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0) || IsPossibleChannelShuffle(); const bool possible_shuffle = ((shuffle_target && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) || m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0) || IsPossibleChannelShuffle();
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && m_context->ALPHA.C == 0 && m_env.TEXA.AEM; const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && m_context->ALPHA.C == 0 && m_env.TEXA.AEM;
const bool req_color = (!PRIM->ABE || (PRIM->ABE && (m_context->ALPHA.IsUsingCs() || need_aem_color))) && (possible_shuffle || (m_cached_ctx.FRAME.FBMSK & (fm_mask & 0x00FFFFFF)) != (fm_mask & 0x00FFFFFF)); const bool req_color = (!PRIM->ABE || (PRIM->ABE && (m_context->ALPHA.IsUsingCs() || need_aem_color))) && (possible_shuffle || (m_cached_ctx.FRAME.FBMSK & (fm_mask & 0x00FFFFFF)) != (fm_mask & 0x00FFFFFF));
const bool alpha_used = m_context->TEX0.TCC && ((PRIM->ABE && m_context->ALPHA.IsUsingAs()) || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST > ATST_ALWAYS) || (possible_shuffle || (m_cached_ctx.FRAME.FBMSK & (fm_mask & 0xFF000000)) != (fm_mask & 0xFF000000))); const bool alpha_used = m_context->TEX0.TCC && ((PRIM->ABE && m_context->ALPHA.IsUsingAs()) || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST > ATST_ALWAYS) || (possible_shuffle || (m_cached_ctx.FRAME.FBMSK & (fm_mask & 0xFF000000)) != (fm_mask & 0xFF000000)));
@ -2224,8 +2261,8 @@ void GSRendererHW::Draw()
m_process_texture = false; m_process_texture = false;
else else
{ {
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME.Block(), req_color, req_alpha) : src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME.Block(), req_color, req_alpha) :
g_texture_cache->LookupSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap >= HWMipmapLevel::Basic || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr, g_texture_cache->LookupSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap >= HWMipmapLevel::Basic || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME.Block(), req_color, req_alpha); possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME.Block(), req_color, req_alpha);
if (!src) [[unlikely]] if (!src) [[unlikely]]
@ -2631,9 +2668,19 @@ void GSRendererHW::Draw()
ds->UpdateValidChannels(ZBUF_TEX0.PSM, zm); ds->UpdateValidChannels(ZBUF_TEX0.PSM, zm);
if (rt) if (rt)
rt->Update(); {
if (m_texture_shuffle || m_channel_shuffle || (!rt->m_dirty.empty() && !rt->m_dirty.GetTotalRect(rt->m_TEX0, rt->m_unscaled_size).rintersect(m_r).rempty()))
rt->Update();
else
rt->m_age = 0;
}
if (ds) if (ds)
ds->Update(); {
if (m_texture_shuffle || m_channel_shuffle || (!ds->m_dirty.empty() && !ds->m_dirty.GetTotalRect(ds->m_TEX0, ds->m_unscaled_size).rintersect(m_r).rempty()))
ds->Update();
else
ds->m_age = 0;
}
const GSVector2i resolution = PCRTCDisplays.GetResolution(); const GSVector2i resolution = PCRTCDisplays.GetResolution();
GSTextureCache::Target* old_rt = nullptr; GSTextureCache::Target* old_rt = nullptr;

View File

@ -776,7 +776,7 @@ __ri static GSTextureCache::Source* FindSourceInMap(const GIFRegTEX0& TEX0, cons
return nullptr; return nullptr;
} }
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, const bool linear, const u32 frame_fbp, bool req_color, bool req_alpha, bool palette) GSTextureCache::Source* GSTextureCache::LookupDepthSource(const bool is_depth, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, const bool linear, const u32 frame_fbp, bool req_color, bool req_alpha, bool palette)
{ {
if (GSConfig.UserHacks_DisableDepthSupport) if (GSConfig.UserHacks_DisableDepthSupport)
{ {
@ -811,7 +811,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
for (auto t : m_dst[DepthStencil]) for (auto t : m_dst[DepthStencil])
{ {
if (!t->m_used || !t->m_dirty.empty()) if (!t->m_used || (!t->m_dirty.empty() && !is_depth))
continue; continue;
if (GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM)) if (GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM))
@ -907,7 +907,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
} }
} }
if (!dst) if (!dst && is_depth)
{ {
// Retry on the render target (Silent Hill 4) // Retry on the render target (Silent Hill 4)
for (auto t : m_dst[RenderTarget]) for (auto t : m_dst[RenderTarget])
@ -966,7 +966,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
else else
{ {
// This is a bit of a worry, since it could load junk from local memory... but it's better than skipping the draw. // This is a bit of a worry, since it could load junk from local memory... but it's better than skipping the draw.
return LookupSource(TEX0, TEXA, CLAMP, r, nullptr, possible_shuffle, linear, frame_fbp, req_color, req_alpha); return is_depth ? LookupSource(false, TEX0, TEXA, CLAMP, r, nullptr, possible_shuffle, linear, frame_fbp, req_color, req_alpha) : nullptr;
} }
pxAssert(src->m_texture); pxAssert(src->m_texture);
@ -975,7 +975,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
return src; return src;
} }
GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle, const bool linear, const u32 frame_fbp, bool req_color, bool req_alpha) GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle, const bool linear, const u32 frame_fbp, bool req_color, bool req_alpha)
{ {
GL_CACHE("TC: Lookup Source <%d,%d => %d,%d> (0x%x, %s, BW: %u, CBP: 0x%x, TW: %d, TH: %d)", r.x, r.y, r.z, r.w, TEX0.TBP0, psm_str(TEX0.PSM), TEX0.TBW, TEX0.CBP, 1 << TEX0.TW, 1 << TEX0.TH); GL_CACHE("TC: Lookup Source <%d,%d => %d,%d> (0x%x, %s, BW: %u, CBP: 0x%x, TW: %d, TH: %d)", r.x, r.y, r.z, r.w, TEX0.TBP0, psm_str(TEX0.PSM), TEX0.TBW, TEX0.CBP, 1 << TEX0.TW, 1 << TEX0.TH);
@ -1010,7 +1010,6 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
if (!src) if (!src)
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[lookup_page]); src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[lookup_page]);
Target* dst = nullptr; Target* dst = nullptr;
bool half_right = false; bool half_right = false;
int x_offset = 0; int x_offset = 0;
@ -1026,6 +1025,14 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
const u32 psm = TEX0.PSM; const u32 psm = TEX0.PSM;
const u32 bw = TEX0.TBW; const u32 bw = TEX0.TBW;
GSVector4i req_rect = r;
// The read area might be offset but the start of the texture is at the beginning of the space.
req_rect.x = 0;
req_rect.y = 0;
if (region.HasX() || region.HasY())
req_rect = req_rect + region.GetOffset(req_rect.z, req_rect.w);
// Arc the Lad finds the wrong surface here when looking for a depth stencil. // Arc the Lad finds the wrong surface here when looking for a depth stencil.
// Since we're currently not caching depth stencils (check ToDo in CreateSource) we should not look for it here. // Since we're currently not caching depth stencils (check ToDo in CreateSource) we should not look for it here.
@ -1046,10 +1053,10 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
if (((bp & (BLOCKS_PER_PAGE - 1)) != (t->m_TEX0.TBP0 & (BLOCKS_PER_PAGE - 1))) && (bp & (BLOCKS_PER_PAGE - 1))) if (((bp & (BLOCKS_PER_PAGE - 1)) != (t->m_TEX0.TBP0 & (BLOCKS_PER_PAGE - 1))) && (bp & (BLOCKS_PER_PAGE - 1)))
continue; continue;
const bool overlaps = t->Overlaps(bp, bw, psm, r); const bool overlaps = t->Overlaps(bp, bw, psm, req_rect);
// Try to make sure the target has available what we need, be careful of self referencing frames with font in the alpha. // Try to make sure the target has available what we need, be careful of self referencing frames with font in the alpha.
if (overlaps && !t->HasValidBitsForFormat(psm, req_color, req_alpha) && !(possible_shuffle && GSLocalMemory::m_psm[psm].bpp == 16 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32)) if (!overlaps || (overlaps && !t->HasValidBitsForFormat(psm, req_color, req_alpha) && !(possible_shuffle && GSLocalMemory::m_psm[psm].bpp == 16 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32)))
continue; continue;
const bool width_match = (std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) == const bool width_match = (std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) ==
@ -1067,7 +1074,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
for (iter = GSRendererHW::GetInstance()->m_draw_transfers.rbegin(); iter != GSRendererHW::GetInstance()->m_draw_transfers.rend(); ) for (iter = GSRendererHW::GetInstance()->m_draw_transfers.rbegin(); iter != GSRendererHW::GetInstance()->m_draw_transfers.rend(); )
{ {
if (TEX0.TBP0 == iter->blit.DBP && GSUtil::HasCompatibleBits(iter->blit.DPSM, TEX0.PSM) && r.rintersect(iter->rect).eq(r)) if (TEX0.TBP0 == iter->blit.DBP && GSUtil::HasCompatibleBits(iter->blit.DPSM, TEX0.PSM) && req_rect.rintersect(iter->rect).eq(req_rect))
{ {
can_use = false; can_use = false;
break; break;
@ -1104,7 +1111,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
const bool real_fmt_match = (GSLocalMemory::m_psm[psm].trbpp == 16) == (t->m_32_bits_fmt == false); const bool real_fmt_match = (GSLocalMemory::m_psm[psm].trbpp == 16) == (t->m_32_bits_fmt == false);
if (rect_clean && tex_overlaps && !t->m_dirty.empty() && width_match) if (rect_clean && tex_overlaps && !t->m_dirty.empty() && width_match)
{ {
GSVector4i new_rect = r; GSVector4i new_rect = req_rect;
if (linear) if (linear)
{ {
@ -1208,14 +1215,14 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
rect_clean = t->m_dirty.empty(); rect_clean = t->m_dirty.empty();
if (!possible_shuffle && rect_clean && bp == t->m_TEX0.TBP0 && t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM) && width_match && real_fmt_match) if (!possible_shuffle && rect_clean && bp == t->m_TEX0.TBP0 && t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM) && width_match && real_fmt_match)
{ {
if (t->Overlaps(bp, bw, psm, r)) if (!tex_merge_rt && t->Overlaps(bp, bw, psm, req_rect))
ResizeTarget(t, r, bp, psm, bw); ResizeTarget(t, req_rect, bp, psm, bw);
} }
} }
if (t->m_TEX0.TBP0 != frame_fbp && !possible_shuffle && bp > t->m_TEX0.TBP0 && t->Overlaps(bp, bw, psm, r) && GSUtil::GetChannelMask(psm) == GSUtil::GetChannelMask(t->m_TEX0.PSM) && !width_match) if (t->m_TEX0.TBP0 != frame_fbp && !possible_shuffle && bp > t->m_TEX0.TBP0 && t->Overlaps(bp, bw, psm, req_rect) && GSUtil::GetChannelMask(psm) == GSUtil::GetChannelMask(t->m_TEX0.PSM) && !width_match)
{ {
GSVector4i new_rect = r; GSVector4i new_rect = req_rect;
if (linear) if (linear)
{ {
@ -1244,16 +1251,34 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
} }
} }
} }
bool overlapping_dirty = true;
if (!rect_clean)
{
const u32 read_start = GSLocalMemory::GetStartBlockAddress(bp, bw, psm, req_rect);
const u32 read_end = GSLocalMemory::GetUnwrappedEndBlockAddress(bp, bw, psm, req_rect);
const GSVector4i dirty_rect = t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size);
const u32 dirty_start = GSLocalMemory::GetStartBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, dirty_rect);
const u32 dirty_end = GSLocalMemory::GetUnwrappedEndBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, dirty_rect);
overlapping_dirty = read_start <= dirty_end && read_end >= dirty_start;
}
const bool t_clean = ((t->m_dirty.GetDirtyChannels() & GSUtil::GetChannelMask(psm)) == 0) || rect_clean; const bool t_clean = ((t->m_dirty.GetDirtyChannels() & GSUtil::GetChannelMask(psm)) == 0) || rect_clean;
const u32 color_psm = ((psm & 0x30) == 0x30) ? (psm & ~0x30) : psm; const u32 color_psm = ((psm & 0x30) == 0x30) ? (psm & ~0x30) : psm;
const u32 tex_color_psm = ((t->m_TEX0.PSM & 0x30) == 0x30) ? (t->m_TEX0.PSM & ~0x30) : t->m_TEX0.PSM; const u32 tex_color_psm = ((t->m_TEX0.PSM & 0x30) == 0x30) ? (t->m_TEX0.PSM & ~0x30) : t->m_TEX0.PSM;
const bool can_convert = (GSUtil::HasCompatibleBits(psm, t_psm) && ((bw == t->m_TEX0.TBW) || (bw <= 1 && req_rect.w < GSLocalMemory::m_psm[psm].pgs.y))) ||
(possible_shuffle && ((bw == t->m_TEX0.TBW) || (bw == (t->m_TEX0.TBW * 2) || bw <= 2)) && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32);
// Match if we haven't already got a tex in rt // Match if we haven't already got a tex in rt
if (t_clean && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t_psm)) if (((!t_clean && can_convert) || t_clean || !overlapping_dirty) && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t_psm))
{ {
bool match = true; bool match = true;
if (found_t && (bw != t->m_TEX0.TBW || t->m_TEX0.PSM != psm)) if (found_t && (bw != t->m_TEX0.TBW || t->m_TEX0.PSM != psm))
match = false; match = false;
//if (!t_clean && can_convert)
// DevCon.Warning("Expected %x Got %x shuffle %d draw %d", psm, t_psm, possible_shuffle, GSState::s_n);
if (match) if (match)
{ {
// It is a complex to convert the code in shader. As a reference, let's do it on the CPU, it will be slow but // It is a complex to convert the code in shader. As a reference, let's do it on the CPU, it will be slow but
@ -1282,19 +1307,30 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
} }
else else
{ {
if (!t_clean)
t->Update();
dst = t; dst = t;
found_t = true; found_t = true;
tex_merge_rt = false;
x_offset = 0; x_offset = 0;
y_offset = 0; y_offset = 0;
break;
if (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::MergeTargets && GSLocalMemory::GetUnwrappedEndBlockAddress(bp, bw, psm, req_rect) > dst->m_end_block)
continue;
else
{
tex_merge_rt = false;
break;
}
} }
} }
} }
} }
else if (t_clean && (t->m_TEX0.TBW >= 16) && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0 + t->m_TEX0.TBW * 0x10, t->m_TEX0.PSM)) else if ((t->m_TEX0.TBW >= 16) && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0 + t->m_TEX0.TBW * 0x10, t->m_TEX0.PSM))
{ {
if (!t_clean)
t->Update();
// Detect half of the render target (fix snow engine game) // Detect half of the render target (fix snow engine game)
// Target Page (8KB) have always a width of 64 pixels // Target Page (8KB) have always a width of 64 pixels
// Half of the Target is TBW/2 pages * 8KB / (1 block * 256B) = 0x10 // Half of the Target is TBW/2 pages * 8KB / (1 block * 256B) = 0x10
@ -1311,12 +1347,12 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
else if (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets && color_psm >= PSMCT32 && else if (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets && color_psm >= PSMCT32 &&
color_psm <= PSMCT16S && (GSUtil::HasCompatibleBits(tex_color_psm, color_psm) || color_psm <= PSMCT16S && (GSUtil::HasCompatibleBits(tex_color_psm, color_psm) ||
(possible_shuffle && tex_color_psm <= PSMCT24 && ((((t->UnwrappedEndBlock() + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == bp)) && (possible_shuffle && tex_color_psm <= PSMCT24 && ((((t->UnwrappedEndBlock() + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == bp)) &&
(t->Overlaps(bp, bw, psm, r) || t->Wraps()) && (t->Overlaps(bp, bw, psm, req_rect) || t->Wraps()) &&
t->m_age <= 1 && (!found_t || dst->m_TEX0.TBW < bw)) t->m_age <= 1 && (!found_t || dst->m_TEX0.TBW < bw))
{ {
// PSM equality needed because CreateSource does not handle PSM conversion. // PSM equality needed because CreateSource does not handle PSM conversion.
// Only inclusive hit to limit false hits. // Only inclusive hit to limit false hits.
GSVector4i rect = r; GSVector4i rect = req_rect;
int src_bw = bw; int src_bw = bw;
int src_psm = psm; int src_psm = psm;
@ -1500,7 +1536,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
if (!found_t && !dst && !GSConfig.UserHacks_DisableDepthSupport) if (!found_t && !dst && !GSConfig.UserHacks_DisableDepthSupport)
{ {
GSVector4i new_rect = r; GSVector4i new_rect = req_rect;
// Just in case the TextureMinMax trolls us as it does, when checking if inside the target. // Just in case the TextureMinMax trolls us as it does, when checking if inside the target.
new_rect.z -= 2; new_rect.z -= 2;
@ -1510,28 +1546,39 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
// Unfortunately, I don't have any Arc the Lad testcase // Unfortunately, I don't have any Arc the Lad testcase
// //
// 1/ Check only current frame, I guess it is only used as a postprocessing effect // 1/ Check only current frame, I guess it is only used as a postprocessing effect
for (auto t : m_dst[DepthStencil]) if (is_color)
{ {
if (t->m_age <= 1 && t->m_used && t->m_dirty.empty() && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM) && t->Inside(bp, bw, psm, new_rect)) for (auto t : m_dst[DepthStencil])
{ {
GL_INS("TC: Warning depth format read as color format. Pixels will be scrambled"); if (t->m_age <= 1 && t->m_used && t->m_dirty.empty() && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM) && t->Inside(bp, bw, psm, new_rect))
// Let's fetch a depth format texture. Rational, it will avoid the texture allocation and the
// rescaling of the current function.
if (psm_s.bpp > 8)
{ {
GIFRegTEX0 depth_TEX0; GL_INS("TC: Warning depth format read as color format. Pixels will be scrambled");
depth_TEX0.U32[0] = TEX0.U32[0] | (0x30u << 20u); // Let's fetch a depth format texture. Rational, it will avoid the texture allocation and the
depth_TEX0.U32[1] = TEX0.U32[1]; // rescaling of the current function.
return LookupDepthSource(depth_TEX0, TEXA, CLAMP, r, possible_shuffle, linear, frame_fbp, req_color, req_alpha); if (psm_s.bpp > 8)
}
else
{
if (!possible_shuffle && TEX0.PSM == PSMT8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 32)
{ {
continue; GIFRegTEX0 depth_TEX0;
depth_TEX0.U32[0] = TEX0.U32[0] | (0x30u << 20u);
depth_TEX0.U32[1] = TEX0.U32[1];
src = LookupDepthSource(false, depth_TEX0, TEXA, CLAMP, req_rect, possible_shuffle, linear, frame_fbp, req_color, req_alpha);
if(src != nullptr)
return src;
} }
else else
return LookupDepthSource(TEX0, TEXA, CLAMP, r, possible_shuffle, linear, frame_fbp, req_color, req_alpha, true); {
if (!possible_shuffle && TEX0.PSM == PSMT8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 32)
{
continue;
}
else
{
src = LookupDepthSource(false, TEX0, TEXA, CLAMP, req_rect, possible_shuffle, linear, frame_fbp, req_color, req_alpha, true);
if (src != nullptr)
return src;
}
}
} }
} }
} }
@ -1999,7 +2046,10 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
else else
{ {
// The old target's going to get invalidated (at least until we handle concurrent frame+depth at the same BP), // The old target's going to get invalidated (at least until we handle concurrent frame+depth at the same BP),
// so just move the dirty rects across. // so just move the dirty rects across, unless the format is diffent, in which case we need to update it.
if (dst->m_TEX0.PSM != dst_match->m_TEX0.PSM)
dst_match->Update();
dst->m_dirty = std::move(dst_match->m_dirty); dst->m_dirty = std::move(dst_match->m_dirty);
dst_match->m_dirty = {}; dst_match->m_dirty = {};
dst->m_alpha_max = dst_match->m_alpha_max; dst->m_alpha_max = dst_match->m_alpha_max;

View File

@ -461,8 +461,8 @@ public:
GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size); GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size);
std::shared_ptr<Palette> LookupPaletteObject(const u32* clut, u16 pal, bool need_gs_texture); std::shared_ptr<Palette> LookupPaletteObject(const u32* clut, u16 pal, bool need_gs_texture);
Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle, const bool linear, const u32 frame_fbp = 0xFFFFFFFF, bool req_color = true, bool req_alpha = true); Source* LookupSource(const bool is_color, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle, const bool linear, const u32 frame_fbp = 0xFFFFFFFF, bool req_color = true, bool req_alpha = true);
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, const bool linear, const u32 frame_fbp = 0xFFFFFFFF, bool req_color = true, bool req_alpha = true, bool palette = false); Source* LookupDepthSource(const bool is_depth, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, const bool linear, const u32 frame_fbp = 0xFFFFFFFF, bool req_color = true, bool req_alpha = true, bool palette = false);
Target* FindTargetOverlap(Target* target, int type, int psm); Target* FindTargetOverlap(Target* target, int type, int psm);
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0, Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,