mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Improve handling of channel shuffles on new targets
This commit is contained in:
parent
834f12dd55
commit
4c8e42d801
|
@ -902,8 +902,18 @@ GSVector2i GSRendererHW::GetValidSize(const GSTextureCache::Source* tex)
|
||||||
pxAssert(tex);
|
pxAssert(tex);
|
||||||
|
|
||||||
// Round up the page as channel shuffles are generally done in pages at a time
|
// Round up the page as channel shuffles are generally done in pages at a time
|
||||||
width = (std::max(tex->GetUnscaledWidth(), width) + page_x) & ~page_x;
|
// Keep in mind the source might be an 8bit texture
|
||||||
height = (std::max(tex->GetUnscaledHeight(), height) + page_y) & ~page_y;
|
int src_width = tex->GetUnscaledWidth();
|
||||||
|
int src_height = tex->GetUnscaledHeight();
|
||||||
|
|
||||||
|
if (!tex->m_from_target && GSLocalMemory::m_psm[tex->m_TEX0.PSM].bpp == 8)
|
||||||
|
{
|
||||||
|
src_width >>= 1;
|
||||||
|
src_height >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
width = (std::max(src_width, width) + page_x) & ~page_x;
|
||||||
|
height = (std::max(src_height, height) + page_y) & ~page_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align to page size. Since FRAME/Z has to always start on a page boundary, in theory no two should overlap.
|
// Align to page size. Since FRAME/Z has to always start on a page boundary, in theory no two should overlap.
|
||||||
|
@ -1404,8 +1414,15 @@ bool GSRendererHW::IsUsingAsInBlend()
|
||||||
{
|
{
|
||||||
return (PRIM->ABE && m_context->ALPHA.IsUsingAs() && GetAlphaMinMax().max != 0);
|
return (PRIM->ABE && m_context->ALPHA.IsUsingAs() && GetAlphaMinMax().max != 0);
|
||||||
}
|
}
|
||||||
|
bool GSRendererHW::ChannelsSharedTEX0FRAME()
|
||||||
|
{
|
||||||
|
if (!IsRTWritten() && !m_cached_ctx.TEST.DATE)
|
||||||
|
return false;
|
||||||
|
|
||||||
bool GSRendererHW::IsTBPFrameOrZ(u32 tbp)
|
return GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM, m_cached_ctx.FRAME.FBMSK) & GSUtil::GetChannelMask(m_cached_ctx.TEX0.PSM);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GSRendererHW::IsTBPFrameOrZ(u32 tbp, bool frame_only)
|
||||||
{
|
{
|
||||||
const bool is_frame = (m_cached_ctx.FRAME.Block() == tbp) && (GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & GSUtil::GetChannelMask(m_cached_ctx.TEX0.PSM));
|
const bool is_frame = (m_cached_ctx.FRAME.Block() == tbp) && (GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & GSUtil::GetChannelMask(m_cached_ctx.TEX0.PSM));
|
||||||
const bool is_z = (m_cached_ctx.ZBUF.Block() == tbp) && (GSUtil::GetChannelMask(m_cached_ctx.ZBUF.PSM) & GSUtil::GetChannelMask(m_cached_ctx.TEX0.PSM));
|
const bool is_z = (m_cached_ctx.ZBUF.Block() == tbp) && (GSUtil::GetChannelMask(m_cached_ctx.ZBUF.PSM) & GSUtil::GetChannelMask(m_cached_ctx.TEX0.PSM));
|
||||||
|
@ -1429,7 +1446,7 @@ bool GSRendererHW::IsTBPFrameOrZ(u32 tbp)
|
||||||
(no_rt && zm != 0);
|
(no_rt && zm != 0);
|
||||||
|
|
||||||
// Relying a lot on the optimizer here... I don't like it.
|
// Relying a lot on the optimizer here... I don't like it.
|
||||||
return (is_frame && !no_rt) || (is_z && !no_ds);
|
return (is_frame && !no_rt) || (is_z && !no_ds && !frame_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSRendererHW::HandleManualDeswizzle()
|
void GSRendererHW::HandleManualDeswizzle()
|
||||||
|
@ -2623,7 +2640,7 @@ void GSRendererHW::Draw()
|
||||||
// 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.
|
||||||
FRAME_TEX0.U64 = 0;
|
FRAME_TEX0.U64 = 0;
|
||||||
FRAME_TEX0.TBP0 = m_cached_ctx.FRAME.Block();
|
FRAME_TEX0.TBP0 = m_cached_ctx.FRAME.Block();
|
||||||
FRAME_TEX0.TBW = m_channel_shuffle ? src->m_from_target_TEX0.TBW : m_cached_ctx.FRAME.FBW;
|
FRAME_TEX0.TBW = (m_channel_shuffle && src->m_target) ? src->m_from_target_TEX0.TBW : m_cached_ctx.FRAME.FBW;
|
||||||
FRAME_TEX0.PSM = m_cached_ctx.FRAME.PSM;
|
FRAME_TEX0.PSM = m_cached_ctx.FRAME.PSM;
|
||||||
|
|
||||||
// Normally we would use 1024 here to match the clear above, but The Godfather does a 1023x1023 draw instead
|
// Normally we would use 1024 here to match the clear above, but The Godfather does a 1023x1023 draw instead
|
||||||
|
@ -2674,7 +2691,9 @@ void GSRendererHW::Draw()
|
||||||
if (m_channel_shuffle)
|
if (m_channel_shuffle)
|
||||||
{
|
{
|
||||||
m_last_channel_shuffle_fbp = rt->m_TEX0.TBP0;
|
m_last_channel_shuffle_fbp = rt->m_TEX0.TBP0;
|
||||||
m_last_channel_shuffle_end_block = rt->m_end_block;
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2745,8 +2764,20 @@ void GSRendererHW::Draw()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->m_target && IsPossibleChannelShuffle())
|
if ((src->m_target || (m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0)) && IsPossibleChannelShuffle())
|
||||||
{
|
{
|
||||||
|
if (!src->m_target)
|
||||||
|
{
|
||||||
|
g_texture_cache->ReplaceSourceTexture(src, rt->GetTexture(), rt->GetScale(), rt->GetUnscaledSize(), nullptr, true);
|
||||||
|
src->m_from_target = rt;
|
||||||
|
src->m_from_target_TEX0 = rt->m_TEX0;
|
||||||
|
src->m_target = true;
|
||||||
|
src->m_target_direct = true;
|
||||||
|
src->m_valid_rect = rt->m_valid;
|
||||||
|
src->m_alpha_minmax.first = rt->m_alpha_min;
|
||||||
|
src->m_alpha_minmax.second = rt->m_alpha_max;
|
||||||
|
}
|
||||||
|
|
||||||
GL_INS("Channel shuffle effect detected (2nd shot)");
|
GL_INS("Channel shuffle effect detected (2nd shot)");
|
||||||
m_channel_shuffle = true;
|
m_channel_shuffle = true;
|
||||||
m_last_channel_shuffle_fbmsk = m_context->FRAME.FBMSK;
|
m_last_channel_shuffle_fbmsk = m_context->FRAME.FBMSK;
|
||||||
|
@ -2754,10 +2785,13 @@ void GSRendererHW::Draw()
|
||||||
{
|
{
|
||||||
m_last_channel_shuffle_fbp = rt->m_TEX0.TBP0;
|
m_last_channel_shuffle_fbp = rt->m_TEX0.TBP0;
|
||||||
// Urban Chaos goes from Z16 to C32, so let's just use the rt's original end block.
|
// Urban Chaos goes from Z16 to C32, so let's just use the rt's original end block.
|
||||||
if (GSLocalMemory::m_psm[src->m_from_target_TEX0.PSM].bpp != GSLocalMemory::m_psm[rt->m_TEX0.PSM].bpp)
|
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;
|
m_last_channel_shuffle_end_block = rt->m_end_block;
|
||||||
else
|
else
|
||||||
m_last_channel_shuffle_end_block = (rt->m_TEX0.TBP0 + (src->m_from_target->m_end_block - src->m_from_target_TEX0.TBP0));
|
m_last_channel_shuffle_end_block = (rt->m_TEX0.TBP0 + (src->m_from_target->m_end_block - src->m_from_target_TEX0.TBP0));
|
||||||
|
|
||||||
|
if (m_last_channel_shuffle_end_block < rt->m_TEX0.TBP0)
|
||||||
|
m_last_channel_shuffle_end_block += MAX_BLOCKS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2930,7 +2964,8 @@ void GSRendererHW::Draw()
|
||||||
// The FBW should also be okay, since it's coming from the source.
|
// The FBW should also be okay, since it's coming from the source.
|
||||||
if (rt)
|
if (rt)
|
||||||
{
|
{
|
||||||
rt->m_TEX0.TBW = (m_channel_shuffle && (!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack())) ? FRAME_TEX0.TBW : std::max(rt->m_TEX0.TBW, FRAME_TEX0.TBW);
|
const bool update_fbw = (m_channel_shuffle && src->m_target) && (!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack());
|
||||||
|
rt->m_TEX0.TBW = update_fbw ? FRAME_TEX0.TBW : std::max(rt->m_TEX0.TBW, FRAME_TEX0.TBW);
|
||||||
rt->m_TEX0.PSM = FRAME_TEX0.PSM;
|
rt->m_TEX0.PSM = FRAME_TEX0.PSM;
|
||||||
}
|
}
|
||||||
if (ds)
|
if (ds)
|
||||||
|
|
|
@ -226,10 +226,13 @@ public:
|
||||||
/// Called by the texture cache to know for certain whether there is a channel shuffle.
|
/// Called by the texture cache to know for certain whether there is a channel shuffle.
|
||||||
bool TestChannelShuffle(GSTextureCache::Target* src);
|
bool TestChannelShuffle(GSTextureCache::Target* src);
|
||||||
|
|
||||||
/// Returns true if the specified texture address matches the frame or Z buffer.
|
/// Returns true if the Frame and TEX0 are sharing channels
|
||||||
bool IsTBPFrameOrZ(u32 tbp);
|
bool ChannelsSharedTEX0FRAME();
|
||||||
|
|
||||||
//// Returns true if the draws appear to be a manual deswizzle.
|
/// Returns true if the specified texture address matches the frame or Z buffer.
|
||||||
|
bool IsTBPFrameOrZ(u32 tbp, bool frame_only = false);
|
||||||
|
|
||||||
|
/// Returns true if the draws appear to be a manual deswizzle.
|
||||||
void HandleManualDeswizzle();
|
void HandleManualDeswizzle();
|
||||||
|
|
||||||
/// Offsets the current draw, used for RT-in-RT. Offsets are relative to the *current* FBP, not the new FBP.
|
/// Offsets the current draw, used for RT-in-RT. Offsets are relative to the *current* FBP, not the new FBP.
|
||||||
|
|
|
@ -4815,6 +4815,13 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||||
g_texture_cache->InvalidateVideoMemType(GSTextureCache::DepthStencil, TEX0.TBP0, TEX0.PSM, GSRendererHW::GetInstance()->GetCachedCtx()->FRAME.FBMSK, true);
|
g_texture_cache->InvalidateVideoMemType(GSTextureCache::DepthStencil, TEX0.TBP0, TEX0.PSM, GSRendererHW::GetInstance()->GetCachedCtx()->FRAME.FBMSK, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// kill source immediately after the draw if it's the RT, because that'll get invalidated immediately.
|
||||||
|
if (GSRendererHW::GetInstance()->IsTBPFrameOrZ(TEX0.TBP0, true) && GSRendererHW::GetInstance()->ChannelsSharedTEX0FRAME())
|
||||||
|
{
|
||||||
|
GL_CACHE("TC: Source == RT before RT creation, invalidating after draw.");
|
||||||
|
m_temporary_source = src;
|
||||||
|
}
|
||||||
|
|
||||||
// maintain the clut even when paltex is on for the dump/replacement texture lookup
|
// maintain the clut even when paltex is on for the dump/replacement texture lookup
|
||||||
bool paltex = (GSConfig.GPUPaletteConversion && psm.pal > 0) || gpu_clut;
|
bool paltex = (GSConfig.GPUPaletteConversion && psm.pal > 0) || gpu_clut;
|
||||||
const u32* clut = (psm.pal > 0) ? static_cast<const u32*>(g_gs_renderer->m_mem.m_clut) : nullptr;
|
const u32* clut = (psm.pal > 0) ? static_cast<const u32*>(g_gs_renderer->m_mem.m_clut) : nullptr;
|
||||||
|
|
Loading…
Reference in New Issue