GS: Clean up usage of PrimitiveCoversWithoutGaps

This commit is contained in:
refractionpcsx2 2024-06-29 17:53:14 +01:00
parent b5258a83c8
commit 7ab494ca31
5 changed files with 35 additions and 43 deletions

View File

@ -3054,47 +3054,35 @@ bool GSState::SpriteDrawWithoutGaps()
return false; return false;
} }
GSState::NoGapsType GSState::PrimitiveCoversWithoutGaps() void GSState::CalculatePrimitiveCoversWithoutGaps()
{ {
if (m_primitive_covers_without_gaps != Uninitialized)
return m_primitive_covers_without_gaps;
m_primitive_covers_without_gaps = FullCover; m_primitive_covers_without_gaps = FullCover;
// Draw shouldn't be offset. // Draw shouldn't be offset.
if (((m_r.eq32(GSVector4i::zero())).mask() & 0xff) != 0xff) if (((m_r.eq32(GSVector4i::zero())).mask() & 0xff) != 0xff)
{
m_primitive_covers_without_gaps = GapsFound; m_primitive_covers_without_gaps = GapsFound;
}
if (m_vt.m_primclass == GS_POINT_CLASS) if (m_vt.m_primclass == GS_POINT_CLASS)
{ {
m_primitive_covers_without_gaps = (m_vertex.next < 2) ? m_primitive_covers_without_gaps : GapsFound; m_primitive_covers_without_gaps = (m_vertex.next < 2) ? m_primitive_covers_without_gaps : GapsFound;
return;
return m_primitive_covers_without_gaps;
} }
else if (m_vt.m_primclass == GS_TRIANGLE_CLASS) else if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
{ {
m_primitive_covers_without_gaps = (m_index.tail == 6 && TrianglesAreQuads()) ? m_primitive_covers_without_gaps : GapsFound; m_primitive_covers_without_gaps = (m_index.tail == 6 && TrianglesAreQuads()) ? m_primitive_covers_without_gaps : GapsFound;
return;
return m_primitive_covers_without_gaps;
} }
else if (m_vt.m_primclass != GS_SPRITE_CLASS) else if (m_vt.m_primclass != GS_SPRITE_CLASS)
{ {
m_primitive_covers_without_gaps = GapsFound; m_primitive_covers_without_gaps = GapsFound;
return m_primitive_covers_without_gaps; return;
} }
// Simple case: one sprite. // Simple case: one sprite.
if (m_primitive_covers_without_gaps != GapsFound && m_index.tail == 2) if (m_primitive_covers_without_gaps != GapsFound && m_index.tail == 2)
{ return;
return m_primitive_covers_without_gaps;
}
const NoGapsType result = SpriteDrawWithoutGaps() ? (m_primitive_covers_without_gaps == GapsFound ? SpriteNoGaps : m_primitive_covers_without_gaps) : GapsFound; m_primitive_covers_without_gaps = SpriteDrawWithoutGaps() ? (m_primitive_covers_without_gaps == GapsFound ? SpriteNoGaps : m_primitive_covers_without_gaps) : GapsFound;
m_primitive_covers_without_gaps = result;
return result;
} }
__forceinline bool GSState::IsAutoFlushDraw(u32 prim) __forceinline bool GSState::IsAutoFlushDraw(u32 prim)
@ -3774,7 +3762,7 @@ static bool UsesRegionRepeat(int fix, int msk, int min, int max, int* min_out, i
return sets_bits || clears_bits; return sets_bits || clears_bits;
} }
GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCLAMP CLAMP, bool linear, bool clamp_to_tsize, bool no_gaps) GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCLAMP CLAMP, bool linear, bool clamp_to_tsize)
{ {
// TODO: some of the +1s can be removed if linear == false // TODO: some of the +1s can be removed if linear == false
@ -3871,7 +3859,7 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
const GSVector2 grad(uv_range / pos_range); const GSVector2 grad(uv_range / pos_range);
// Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this // Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this
// optimization doesn't work when perspective correction is enabled. // optimization doesn't work when perspective correction is enabled.
if (m_vt.m_primclass == GS_SPRITE_CLASS && PRIM->FST == 1 && no_gaps) if (m_vt.m_primclass == GS_SPRITE_CLASS && PRIM->FST == 1 && m_primitive_covers_without_gaps != NoGapsType::GapsFound)
{ {
// When coordinates are fractional, GS appears to draw to the right/bottom (effectively // When coordinates are fractional, GS appears to draw to the right/bottom (effectively
// taking the ceiling), not to the top/left (taking the floor). // taking the ceiling), not to the top/left (taking the floor).

View File

@ -182,7 +182,7 @@ protected:
GSVector4i coverage; ///< Part of the texture used GSVector4i coverage; ///< Part of the texture used
u8 uses_boundary; ///< Whether or not the usage touches the left, top, right, or bottom edge (and therefore needs wrap modes preserved) u8 uses_boundary; ///< Whether or not the usage touches the left, top, right, or bottom edge (and therefore needs wrap modes preserved)
}; };
TextureMinMaxResult GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCLAMP CLAMP, bool linear, bool clamp_to_tsize, bool no_gaps); TextureMinMaxResult GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCLAMP CLAMP, bool linear, bool clamp_to_tsize);
bool TryAlphaTest(u32& fm, u32& zm); bool TryAlphaTest(u32& fm, u32& zm);
bool IsOpaque(); bool IsOpaque();
bool IsMipMapDraw(); bool IsMipMapDraw();
@ -419,7 +419,7 @@ public:
bool TrianglesAreQuads(bool shuffle_check = false) const; bool TrianglesAreQuads(bool shuffle_check = false) const;
PRIM_OVERLAP PrimitiveOverlap(); PRIM_OVERLAP PrimitiveOverlap();
bool SpriteDrawWithoutGaps(); bool SpriteDrawWithoutGaps();
NoGapsType PrimitiveCoversWithoutGaps(); void CalculatePrimitiveCoversWithoutGaps();
GIFRegTEX0 GetTex0Layer(u32 lod); GIFRegTEX0 GetTex0Layer(u32 lod);
}; };

View File

@ -1251,7 +1251,7 @@ bool GSRendererHW::IsSplitClearActive() const
bool GSRendererHW::IsStartingSplitClear() bool GSRendererHW::IsStartingSplitClear()
{ {
// Shouldn't have gaps. // Shouldn't have gaps.
if (m_vt.m_eq.rgba != 0xFFFF || (!m_cached_ctx.ZBUF.ZMSK && !m_vt.m_eq.z) || PrimitiveCoversWithoutGaps() != NoGapsType::FullCover) if (m_vt.m_eq.rgba != 0xFFFF || (!m_cached_ctx.ZBUF.ZMSK && !m_vt.m_eq.z) || m_primitive_covers_without_gaps != NoGapsType::FullCover)
return false; return false;
// Limit to only single page wide tall draws for now. Too many false positives otherwise (e.g. NFSU). // Limit to only single page wide tall draws for now. Too many false positives otherwise (e.g. NFSU).
@ -1289,7 +1289,7 @@ bool GSRendererHW::ContinueSplitClear()
return false; return false;
// Shouldn't have gaps. // Shouldn't have gaps.
if (m_vt.m_eq.rgba != 0xFFFF || (!m_cached_ctx.ZBUF.ZMSK && !m_vt.m_eq.z) || PrimitiveCoversWithoutGaps() != NoGapsType::FullCover) if (m_vt.m_eq.rgba != 0xFFFF || (!m_cached_ctx.ZBUF.ZMSK && !m_vt.m_eq.z) || m_primitive_covers_without_gaps != NoGapsType::FullCover)
return false; return false;
// Remove any targets which are directly at the start, since we checked this draw in the last. // Remove any targets which are directly at the start, since we checked this draw in the last.
@ -1998,7 +1998,6 @@ void GSRendererHW::Draw()
m_cached_ctx.TEST = context->TEST; m_cached_ctx.TEST = context->TEST;
m_cached_ctx.FRAME = context->FRAME; m_cached_ctx.FRAME = context->FRAME;
m_cached_ctx.ZBUF = context->ZBUF; m_cached_ctx.ZBUF = context->ZBUF;
m_primitive_covers_without_gaps = NoGapsType::Uninitialized;
if (IsBadFrame()) if (IsBadFrame())
{ {
@ -2187,8 +2186,9 @@ void GSRendererHW::Draw()
m_process_texture = PRIM->TME && !(PRIM->ABE && m_context->ALPHA.IsBlack() && !m_cached_ctx.TEX0.TCC) && !(no_rt && (!m_cached_ctx.TEST.ATE || m_cached_ctx.TEST.ATST <= ATST_ALWAYS)); m_process_texture = PRIM->TME && !(PRIM->ABE && m_context->ALPHA.IsBlack() && !m_cached_ctx.TEX0.TCC) && !(no_rt && (!m_cached_ctx.TEST.ATE || m_cached_ctx.TEST.ATST <= ATST_ALWAYS));
const NoGapsType no_gaps = PrimitiveCoversWithoutGaps(); CalculatePrimitiveCoversWithoutGaps();
const bool not_writing_to_all = (no_gaps != NoGapsType::FullCover || AreAnyPixelsDiscarded() || !all_depth_tests_pass);
const bool not_writing_to_all = (m_primitive_covers_without_gaps != NoGapsType::FullCover || AreAnyPixelsDiscarded() || !all_depth_tests_pass);
bool preserve_depth = bool preserve_depth =
not_writing_to_all || (!no_ds && (!all_depth_tests_pass || !m_cached_ctx.DepthWrite() || m_cached_ctx.TEST.ATE)); not_writing_to_all || (!no_ds && (!all_depth_tests_pass || !m_cached_ctx.DepthWrite() || m_cached_ctx.TEST.ATE));
@ -2488,7 +2488,7 @@ void GSRendererHW::Draw()
TEX0 = m_cached_ctx.TEX0; TEX0 = m_cached_ctx.TEX0;
} }
tmm = GetTextureMinMax(TEX0, MIP_CLAMP, m_vt.IsLinear(), false, no_gaps != NoGapsType::GapsFound); tmm = GetTextureMinMax(TEX0, MIP_CLAMP, m_vt.IsLinear(), false);
// Snowblind games set TW/TH to 1024, and use UVs for smaller textures inside that. // Snowblind games set TW/TH to 1024, and use UVs for smaller textures inside that.
// Such textures usually contain junk in local memory, so try to make them smaller based on UVs. // Such textures usually contain junk in local memory, so try to make them smaller based on UVs.
@ -2620,7 +2620,7 @@ void GSRendererHW::Draw()
m_r = m_r.rintersect(t_size_rect); m_r = m_r.rintersect(t_size_rect);
float target_scale = GetTextureScaleFactor(); float target_scale = GetTextureScaleFactor();
int scale_draw = IsScalingDraw(src, no_gaps != NoGapsType::GapsFound); int scale_draw = IsScalingDraw(src, m_primitive_covers_without_gaps != NoGapsType::GapsFound);
if (target_scale > 1.0f && scale_draw > 0) if (target_scale > 1.0f && scale_draw > 0)
{ {
// 1 == Downscale, so we need to reduce the size of the target also. // 1 == Downscale, so we need to reduce the size of the target also.
@ -2685,7 +2685,7 @@ void GSRendererHW::Draw()
// 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
// (very close to 1024x1024, but apparently the GS rounds down..). So, catch that here, we don't want to // (very close to 1024x1024, but apparently the GS rounds down..). So, catch that here, we don't want to
// create that target, because the clear isn't black, it'll hang around and never get invalidated. // create that target, because the clear isn't black, it'll hang around and never get invalidated.
const bool is_square = (t_size.y == t_size.x) && m_r.w >= 1023 && PrimitiveCoversWithoutGaps() == NoGapsType::FullCover; const bool is_square = (t_size.y == t_size.x) && m_r.w >= 1023 && m_primitive_covers_without_gaps == NoGapsType::FullCover;
const bool is_clear = is_possible_mem_clear && is_square; const bool is_clear = is_possible_mem_clear && is_square;
const bool possible_shuffle = draw_sprite_tex && (((src && src->m_target && src->m_from_target && src->m_from_target->m_32_bits_fmt) && const bool possible_shuffle = draw_sprite_tex && (((src && src->m_target && src->m_from_target && src->m_from_target->m_32_bits_fmt) &&
GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) || GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) ||
@ -2976,7 +2976,7 @@ void GSRendererHW::Draw()
m_vt.m_min.t *= 0.5f; m_vt.m_min.t *= 0.5f;
m_vt.m_max.t *= 0.5f; m_vt.m_max.t *= 0.5f;
tmm = GetTextureMinMax(MIP_TEX0, MIP_CLAMP, m_vt.IsLinear(), false, no_gaps != NoGapsType::GapsFound); tmm = GetTextureMinMax(MIP_TEX0, MIP_CLAMP, m_vt.IsLinear(), false);
src->UpdateLayer(MIP_TEX0, tmm.coverage, layer - m_lod.x); src->UpdateLayer(MIP_TEX0, tmm.coverage, layer - m_lod.x);
} }
@ -3006,7 +3006,7 @@ void GSRendererHW::Draw()
if (!m_texture_shuffle && !m_channel_shuffle) if (!m_texture_shuffle && !m_channel_shuffle)
{ {
// Try to turn blits in to single sprites, saves upscaling problems when striped clears/blits. // Try to turn blits in to single sprites, saves upscaling problems when striped clears/blits.
if (m_vt.m_primclass == GS_SPRITE_CLASS && no_gaps == NoGapsType::FullCover && m_index.tail > 2 && (!PRIM->TME || TextureCoversWithoutGapsNotEqual()) && m_vt.m_eq.rgba == 0xFFFF) if (m_vt.m_primclass == GS_SPRITE_CLASS && m_primitive_covers_without_gaps == NoGapsType::FullCover && m_index.tail > 2 && (!PRIM->TME || TextureCoversWithoutGapsNotEqual()) && m_vt.m_eq.rgba == 0xFFFF)
{ {
// Full final framebuffer only. // Full final framebuffer only.
const GSVector2i fb_size = PCRTCDisplays.GetFramebufferSize(-1); const GSVector2i fb_size = PCRTCDisplays.GetFramebufferSize(-1);
@ -4592,7 +4592,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
{ {
const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32); const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32);
const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS); const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS);
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && PrimitiveCoversWithoutGaps() == NoGapsType::FullCover && !(DATE_PRIMID || DATE_BARRIER || !always_passing_alpha || !IsDepthAlwaysPassing()); const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover && !(DATE_PRIMID || DATE_BARRIER || !always_passing_alpha || !IsDepthAlwaysPassing());
if (!full_cover) if (!full_cover)
{ {
@ -5586,7 +5586,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32); const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32);
const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS); const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS);
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && PrimitiveCoversWithoutGaps() == NoGapsType::FullCover && !(DATE || !always_passing_alpha || !IsDepthAlwaysPassing()); const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover && !(DATE || !always_passing_alpha || !IsDepthAlwaysPassing());
// On DX FBMask emulation can be missing on lower blend levels, so we'll do whatever the API does. // On DX FBMask emulation can be missing on lower blend levels, so we'll do whatever the API does.
const u32 fb_mask = m_conf.colormask.wa ? (m_conf.ps.fbmask ? m_conf.cb_ps.FbMask.a : 0) : 0xFF; const u32 fb_mask = m_conf.colormask.wa ? (m_conf.ps.fbmask ? m_conf.cb_ps.FbMask.a : 0) : 0xFF;
@ -5873,7 +5873,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
{ {
const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32); const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32);
const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS); const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS);
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && PrimitiveCoversWithoutGaps() == NoGapsType::FullCover && !(DATE || !always_passing_alpha || !IsDepthAlwaysPassing()); const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover && !(DATE || !always_passing_alpha || !IsDepthAlwaysPassing());
// Restrict this to only when we're overwriting the whole target. // Restrict this to only when we're overwriting the whole target.
new_scale_rt_alpha = full_cover; new_scale_rt_alpha = full_cover;
@ -6362,7 +6362,7 @@ GSRendererHW::CLUTDrawTestResult GSRendererHW::PossibleCLUTDraw()
if (m_process_texture) if (m_process_texture)
{ {
// If we're using a texture to draw our CLUT/whatever, we need the GPU to write back dirty data we need. // If we're using a texture to draw our CLUT/whatever, we need the GPU to write back dirty data we need.
const GSVector4i r = GetTextureMinMax(m_cached_ctx.TEX0, m_cached_ctx.CLAMP, m_vt.IsLinear(), false, m_vt.m_primclass == GS_SPRITE_CLASS && PrimitiveCoversWithoutGaps() != NoGapsType::GapsFound).coverage; const GSVector4i r = GetTextureMinMax(m_cached_ctx.TEX0, m_cached_ctx.CLAMP, m_vt.IsLinear(), false).coverage;
// If we have GPU CLUT enabled, don't do a CPU draw when it would result in a download. // If we have GPU CLUT enabled, don't do a CPU draw when it would result in a download.
if (GSConfig.UserHacks_GPUTargetCLUTMode != GSGPUTargetCLUTMode::Disabled) if (GSConfig.UserHacks_GPUTargetCLUTMode != GSGPUTargetCLUTMode::Disabled)
@ -6476,7 +6476,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t
// If the EE has written over our sample area, we're fine to do this on the CPU, despite the target. // If the EE has written over our sample area, we're fine to do this on the CPU, despite the target.
if (!src_target->m_dirty.empty()) if (!src_target->m_dirty.empty())
{ {
const GSVector4i tr(GetTextureMinMax(m_cached_ctx.TEX0, m_cached_ctx.CLAMP, m_vt.IsLinear(), false, m_vt.m_primclass == GS_SPRITE_CLASS && PrimitiveCoversWithoutGaps() != NoGapsType::GapsFound).coverage); const GSVector4i tr(GetTextureMinMax(m_cached_ctx.TEX0, m_cached_ctx.CLAMP, m_vt.IsLinear(), false).coverage);
const u32 start_bp = GSLocalMemory::GetStartBlockAddress(m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.TBW, m_cached_ctx.TEX0.PSM, tr); const u32 start_bp = GSLocalMemory::GetStartBlockAddress(m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.TBW, m_cached_ctx.TEX0.PSM, tr);
const u32 end_bp = GSLocalMemory::GetEndBlockAddress(m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.TBW, m_cached_ctx.TEX0.PSM, tr); const u32 end_bp = GSLocalMemory::GetEndBlockAddress(m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.TBW, m_cached_ctx.TEX0.PSM, tr);
@ -6493,7 +6493,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t
{ {
return true; return true;
} }
else if (GSUtil::HasSameSwizzleBits(m_cached_ctx.TEX0.PSM, src_target->m_TEX0.PSM) || PrimitiveCoversWithoutGaps() == NoGapsType::FullCover) else if (GSUtil::HasSameSwizzleBits(m_cached_ctx.TEX0.PSM, src_target->m_TEX0.PSM) || m_primitive_covers_without_gaps == NoGapsType::FullCover)
return false; return false;
} }
} }
@ -6945,7 +6945,7 @@ bool GSRendererHW::TryTargetClear(GSTextureCache::Target* rt, GSTextureCache::Ta
bool GSRendererHW::TryGSMemClear(bool no_rt, bool preserve_rt, bool invalidate_rt, u32 rt_end_bp, bool GSRendererHW::TryGSMemClear(bool no_rt, bool preserve_rt, bool invalidate_rt, u32 rt_end_bp,
bool no_ds, bool preserve_z, bool invalidate_z, u32 ds_end_bp) bool no_ds, bool preserve_z, bool invalidate_z, u32 ds_end_bp)
{ {
if (PrimitiveCoversWithoutGaps() == NoGapsType::GapsFound) if (m_primitive_covers_without_gaps == NoGapsType::GapsFound)
return false; return false;
// Limit the hack to a single full buffer clear. Some games might use severals column to clear a screen // Limit the hack to a single full buffer clear. Some games might use severals column to clear a screen

View File

@ -182,11 +182,13 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc, b
gd.sel.tfx = TFX_DECAL; gd.sel.tfx = TFX_DECAL;
} }
hw.CalculatePrimitiveCoversWithoutGaps();
bool mipmap = hw.IsMipMapActive(); bool mipmap = hw.IsMipMapActive();
GIFRegTEX0 TEX0 = context->GetSizeFixedTEX0(vt.m_min.t.xyxy(vt.m_max.t), vt.IsLinear(), mipmap); GIFRegTEX0 TEX0 = context->GetSizeFixedTEX0(vt.m_min.t.xyxy(vt.m_max.t), vt.IsLinear(), mipmap);
const GSVector4i r = hw.GetTextureMinMax(TEX0, context->CLAMP, gd.sel.ltf, true, hw.m_index.tail < 3).coverage; const GSVector4i r = hw.GetTextureMinMax(TEX0, context->CLAMP, gd.sel.ltf, true).coverage;
if (!hw.m_sw_texture[0]) if (!hw.m_sw_texture[0])
hw.m_sw_texture[0] = std::make_unique<GSTextureCacheSW::Texture>(0, TEX0, env.TEXA); hw.m_sw_texture[0] = std::make_unique<GSTextureCacheSW::Texture>(0, TEX0, env.TEXA);
@ -287,7 +289,7 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc, b
else else
hw.m_sw_texture[i]->Reset(gd.sel.tw + 3, MIP_TEX0, env.TEXA); hw.m_sw_texture[i]->Reset(gd.sel.tw + 3, MIP_TEX0, env.TEXA);
GSVector4i r = hw.GetTextureMinMax(MIP_TEX0, MIP_CLAMP, gd.sel.ltf, true, hw.m_index.tail < 3).coverage; GSVector4i r = hw.GetTextureMinMax(MIP_TEX0, MIP_CLAMP, gd.sel.ltf, true).coverage;
hw.m_sw_texture[i]->Update(r); hw.m_sw_texture[i]->Update(r);
gd.tex[i] = hw.m_sw_texture[i]->m_buff; gd.tex[i] = hw.m_sw_texture[i]->m_buff;
} }

View File

@ -1051,11 +1051,13 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
gd.sel.tfx = TFX_DECAL; gd.sel.tfx = TFX_DECAL;
} }
CalculatePrimitiveCoversWithoutGaps();
bool mipmap = IsMipMapActive(); bool mipmap = IsMipMapActive();
GIFRegTEX0 TEX0 = m_context->GetSizeFixedTEX0(m_vt.m_min.t.xyxy(m_vt.m_max.t), m_vt.IsLinear(), mipmap); GIFRegTEX0 TEX0 = m_context->GetSizeFixedTEX0(m_vt.m_min.t.xyxy(m_vt.m_max.t), m_vt.IsLinear(), mipmap);
GSVector4i r = GetTextureMinMax(TEX0, context->CLAMP, gd.sel.ltf, true, m_index.tail < 3).coverage; GSVector4i r = GetTextureMinMax(TEX0, context->CLAMP, gd.sel.ltf, true).coverage;
GSTextureCacheSW::Texture* t = m_tc->Lookup(TEX0, env.TEXA); GSTextureCacheSW::Texture* t = m_tc->Lookup(TEX0, env.TEXA);
@ -1161,7 +1163,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
return false; return false;
} }
GSVector4i r = GetTextureMinMax(MIP_TEX0, MIP_CLAMP, gd.sel.ltf, true, m_index.tail < 3).coverage; GSVector4i r = GetTextureMinMax(MIP_TEX0, MIP_CLAMP, gd.sel.ltf, true).coverage;
data->SetSource(t, r, i); data->SetSource(t, r, i);
} }