GS/HW: Better avoid target uploads on HW clear

This commit is contained in:
Stenzek 2024-01-20 15:43:05 +10:00 committed by Connor McLaughlin
parent 01849565aa
commit 3b25fa3065
1 changed files with 19 additions and 17 deletions

View File

@ -2313,7 +2313,10 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe
}
}
if (was_clear)
{
GL_INS("TC: Clear dirty list on new target %x, because it was a zero clear", TEX0.TBP0);
dst->m_dirty.clear();
}
}
dst->readbacks_since_draw = 0;
@ -2338,7 +2341,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
// but normally few RT are miss so it must remain reasonable.
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
const bool supported_fmt = !GSConfig.UserHacks_DisableDepthSupport || psm_s.depth == 0;
bool hw_clear = false;
std::optional<bool> hw_clear;
if (TEX0.TBW > 0 && supported_fmt)
{
@ -2353,11 +2356,11 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
{
if ((preserve_target || !draw_rect.eq(dst->m_valid)) && GSRendererHW::GetInstance()->m_draw_transfers.size() > 0)
{
std::vector<GSState::GSUploadQueue>::reverse_iterator iter;
auto& transfers = GSRendererHW::GetInstance()->m_draw_transfers;
const int last_draw = transfers.back().draw;
GSVector4i eerect = GSVector4i::zero();
const int last_draw = GSRendererHW::GetInstance()->m_draw_transfers.back().draw;
for (iter = GSRendererHW::GetInstance()->m_draw_transfers.rbegin(); iter != GSRendererHW::GetInstance()->m_draw_transfers.rend(); )
for (auto iter = transfers.rbegin(); iter != transfers.rend(); ++iter)
{
// Would be nice to make this 100, but B-Boy seems to rely on data uploaded ~200 draws ago. Making it bigger for now to be safe.
if (last_draw - iter->draw > 500)
@ -2420,23 +2423,22 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
else
eerect = eerect.runion(targetr);
if (iter->zero_clear && iter->draw == last_draw)
{
hw_clear |= true;
}
// Later writes might be partial over a previously cleared area. We want to upload in these cases.
hw_clear = hw_clear.has_value() ? (hw_clear.value() && iter->zero_clear) : iter->zero_clear;
if (iter->blit.DBP == TEX0.TBP0 && transfer_end == rect_end)
// When the write covers the entire target, don't bother checking any earlier writes.
if (iter->blit.DBP <= TEX0.TBP0 && transfer_end >= rect_end)
{
iter = std::vector<GSState::GSUploadQueue>::reverse_iterator(GSRendererHW::GetInstance()->m_draw_transfers.erase(iter.base() - 1));
// Some games clear RT and Z at the same time, only erase if it's specifically this target.
if (iter->blit.DBP == TEX0.TBP0 && transfer_end == rect_end)
transfers.erase(iter.base() - 1);
break;
}
else
++iter;
if (eerect.rintersect(newrect).eq(newrect))
break;
}
else
++iter;
}
if (!eerect.rempty())
@ -2486,7 +2488,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
new_valid.w /= 2;
GL_INS("RT resize buffer for FBP 0x%x, %dx%d => %d,%d", t->m_TEX0.TBP0, t->m_valid.width(), t->m_valid.height(), new_valid.width(), new_valid.height());
t->ResizeValidity(new_valid);
return hw_clear;
return hw_clear.value_or(false);
}
// The new texture is behind it but engulfs the whole thing, shrink the new target so it grows in the HW Draw resize.
else if (((((dst->UnwrappedEndBlock() + 1) - dst->m_TEX0.TBP0) >> 1) + dst->m_TEX0.TBP0) == t->m_TEX0.TBP0)
@ -2545,7 +2547,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
i = list.erase(j);
delete t;
}
return hw_clear;
return hw_clear.value_or(false);
}
}
i++;
@ -2553,7 +2555,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
}
}
return hw_clear;
return hw_clear.value_or(false);
}
GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, bool is_feedback)