mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Improve texture coverage detection
This commit is contained in:
parent
bb67ed3ded
commit
2ce9dd4689
|
@ -3054,42 +3054,50 @@ bool GSState::SpriteDrawWithoutGaps()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSState::PrimitiveCoversWithoutGaps()
|
GSState::NoGapsType GSState::PrimitiveCoversWithoutGaps()
|
||||||
{
|
{
|
||||||
if (m_primitive_covers_without_gaps.has_value())
|
if (m_primitive_covers_without_gaps.has_value())
|
||||||
return m_primitive_covers_without_gaps.value();
|
return m_primitive_covers_without_gaps.value();
|
||||||
|
|
||||||
|
bool issue_found = false;
|
||||||
|
|
||||||
// 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 = false;
|
issue_found = true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = (m_vertex.next < 2) ? FullCover : GapsFound;
|
||||||
|
|
||||||
return m_primitive_covers_without_gaps.value();
|
return m_primitive_covers_without_gaps.value();
|
||||||
}
|
}
|
||||||
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 = (m_index.tail == 6 && TrianglesAreQuads()) ? FullCover : GapsFound;
|
||||||
|
|
||||||
return m_primitive_covers_without_gaps.value();
|
return m_primitive_covers_without_gaps.value();
|
||||||
}
|
}
|
||||||
else if (m_vt.m_primclass != GS_SPRITE_CLASS)
|
else if (m_vt.m_primclass != GS_SPRITE_CLASS)
|
||||||
{
|
{
|
||||||
m_primitive_covers_without_gaps = false;
|
m_primitive_covers_without_gaps = GapsFound;
|
||||||
return false;
|
return m_primitive_covers_without_gaps.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple case: one sprite.
|
// Simple case: one sprite.
|
||||||
if (m_index.tail == 2)
|
if (issue_found == false && m_index.tail == 2)
|
||||||
{
|
{
|
||||||
m_primitive_covers_without_gaps = true;
|
m_primitive_covers_without_gaps = FullCover;
|
||||||
return true;
|
return m_primitive_covers_without_gaps.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool result = SpriteDrawWithoutGaps();
|
if (issue_found)
|
||||||
|
m_primitive_covers_without_gaps = GapsFound;
|
||||||
|
else
|
||||||
|
m_primitive_covers_without_gaps = FullCover;
|
||||||
|
|
||||||
|
const NoGapsType result = SpriteDrawWithoutGaps() ? (issue_found ? SpriteNoGaps : m_primitive_covers_without_gaps.value()) : GapsFound;
|
||||||
m_primitive_covers_without_gaps = result;
|
m_primitive_covers_without_gaps = result;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -3902,7 +3910,7 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||||
new_st.x += floor(static_cast<float>(int_rc.right - scissored_rc.right) * grad.x);
|
new_st.x += floor(static_cast<float>(int_rc.right - scissored_rc.right) * grad.x);
|
||||||
}
|
}
|
||||||
// we need to check that it's not going to repeat over the non-clipped part
|
// we need to check that it's not going to repeat over the non-clipped part
|
||||||
if (wms != CLAMP_REGION_REPEAT && (wms != CLAMP_REPEAT || (static_cast<int>(new_st.x) & ~tw_mask) == (static_cast<int>(new_st.z) & ~tw_mask)))
|
if (wms != CLAMP_REGION_REPEAT && (wms != CLAMP_REPEAT || (static_cast<int>(new_st.x) & ~tw_mask) == (static_cast<int>(new_st.z - 1) & ~tw_mask)))
|
||||||
{
|
{
|
||||||
st.x = new_st.x;
|
st.x = new_st.x;
|
||||||
st.z = new_st.z;
|
st.z = new_st.z;
|
||||||
|
@ -3926,7 +3934,7 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||||
else
|
else
|
||||||
new_st.y += floor(static_cast<float>(int_rc.bottom - scissored_rc.bottom) * grad.y);
|
new_st.y += floor(static_cast<float>(int_rc.bottom - scissored_rc.bottom) * grad.y);
|
||||||
}
|
}
|
||||||
if (wmt != CLAMP_REGION_REPEAT && (wmt != CLAMP_REPEAT || (static_cast<int>(new_st.y) & ~th_mask) == (static_cast<int>(new_st.w) & ~th_mask)))
|
if (wmt != CLAMP_REGION_REPEAT && (wmt != CLAMP_REPEAT || (static_cast<int>(new_st.y) & ~th_mask) == (static_cast<int>(new_st.w - 1) & ~th_mask)))
|
||||||
{
|
{
|
||||||
st.y = new_st.y;
|
st.y = new_st.y;
|
||||||
st.w = new_st.w;
|
st.w = new_st.w;
|
||||||
|
|
|
@ -200,6 +200,13 @@ public:
|
||||||
bool zero_clear;
|
bool zero_clear;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum NoGapsType
|
||||||
|
{
|
||||||
|
GapsFound = 0,
|
||||||
|
SpriteNoGaps,
|
||||||
|
FullCover,
|
||||||
|
};
|
||||||
|
|
||||||
GIFPath m_path[4] = {};
|
GIFPath m_path[4] = {};
|
||||||
const GIFRegPRIM* PRIM = nullptr;
|
const GIFRegPRIM* PRIM = nullptr;
|
||||||
GSPrivRegSet* m_regs = nullptr;
|
GSPrivRegSet* m_regs = nullptr;
|
||||||
|
@ -220,7 +227,7 @@ public:
|
||||||
u32 m_dirty_gs_regs = 0;
|
u32 m_dirty_gs_regs = 0;
|
||||||
int m_backed_up_ctx = 0;
|
int m_backed_up_ctx = 0;
|
||||||
std::vector<GSUploadQueue> m_draw_transfers;
|
std::vector<GSUploadQueue> m_draw_transfers;
|
||||||
std::optional<bool> m_primitive_covers_without_gaps;
|
std::optional<NoGapsType> m_primitive_covers_without_gaps;
|
||||||
GSVector4i m_r = {};
|
GSVector4i m_r = {};
|
||||||
GSVector4i m_r_no_scissor = {};
|
GSVector4i m_r_no_scissor = {};
|
||||||
|
|
||||||
|
@ -411,7 +418,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();
|
||||||
bool PrimitiveCoversWithoutGaps();
|
NoGapsType PrimitiveCoversWithoutGaps();
|
||||||
GIFRegTEX0 GetTex0Layer(u32 lod);
|
GIFRegTEX0 GetTex0Layer(u32 lod);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1474,7 +1474,6 @@ void GSDevice11::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32
|
||||||
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||||
|
|
||||||
const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY;
|
const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY;
|
||||||
//const GSVector4 dRect = GSVector4(dTex->GetRect());
|
|
||||||
StretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), m_merge.cb.get(), nullptr, false);
|
StretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), m_merge.cb.get(), nullptr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
if (m_vt.m_eq.rgba != 0xFFFF || (!m_cached_ctx.ZBUF.ZMSK && !m_vt.m_eq.z) || PrimitiveCoversWithoutGaps() == NoGapsType::GapsFound)
|
||||||
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())
|
if (m_vt.m_eq.rgba != 0xFFFF || (!m_cached_ctx.ZBUF.ZMSK && !m_vt.m_eq.z) || PrimitiveCoversWithoutGaps() == NoGapsType::GapsFound)
|
||||||
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.
|
||||||
|
@ -2187,8 +2187,8 @@ 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 bool no_gaps = PrimitiveCoversWithoutGaps();
|
const NoGapsType no_gaps = PrimitiveCoversWithoutGaps();
|
||||||
const bool not_writing_to_all = (!no_gaps || AreAnyPixelsDiscarded() || !all_depth_tests_pass);
|
const bool not_writing_to_all = (no_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);
|
tmm = GetTextureMinMax(TEX0, MIP_CLAMP, m_vt.IsLinear(), false, no_gaps != NoGapsType::GapsFound);
|
||||||
|
|
||||||
// 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);
|
int scale_draw = IsScalingDraw(src, no_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();
|
const bool is_square = (t_size.y == t_size.x) && m_r.w >= 1023 && PrimitiveCoversWithoutGaps() == 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);
|
tmm = GetTextureMinMax(MIP_TEX0, MIP_CLAMP, m_vt.IsLinear(), false, no_gaps != NoGapsType::GapsFound);
|
||||||
|
|
||||||
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 && m_index.tail > 2 && (!PRIM->TME || TextureCoversWithoutGapsNotEqual()) && m_vt.m_eq.rgba == 0xFFFF)
|
if (m_vt.m_primclass == GS_SPRITE_CLASS && no_gaps != NoGapsType::GapsFound && 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);
|
||||||
|
@ -3785,7 +3785,7 @@ void GSRendererHW::EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GS
|
||||||
if (m_cached_ctx.CLAMP.WMT > CLAMP_CLAMP)
|
if (m_cached_ctx.CLAMP.WMT > CLAMP_CLAMP)
|
||||||
m_cached_ctx.CLAMP.WMT = m_cached_ctx.CLAMP.WMT == CLAMP_REGION_CLAMP ? CLAMP_CLAMP : CLAMP_REPEAT;
|
m_cached_ctx.CLAMP.WMT = m_cached_ctx.CLAMP.WMT == CLAMP_REGION_CLAMP ? CLAMP_CLAMP : CLAMP_REPEAT;
|
||||||
|
|
||||||
m_primitive_covers_without_gaps = rt->m_valid.rintersect(m_r).eq(rt->m_valid);
|
m_primitive_covers_without_gaps = rt->m_valid.rintersect(m_r).eq(rt->m_valid) ? NoGapsType::FullCover : NoGapsType::GapsFound;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4047,7 +4047,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
||||||
m_vertex.head = m_vertex.tail = m_vertex.next = 2;
|
m_vertex.head = m_vertex.tail = m_vertex.next = 2;
|
||||||
m_index.tail = 2;
|
m_index.tail = 2;
|
||||||
|
|
||||||
m_primitive_covers_without_gaps = true;
|
m_primitive_covers_without_gaps = NoGapsType::FullCover;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -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() && !(DATE_PRIMID || DATE_BARRIER || !always_passing_alpha || !IsDepthAlwaysPassing());
|
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());
|
||||||
|
|
||||||
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() && !(DATE || !always_passing_alpha || !IsDepthAlwaysPassing());
|
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && PrimitiveCoversWithoutGaps() == 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() && !(DATE || !always_passing_alpha || !IsDepthAlwaysPassing());
|
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && PrimitiveCoversWithoutGaps() == 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()).coverage;
|
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;
|
||||||
|
|
||||||
// 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()).coverage);
|
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 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())
|
else if (GSUtil::HasSameSwizzleBits(m_cached_ctx.TEX0.PSM, src_target->m_TEX0.PSM) || PrimitiveCoversWithoutGaps() == 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())
|
if (PrimitiveCoversWithoutGaps() == 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
|
||||||
|
|
|
@ -414,7 +414,7 @@ public:
|
||||||
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
|
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
|
||||||
void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
|
void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
|
||||||
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override;
|
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override;
|
||||||
void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min) override;
|
void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override;
|
||||||
|
|
||||||
void FlushClears(GSTexture* tex);
|
void FlushClears(GSTexture* tex);
|
||||||
|
|
||||||
|
|
|
@ -1696,7 +1696,7 @@ void GSDeviceMTL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 off
|
||||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, false, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, false, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
||||||
}}
|
}}
|
||||||
|
|
||||||
void GSDeviceMTL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min)
|
void GSDeviceMTL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect)
|
||||||
{ @autoreleasepool {
|
{ @autoreleasepool {
|
||||||
const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY;
|
const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY;
|
||||||
id<MTLRenderPipelineState> pipeline = m_convert_pipeline[static_cast<int>(shader)];
|
id<MTLRenderPipelineState> pipeline = m_convert_pipeline[static_cast<int>(shader)];
|
||||||
|
@ -1706,7 +1706,6 @@ void GSDeviceMTL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u3
|
||||||
GSMTLDownsamplePSUniform uniform = { {static_cast<uint>(clamp_min.x), static_cast<uint>(clamp_min.x)}, downsample_factor,
|
GSMTLDownsamplePSUniform uniform = { {static_cast<uint>(clamp_min.x), static_cast<uint>(clamp_min.x)}, downsample_factor,
|
||||||
static_cast<float>(downsample_factor * downsample_factor) };
|
static_cast<float>(downsample_factor * downsample_factor) };
|
||||||
|
|
||||||
const GSVector4 dRect = GSVector4(dTex->GetRect());
|
|
||||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, false, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, false, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue