mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Fix some back to back shuffles and inside source invalidation
This commit is contained in:
parent
e9341bde7c
commit
8de5f53252
|
@ -936,8 +936,8 @@ GSVector2i GSRendererHW::GetValidSize(const GSTextureCache::Source* tex)
|
|||
|
||||
// Round up the page as channel shuffles are generally done in pages at a time
|
||||
// Keep in mind the source might be an 8bit texture
|
||||
int src_width = tex->GetUnscaledWidth();
|
||||
int src_height = tex->GetUnscaledHeight();
|
||||
int src_width = tex->m_from_target ? tex->m_from_target->m_valid.width() : tex->GetUnscaledWidth();
|
||||
int src_height = tex->m_from_target ? tex->m_from_target->m_valid.height() : tex->GetUnscaledHeight();
|
||||
|
||||
if (!tex->m_from_target && GSLocalMemory::m_psm[tex->m_TEX0.PSM].bpp == 8)
|
||||
{
|
||||
|
@ -2053,9 +2053,7 @@ void GSRendererHW::Draw()
|
|||
DumpVertices(s);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OGL_DEBUG
|
||||
static u32 num_skipped_channel_shuffle_draws = 0;
|
||||
#endif
|
||||
|
||||
// We mess with this state as an optimization, so take a copy and use that instead.
|
||||
const GSDrawingContext* context = m_context;
|
||||
|
@ -2079,24 +2077,26 @@ void GSRendererHW::Draw()
|
|||
// Tomb Raider: Underworld does similar, except with R, G, B in separate palettes, therefore
|
||||
// we need to split on those too.
|
||||
m_channel_shuffle = IsPossibleChannelShuffle() && m_last_channel_shuffle_fbmsk == m_context->FRAME.FBMSK &&
|
||||
m_last_channel_shuffle_fbp <= m_context->FRAME.Block() && m_last_channel_shuffle_end_block > m_context->FRAME.Block();
|
||||
m_last_channel_shuffle_fbp <= m_context->FRAME.Block() && m_last_channel_shuffle_end_block > m_context->FRAME.Block() &&
|
||||
m_last_channel_shuffle_tbp <= m_context->TEX0.TBP0;
|
||||
|
||||
#ifdef ENABLE_OGL_DEBUG
|
||||
if (m_channel_shuffle)
|
||||
{
|
||||
m_last_channel_shuffle_fbp = m_context->FRAME.Block();
|
||||
m_last_channel_shuffle_tbp = m_context->TEX0.TBP0;
|
||||
|
||||
num_skipped_channel_shuffle_draws++;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OGL_DEBUG
|
||||
if (num_skipped_channel_shuffle_draws > 0)
|
||||
GL_INS("Skipped %u channel shuffle draws", num_skipped_channel_shuffle_draws);
|
||||
GL_CACHE("Skipped %d channel shuffle draws ending at %d", num_skipped_channel_shuffle_draws, s_n);
|
||||
#endif
|
||||
num_skipped_channel_shuffle_draws = 0;
|
||||
m_last_channel_shuffle_fbp = 0xffff;
|
||||
m_last_channel_shuffle_tbp = 0xffff;
|
||||
m_last_channel_shuffle_end_block = 0xffff;
|
||||
#else
|
||||
if (m_channel_shuffle)
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
GL_PUSH("HW Draw %d (Context %u)", s_n, PRIM->CTXT);
|
||||
|
@ -3070,6 +3070,7 @@ void GSRendererHW::Draw()
|
|||
if (m_channel_shuffle)
|
||||
{
|
||||
m_last_channel_shuffle_fbp = rt->m_TEX0.TBP0;
|
||||
m_last_channel_shuffle_tbp = src->m_TEX0.TBP0;
|
||||
|
||||
// If it's a new target, we don't know where the end is as it's starting on a shuffle, so just do every shuffle following.
|
||||
m_last_channel_shuffle_end_block = (rt->m_last_draw >= s_n) ? (MAX_BLOCKS - 1) : (rt->m_end_block < rt->m_TEX0.TBP0 ? (rt->m_end_block + MAX_BLOCKS) : rt->m_end_block);
|
||||
|
@ -3211,6 +3212,7 @@ void GSRendererHW::Draw()
|
|||
if (rt)
|
||||
{
|
||||
m_last_channel_shuffle_fbp = rt->m_TEX0.TBP0;
|
||||
m_last_channel_shuffle_tbp = src->m_TEX0.TBP0;
|
||||
// Urban Chaos goes from Z16 to C32, so let's just use the rt's original end block.
|
||||
if (!src->m_from_target || GSLocalMemory::m_psm[src->m_from_target_TEX0.PSM].bpp != GSLocalMemory::m_psm[rt->m_TEX0.PSM].bpp)
|
||||
m_last_channel_shuffle_end_block = rt->m_end_block;
|
||||
|
@ -5620,8 +5622,9 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
|||
bool& target_region, GSVector2i& unscaled_size, float& scale, GSDevice::RecycledTexture& src_copy)
|
||||
{
|
||||
|
||||
const int tex_diff = tex->m_from_target ? static_cast<int>(m_cached_ctx.TEX0.TBP0 - tex->m_from_target->m_TEX0.TBP0) : 0;
|
||||
const int tex_diff = tex->m_from_target ? static_cast<int>(m_cached_ctx.TEX0.TBP0 - tex->m_from_target->m_TEX0.TBP0) : static_cast<int>(m_cached_ctx.TEX0.TBP0 - tex->m_TEX0.TBP0);
|
||||
const int frame_diff = rt ? static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) : 0;
|
||||
|
||||
// Detect framebuffer read that will need special handling
|
||||
const GSTextureCache::Target* src_target = nullptr;
|
||||
if (m_conf.tex == m_conf.rt && !(m_channel_shuffle && tex && (tex_diff != frame_diff || target_region)))
|
||||
|
|
|
@ -174,6 +174,7 @@ private:
|
|||
|
||||
u32 m_last_channel_shuffle_fbmsk = 0;
|
||||
u32 m_last_channel_shuffle_fbp = 0;
|
||||
u32 m_last_channel_shuffle_tbp = 0;
|
||||
u32 m_last_channel_shuffle_end_block = 0;
|
||||
|
||||
GIFRegFRAME m_split_clear_start = {};
|
||||
|
|
|
@ -2542,8 +2542,7 @@ 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;
|
||||
|
@ -3428,6 +3427,12 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r
|
|||
const u32 bw = off.bw();
|
||||
const u32 psm = off.psm();
|
||||
|
||||
// Get the bounds that we're invalidating in blocks, so we can remove any targets which are completely contained.
|
||||
// Unfortunately sometimes the draw rect is incorrect, and since the end block gets the rect -1, it'll underflow,
|
||||
// so we need to prevent that from happening. Just make it a single block in that case, and hope for the best.
|
||||
const u32 start_bp = GSLocalMemory::GetStartBlockAddress(off.bp(), off.bw(), off.psm(), rect);
|
||||
const u32 end_bp = rect.rempty() ? start_bp : GSLocalMemory::GetUnwrappedEndBlockAddress(off.bp(), off.bw(), off.psm(), rect);
|
||||
|
||||
if (!target)
|
||||
{
|
||||
// Remove Source that have same BP as the render target (color&dss)
|
||||
|
@ -3438,7 +3443,7 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r
|
|||
Source* s = *i;
|
||||
++i;
|
||||
|
||||
if (GSUtil::HasSharedBits(bp, psm, s->m_TEX0.TBP0, s->m_TEX0.PSM) ||
|
||||
if ((GSUtil::HasSharedBits(psm, s->m_TEX0.PSM) && (bp >= start_bp && bp < end_bp)) ||
|
||||
(GSUtil::HasSharedBits(bp, psm, s->m_from_target_TEX0.TBP0, s->m_TEX0.PSM) && s->m_target))
|
||||
{
|
||||
m_src.RemoveAt(s);
|
||||
|
@ -3535,11 +3540,6 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r
|
|||
if (!target)
|
||||
return;
|
||||
|
||||
// Get the bounds that we're invalidating in blocks, so we can remove any targets which are completely contained.
|
||||
// Unfortunately sometimes the draw rect is incorrect, and since the end block gets the rect -1, it'll underflow,
|
||||
// so we need to prevent that from happening. Just make it a single block in that case, and hope for the best.
|
||||
const u32 start_bp = GSLocalMemory::GetStartBlockAddress(off.bp(), off.bw(), off.psm(), rect);
|
||||
const u32 end_bp = rect.rempty() ? start_bp : GSLocalMemory::GetUnwrappedEndBlockAddress(off.bp(), off.bw(), off.psm(), rect);
|
||||
|
||||
RGBAMask rgba;
|
||||
rgba._u32 = GSUtil::GetChannelMask(psm);
|
||||
|
@ -4819,6 +4819,9 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
|||
src->m_texture = dst->m_texture;
|
||||
src->m_unscaled_size = dst->m_unscaled_size;
|
||||
src->m_shared_texture = true;
|
||||
|
||||
if(channel_shuffle)
|
||||
m_temporary_source = src;
|
||||
}
|
||||
|
||||
// Invalidate immediately on recursive draws, because if we don't here, InvalidateVideoMem() will.
|
||||
|
@ -5074,7 +5077,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
|||
}
|
||||
|
||||
// kill source immediately if it's the RT/DS, because that'll get invalidated immediately
|
||||
if (GSRendererHW::GetInstance()->IsTBPFrameOrZ(dst->m_TEX0.TBP0))
|
||||
if (GSRendererHW::GetInstance()->IsTBPFrameOrZ(dst->m_TEX0.TBP0) || channel_shuffle)
|
||||
{
|
||||
GL_CACHE("TC: Source is RT or ZBUF, invalidating after draw.");
|
||||
m_temporary_source = src;
|
||||
|
|
|
@ -518,7 +518,7 @@ public:
|
|||
/// Removes any sources which point to the specified target.
|
||||
void InvalidateSourcesFromTarget(const Target* t);
|
||||
|
||||
/// Replaces a source's texture externally. Required for some CRC hacks.
|
||||
/// Removes any sources which point to the same address as a new target.
|
||||
void ReplaceSourceTexture(Source* s, GSTexture* new_texture, float new_scale, const GSVector2i& new_unscaled_size,
|
||||
HashCacheEntry* hc_entry, bool new_texture_is_shared);
|
||||
|
||||
|
|
Loading…
Reference in New Issue