GS/HW: More changes some regressions

This commit is contained in:
refractionpcsx2 2025-01-12 06:33:38 +00:00
parent 7b9c5b7543
commit da3e5c0aad
2 changed files with 170 additions and 109 deletions

View File

@ -2607,7 +2607,7 @@ void GSRendererHW::Draw()
shuffle_target = shuffle_coords && (draw_width & 7) == 0 && std::abs(draw_width - read_width) <= 1;
}
if (m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0 || !shuffle_target)
if (!shuffle_target)
{
// FBW is going to be wrong for channel shuffling into a new target, so take it from the source.
FRAME_TEX0.U64 = 0;
@ -2693,7 +2693,7 @@ void GSRendererHW::Draw()
// Urban Reign trolls by scissoring a draw to a target at 0x0-0x117F to 378x449 which ends up the size being rounded up to 640x480
// causing the buffer to expand to around 0x1400, which makes a later framebuffer at 0x1180 to fail to be created correctly.
// We can cheese this by checking if the Z is masked and the resultant colour is going to be black anyway.
const bool output_black = PRIM->ABE && ((m_context->ALPHA.A == 1 && m_context->ALPHA.B == 0 && GetAlphaMinMax().min >= 128) || m_context->ALPHA.IsBlack()) && m_draw_env->COLCLAMP.CLAMP == 1;
const bool output_black = PRIM->ABE && ((m_context->ALPHA.A == 1 || m_context->ALPHA.IsBlack()) && m_context->ALPHA.D != 1) && m_draw_env->COLCLAMP.CLAMP == 1;
const bool can_expand = !(m_cached_ctx.ZBUF.ZMSK && output_black);
// Estimate size based on the scissor rectangle and height cache.
@ -2930,7 +2930,7 @@ void GSRendererHW::Draw()
{
int vertical_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.y; // I know I could just not shift it..
int texture_offset = 0;
const int horizontal_offset = ((static_cast<int>((m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0)) / 32) % static_cast<int>(std::max(rt->m_TEX0.TBW, 1U))) * frame_psm.pgs.x;
int horizontal_offset = ((static_cast<int>((m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0)) / 32) % static_cast<int>(std::max(rt->m_TEX0.TBW, 1U))) * frame_psm.pgs.x;
// Used to reduce the offset made later in channel shuffles
m_target_offset = std::abs(static_cast<int>((m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0)) >> 5);
@ -2969,6 +2969,13 @@ void GSRendererHW::Draw()
vertical_offset = 0;
}
if (horizontal_offset < 0)
{
// Thankfully this doesn't really happen, but catwoman moves the framebuffer backwards 1 page with a channel shuffle, which is really messy and not easy to deal with.
// Hopefully the quick channel shuffle will just guess this and run with it.
rt->m_TEX0.TBP0 += horizontal_offset;
horizontal_offset = 0;
}
// Z isn't offset but RT is, so we need a temp Z to align it, hopefully nothing will ever write to the Z too, right??
if (ds && vertical_offset && (m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) != (m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0))
{
@ -3018,7 +3025,7 @@ void GSRendererHW::Draw()
m_r.w += vertical_offset;
m_r.x += horizontal_offset;
m_r.z += horizontal_offset;
m_in_target_draw = true;
m_in_target_draw = rt->m_TEX0.TBP0 != m_cached_ctx.FRAME.Block();
m_vt.m_min.p.x += horizontal_offset;
m_vt.m_max.p.x += horizontal_offset;
m_vt.m_min.p.y += vertical_offset;

View File

@ -1863,6 +1863,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
Target* dst = nullptr;
auto& list = m_dst[type];
const GSVector4i min_rect = draw_rect.max_u32(GSVector4i(0, 0, draw_rect.x, draw_rect.y));
// TODO: Move all frame stuff to its own routine too.
if (!is_frame)
@ -1951,12 +1952,18 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
}*/
const u32 widthpage_offset = (std::abs(static_cast<int>(bp - t->m_TEX0.TBP0)) >> 5) % std::max(t->m_TEX0.TBW, 1U);
const bool is_aligned_ok = widthpage_offset == 0 || (t->m_TEX0.TBW == TEX0.TBW &&
/*const bool is_aligned_ok = widthpage_offset == 0 || (t->m_TEX0.TBW == TEX0.TBW &&
((((min_rect.z + 63) >> 6) + widthpage_offset) <= TEX0.TBW) ||
((widthpage_offset + TEX0.TBW) <= t->m_TEX0.TBW) ||
min_rect.width() <= 64 || (widthpage_offset == (t->m_TEX0.TBW >> 1) &&
(static_cast<u32>(min_rect.width()) <= (widthpage_offset * 64))));
if ((!dst || ((GSState::s_n - dst->m_last_draw) < (GSState::s_n - t->m_last_draw))) && is_aligned_ok && (t->m_TEX0.TBW == TEX0.TBW || TEX0.TBW == 1) && t->Overlaps(bp, TEX0.TBW, TEX0.PSM, min_rect))
(static_cast<u32>(min_rect.width()) <= (widthpage_offset * 64))));*/
const bool is_aligned_ok = widthpage_offset == 0 || ((min_rect.width() <= static_cast<int>((t->m_TEX0.TBW - widthpage_offset) * 64) && (t->m_TEX0.TBW == TEX0.TBW || TEX0.TBW == 1)) && bp >= t->m_TEX0.TBP0);
const bool no_target_or_newer = (!dst || ((GSState::s_n - dst->m_last_draw) < (GSState::s_n - t->m_last_draw)));
const bool width_match = (t->m_TEX0.TBW == TEX0.TBW || TEX0.TBW == 1);
// if it's a shuffle, some games tend to offset back by a page, such as Tomb Raider, for no disernable reason, but it then causes problems.
// This can also happen horizontally (Catwoman moves everything one page left with shuffles), but this is too messy to deal with right now.
const bool overlaps = t->Overlaps(bp, TEX0.TBW, TEX0.PSM, min_rect) || (is_shuffle && t->Overlaps(bp, TEX0.TBW, TEX0.PSM, min_rect + GSVector4i(0, 0, 0, 32)));
if (no_target_or_newer && is_aligned_ok && width_match && overlaps)
{
const GSLocalMemory::psm_t& s_psm = GSLocalMemory::m_psm[TEX0.PSM];
@ -2204,12 +2211,12 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
}
// New format or doing a shuffle to a 32bit target that used to be 16bit
if (!is_shuffle)
if (!is_shuffle || GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp < GSLocalMemory::m_psm[TEX0.PSM].bpp)
dst->m_TEX0.PSM = TEX0.PSM;
// LEGO Dome Racers does a copy to a target as 8bit in alpha only, this doesn't really work great for us, so let's make it 32bit with invalid RGB.
else if (dst->m_TEX0.PSM == PSMT8H)
{
//dst->m_TEX0.PSM = PSMCT32;
dst->m_TEX0.PSM = PSMCT32;
dst->m_valid_rgb = false;
}
}
@ -2515,8 +2522,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
pxAssert(dst && dst->m_texture && dst->m_scale == scale);
}
if (dst && dst->m_TEX0.TBP0 == 0x3f80 && dst->m_TEX0.PSM == 0)
DevCon.Warning("It's 32bit on draw %d", GSState::s_n);
return dst;
}
@ -2536,7 +2542,8 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe
// Avoid making garbage targets (usually PCRTC).
if (GSVector4i::loadh(size).rempty())
return nullptr;
if (TEX0.TBP0 == 0x3320 || TEX0.TBP0 == 0x32a0)
DevCon.Warning("Making target %x on draw %d", TEX0.TBP0, GSState::s_n);
Target* dst = Target::Create(TEX0, size.x, size.y, scale, type, true);
if (!dst) [[unlikely]]
return nullptr;
@ -2787,8 +2794,8 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
auto j = i;
Target* t = *j;
if (dst != t && t->m_TEX0.PSM == dst->m_TEX0.PSM/* && t->m_TEX0.TBW == dst->m_TEX0.TBW*/)
if (t->Overlaps(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst->m_valid))
if (dst != t && t->m_TEX0.PSM == dst->m_TEX0.PSM && t->Overlaps(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst->m_valid) &&
static_cast<int>(((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) / 32) % std::max(dst->m_TEX0.TBW, 1U)) <= std::max(0, static_cast<int>(dst->m_TEX0.TBW - t->m_TEX0.TBW)))
{
const u32 buffer_width = std::max(1U, dst->m_TEX0.TBW);
@ -3244,7 +3251,7 @@ bool GSTextureCache::PrepareDownloadTexture(u32 width, u32 height, GSTexture::Fo
return true;
}
void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm, u32 write_bw)
/*void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm, u32 write_bw)
{
const bool preserve_alpha = (GSLocalMemory::m_psm[write_psm].trbpp == 24);
for (int type = 0; type < 2; type++)
@ -3261,16 +3268,63 @@ void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 wr
//const u32 total_pages = ((end_bp + 1) - t->m_TEX0.TBP0) >> 5;
// Not covering the whole target, and a different format, so just dirty it.
/*if (start_bp >= t->m_TEX0.TBP0 && (t->UnwrappedEndBlock() > end_bp) && write_psm != t->m_TEX0.PSM && write_bw == t->m_TEX0.TBW)
//if (start_bp >= t->m_TEX0.TBP0 && (t->UnwrappedEndBlock() > end_bp) && write_psm != t->m_TEX0.PSM && write_bw == t->m_TEX0.TBW)
//{
// const GSLocalMemory::psm_t& target_psm = GSLocalMemory::m_psm[write_psm];
// const u32 page_offset = ((start_bp - t->m_TEX0.TBP0) >> 5);
// const u32 vertical_offset = (page_offset / t->m_TEX0.TBW) * target_psm.pgs.y;
// GSVector4i dirty_area = GSVector4i(page_offset % t->m_TEX0.TBW, vertical_offset, t->m_valid.z, vertical_offset + ((total_pages / t->m_TEX0.TBW) * target_psm.pgs.y));
// InvalidateVideoMem(g_gs_renderer->m_mem.GetOffset(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM), dirty_area, true);
// ++i;
// continue;
//}
InvalidateSourcesFromTarget(t);
t->m_valid_alpha_low &= preserve_alpha;
t->m_valid_alpha_high &= preserve_alpha;
t->m_valid_rgb &= !(t->m_TEX0.TBP0 == start_bp);
// Don't keep partial depth buffers around.
if ((!t->m_valid_alpha_low && !t->m_valid_alpha_high && !t->m_valid_rgb) || type == DepthStencil)
{
auto& rev_list = m_dst[1 - type];
for (auto j = rev_list.begin(); j != rev_list.end();)
{
Target* const rev_t = *j;
if (rev_t->m_TEX0.TBP0 == t->m_TEX0.TBP0 && GSLocalMemory::m_psm[rev_t->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp)
{
rev_t->m_was_dst_matched = false;
break;
}
++j;
}
GL_CACHE("TC: InvalidateContainedTargets: Remove Target %s[%x, %s]", to_string(type), t->m_TEX0.TBP0, psm_str(t->m_TEX0.PSM));
i = list.erase(i);
delete t;
continue;
}
GL_CACHE("TC: InvalidateContainedTargets: Clear RGB valid on %s[%x, %s]", to_string(type), t->m_TEX0.TBP0, psm_str(t->m_TEX0.PSM));
++i;
}
}
}*/
void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm, u32 write_bw)
{
const bool preserve_alpha = (GSLocalMemory::m_psm[write_psm].trbpp == 24);
for (int type = 0; type < 2; type++)
{
auto& list = m_dst[type];
for (auto i = list.begin(); i != list.end();)
{
Target* const t = *i;
if (start_bp != t->m_TEX0.TBP0 && (t->m_TEX0.TBP0 < start_bp || t->UnwrappedEndBlock() > end_bp))
{
const GSLocalMemory::psm_t& target_psm = GSLocalMemory::m_psm[write_psm];
const u32 page_offset = ((start_bp - t->m_TEX0.TBP0) >> 5);
const u32 vertical_offset = (page_offset / t->m_TEX0.TBW) * target_psm.pgs.y;
GSVector4i dirty_area = GSVector4i(page_offset % t->m_TEX0.TBW, vertical_offset, t->m_valid.z, vertical_offset + ((total_pages / t->m_TEX0.TBW) * target_psm.pgs.y));
InvalidateVideoMem(g_gs_renderer->m_mem.GetOffset(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM), dirty_area, true);
++i;
continue;
}*/
}
InvalidateSourcesFromTarget(t);