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,8 +2313,11 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe
} }
} }
if (was_clear) 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->m_dirty.clear();
} }
}
dst->readbacks_since_draw = 0; 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. // but normally few RT are miss so it must remain reasonable.
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM]; const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
const bool supported_fmt = !GSConfig.UserHacks_DisableDepthSupport || psm_s.depth == 0; 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) 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) 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(); 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. // 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) if (last_draw - iter->draw > 500)
@ -2420,23 +2423,22 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
else else
eerect = eerect.runion(targetr); eerect = eerect.runion(targetr);
if (iter->zero_clear && iter->draw == last_draw) // 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;
hw_clear |= true;
}
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)) if (eerect.rintersect(newrect).eq(newrect))
break; break;
} }
else
++iter;
} }
if (!eerect.rempty()) if (!eerect.rempty())
@ -2486,7 +2488,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
new_valid.w /= 2; 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()); 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); 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. // 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) 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); i = list.erase(j);
delete t; delete t;
} }
return hw_clear; return hw_clear.value_or(false);
} }
} }
i++; 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) GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, bool is_feedback)