GS/HW: Reduce misdetections for downscaling

This commit is contained in:
refractionpcsx2 2024-06-21 22:36:14 +01:00
parent 2c9ddf3b38
commit 915ed85f5d
2 changed files with 23 additions and 13 deletions

View File

@ -2171,7 +2171,7 @@ void GSRendererHW::Draw()
}
// We want to fix up the context if we're doing a double half clear, regardless of whether we do the CPU fill.
const bool is_possible_mem_clear = IsConstantDirectWriteMemClear();
const ClearType is_possible_mem_clear = IsConstantDirectWriteMemClear();
if (!GSConfig.UserHacks_DisableSafeFeatures && is_possible_mem_clear)
{
if (!DetectStripedDoubleClear(no_rt, no_ds))
@ -2686,7 +2686,7 @@ void GSRendererHW::Draw()
IsPossibleChannelShuffle());
rt = g_texture_cache->LookupTarget(FRAME_TEX0, t_size, ((src && src->m_scale != 1) && GSConfig.UserHacks_NativeScaling == GSNativeScaling::Normal && !possible_shuffle) ? GetTextureScaleFactor() : target_scale, GSTextureCache::RenderTarget, true,
fm, false, force_preload, preserve_rt_rgb, preserve_rt_alpha, unclamped_draw_rect, possible_shuffle, is_possible_mem_clear && FRAME_TEX0.TBP0 != m_cached_ctx.ZBUF.Block(), GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw != 1);
fm, false, force_preload, preserve_rt_rgb, preserve_rt_alpha, unclamped_draw_rect, possible_shuffle, is_possible_mem_clear && FRAME_TEX0.TBP0 != m_cached_ctx.ZBUF.Block(), GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw != 1 && is_possible_mem_clear != ClearType::NormalClear);
// Draw skipped because it was a clear and there was no target.
if (!rt)
@ -2708,8 +2708,8 @@ void GSRendererHW::Draw()
return;
}
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src), (scale_draw < 0) ? src->m_from_target->GetScale() : target_scale, GSTextureCache::RenderTarget, true,
fm, false, force_preload, preserve_rt_color, m_r, src);
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src), (scale_draw < 0 && is_possible_mem_clear != ClearType::NormalClear) ? src->m_from_target->GetScale() : target_scale, GSTextureCache::RenderTarget, true,
fm, false, force_preload, preserve_rt_color | possible_shuffle, m_r, src);
if (!rt) [[unlikely]]
{
GL_INS("ERROR: Failed to create FRAME target, skipping.");
@ -7239,17 +7239,17 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
if (is_target_src && src->m_from_target->m_downscaled && std::abs(draw_size.x - tex_size.x) <= 1 && std::abs(draw_size.y - tex_size.y) <= 1)
return -1;
if (m_context->TEX1.MMAG != 1 || m_vt.m_primclass < GS_TRIANGLE_CLASS || m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 ||
if (!PRIM->TME || m_context->TEX1.MMAG != 1 || m_vt.m_primclass < GS_TRIANGLE_CLASS || m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 ||
IsMipMapDraw() || GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 8 || !src || !src->m_from_target)
return 0;
// Should usually be 2x but some games like Monster House goes from 512x448 -> 128x128
const bool is_downscale = draw_size.x <= (tex_size.x * 0.75f) && draw_size.y <= (tex_size.y * 0.75f);
const bool is_downscale = m_cached_ctx.TEX0.TBW >= m_cached_ctx.FRAME.FBW && draw_size.x <= (tex_size.x * 0.75f) && draw_size.y <= (tex_size.y * 0.75f);
if (is_downscale && draw_size.x >= PCRTCDisplays.GetResolution().x)
return 0;
const bool is_upscale = (draw_size.x / tex_size.x) >= 4 || (draw_size.y / tex_size.y) >= 4;
const bool is_upscale = m_cached_ctx.TEX0.TBW <= m_cached_ctx.FRAME.FBW && (draw_size.x / tex_size.x) >= 4 || (draw_size.y / tex_size.y) >= 4;
// DMC does a blit in strips with the scissor to keep it inside page boundaries, so that's not technically full coverage
// but good enough for what we want.
const bool no_gaps_or_single_sprite = (is_downscale || is_upscale) && (no_gaps || (m_vt.m_primclass == GS_SPRITE_CLASS && SpriteDrawWithoutGaps()));
@ -7265,19 +7265,22 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
return 0;
}
bool GSRendererHW::IsConstantDirectWriteMemClear()
ClearType GSRendererHW::IsConstantDirectWriteMemClear()
{
const bool direct_draw = (m_vt.m_primclass == GS_SPRITE_CLASS) || (((m_index.tail % 6) == 0 && TrianglesAreQuads()) && m_vt.m_primclass == GS_TRIANGLE_CLASS);
// Constant Direct Write without texture/test/blending (aka a GS mem clear)
if (direct_draw && !PRIM->TME // Direct write
&& !(m_draw_env->SCANMSK.MSK & 2)
&& !m_cached_ctx.TEST.ATE // no alpha test
&& !(m_draw_env->SCANMSK.MSK & 2) && !m_cached_ctx.TEST.ATE // no alpha test
&& !m_cached_ctx.TEST.DATE // no destination alpha test
&& (!m_cached_ctx.TEST.ZTE || m_cached_ctx.TEST.ZTST == ZTST_ALWAYS) // no depth test
&& (m_vt.m_eq.rgba == 0xFFFF || m_vertex.next == 2)) // constant color write
return true;
{
if (PRIM->ABE && (!m_context->ALPHA.IsOpaque() || m_cached_ctx.FRAME.FBMSK))
return ClearWithDraw;
return false;
return NormalClear;
}
return NotClear;
}
u32 GSRendererHW::GetConstantDirectWriteMemClearColor() const

View File

@ -16,6 +16,13 @@ MULTI_ISA_DEF(void GSRendererHWPopulateFunctions(GSRendererHW& renderer);)
class GSHwHack;
enum ClearType
{
NotClear,
NormalClear,
ClearWithDraw
};
class GSRendererHW : public GSRenderer
{
MULTI_ISA_FRIEND(GSRendererHWFunctions);
@ -49,7 +56,7 @@ private:
void SwSpriteRender();
bool CanUseSwSpriteRender();
int IsScalingDraw(GSTextureCache::Source* src, bool no_gaps);
bool IsConstantDirectWriteMemClear();
ClearType IsConstantDirectWriteMemClear();
u32 GetConstantDirectWriteMemClearColor() const;
u32 GetConstantDirectWriteMemClearDepth() const;
bool IsReallyDithered() const;