GS/HW: Skip target conversion when alpha doesn't exist

This commit is contained in:
Stenzek 2023-07-30 00:42:55 +10:00 committed by Connor McLaughlin
parent 12e79cccf6
commit 36865f2930
5 changed files with 47 additions and 12 deletions

View File

@ -1264,7 +1264,7 @@ static bool GetMoveTargetPair(GSRendererHW& r, GSTextureCache::Target** src, GIF
const int dst_type = const int dst_type =
GSLocalMemory::m_psm[dst_desc.PSM].depth ? GSTextureCache::DepthStencil : GSTextureCache::RenderTarget; GSLocalMemory::m_psm[dst_desc.PSM].depth ? GSTextureCache::DepthStencil : GSTextureCache::RenderTarget;
GSTextureCache::Target* tdst = g_texture_cache->LookupTarget(dst_desc, tsrc->GetUnscaledSize(), tsrc->GetScale(), GSTextureCache::Target* tdst = g_texture_cache->LookupTarget(dst_desc, tsrc->GetUnscaledSize(), tsrc->GetScale(),
dst_type, true, 0, false, false, preserve_target, tsrc->GetUnscaledRect()); dst_type, true, 0, false, false, preserve_target, preserve_target, tsrc->GetUnscaledRect());
if (!tdst) if (!tdst)
{ {
if (req_target) if (req_target)

View File

@ -1832,11 +1832,14 @@ void GSRendererHW::Draw()
const bool process_texture = PRIM->TME && !(PRIM->ABE && m_context->ALPHA.IsBlack() && !m_cached_ctx.TEX0.TCC); const bool process_texture = PRIM->TME && !(PRIM->ABE && m_context->ALPHA.IsBlack() && !m_cached_ctx.TEX0.TCC);
const u32 frame_end_bp = GSLocalMemory::GetUnwrappedEndBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r); const u32 frame_end_bp = GSLocalMemory::GetUnwrappedEndBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r);
bool preserve_rt_color = const bool tex_is_rt = (process_texture && m_cached_ctx.TEX0.TBP0 >= m_cached_ctx.FRAME.Block() &&
((!no_rt && (!IsDiscardingDstColor() || !PrimitiveCoversWithoutGaps() || !all_depth_tests_pass)) || // Using Dst Color or draw has gaps m_cached_ctx.TEX0.TBP0 < frame_end_bp);
(process_texture && m_cached_ctx.TEX0.TBP0 >= m_cached_ctx.FRAME.Block() && const bool not_writing_to_all = (!PrimitiveCoversWithoutGaps() || !all_depth_tests_pass);
m_cached_ctx.TEX0.TBP0 < frame_end_bp)); // Tex is RT const bool preserve_rt_rgb = (!no_rt && (!IsDiscardingDstRGB() || not_writing_to_all));
bool preserve_depth = preserve_rt_color || (!no_ds && (!all_depth_tests_pass || !m_cached_ctx.DepthWrite())); const bool preserve_rt_alpha = (!no_rt && (!IsDiscardingDstAlpha() || not_writing_to_all));
bool preserve_rt_color = preserve_rt_rgb || preserve_rt_alpha;
bool preserve_depth =
preserve_rt_color || (!no_ds && (!all_depth_tests_pass || !m_cached_ctx.DepthWrite() || m_cached_ctx.TEST.ATE));
// SW CLUT Render enable. // SW CLUT Render enable.
bool force_preload = GSConfig.PreloadFrameWithGSData; bool force_preload = GSConfig.PreloadFrameWithGSData;
@ -2133,6 +2136,7 @@ void GSRendererHW::Draw()
const GSVector4i t_size_rect = GSVector4i::loadh(t_size); const GSVector4i t_size_rect = GSVector4i::loadh(t_size);
// Ensure draw rect is clamped to framebuffer size. Necessary for updating valid area. // Ensure draw rect is clamped to framebuffer size. Necessary for updating valid area.
const GSVector4i unclamped_draw_rect = m_r;
m_r = m_r.rintersect(t_size_rect); m_r = m_r.rintersect(t_size_rect);
float target_scale = GetTextureScaleFactor(); float target_scale = GetTextureScaleFactor();
@ -2163,7 +2167,7 @@ void GSRendererHW::Draw()
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();
const bool is_clear = is_possible_mem_clear && is_square; const bool is_clear = is_possible_mem_clear && is_square;
rt = g_texture_cache->LookupTarget(FRAME_TEX0, t_size, target_scale, GSTextureCache::RenderTarget, true, rt = g_texture_cache->LookupTarget(FRAME_TEX0, t_size, target_scale, GSTextureCache::RenderTarget, true,
fm, false, force_preload, preserve_rt_color, m_r); fm, false, force_preload, preserve_rt_rgb, preserve_rt_alpha, unclamped_draw_rect);
// Draw skipped because it was a clear and there was no target. // Draw skipped because it was a clear and there was no target.
if (!rt) if (!rt)
@ -2197,7 +2201,7 @@ void GSRendererHW::Draw()
ZBUF_TEX0.PSM = m_cached_ctx.ZBUF.PSM; ZBUF_TEX0.PSM = m_cached_ctx.ZBUF.PSM;
ds = g_texture_cache->LookupTarget(ZBUF_TEX0, t_size, target_scale, GSTextureCache::DepthStencil, ds = g_texture_cache->LookupTarget(ZBUF_TEX0, t_size, target_scale, GSTextureCache::DepthStencil,
m_cached_ctx.DepthWrite(), 0, false, force_preload, preserve_depth, m_r); m_cached_ctx.DepthWrite(), 0, false, force_preload, preserve_depth, preserve_depth, unclamped_draw_rect);
if (!ds) if (!ds)
{ {
ds = g_texture_cache->CreateTarget(ZBUF_TEX0, t_size, GetValidSize(src), target_scale, GSTextureCache::DepthStencil, ds = g_texture_cache->CreateTarget(ZBUF_TEX0, t_size, GetValidSize(src), target_scale, GSTextureCache::DepthStencil,
@ -5814,7 +5818,25 @@ bool GSRendererHW::IsDiscardingDstColor()
(!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack()) && // no blending or writing black (!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack()) && // no blending or writing black
!m_cached_ctx.TEST.ATE && // not testing alpha (might discard some pixels) !m_cached_ctx.TEST.ATE && // not testing alpha (might discard some pixels)
!m_cached_ctx.TEST.DATE && // not reading alpha !m_cached_ctx.TEST.DATE && // not reading alpha
(m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) == 0); // no channels masked (m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) == 0); // no channels masked
}
bool GSRendererHW::IsDiscardingDstRGB()
{
return ((!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack()) && // no blending or writing black
!m_cached_ctx.TEST.ATE && // not testing alpha (might discard some pixels)
!m_cached_ctx.TEST.DATE && // not reading alpha
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFFFFFFu) ==
0); // RGB isn't masked
}
bool GSRendererHW::IsDiscardingDstAlpha()
{
return ((!PRIM->ABE || m_context->ALPHA.C != 1) && // not using Ad
!m_cached_ctx.TEST.ATE && // not testing alpha (might discard some pixels)
!m_cached_ctx.TEST.DATE && // not reading alpha
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFF000000u) ==
0); // alpha isn't masked
} }
bool GSRendererHW::PrimitiveCoversWithoutGaps() bool GSRendererHW::PrimitiveCoversWithoutGaps()

View File

@ -62,6 +62,8 @@ private:
u32 GetConstantDirectWriteMemClearColor() const; u32 GetConstantDirectWriteMemClearColor() const;
bool IsReallyDithered() const; bool IsReallyDithered() const;
bool IsDiscardingDstColor(); bool IsDiscardingDstColor();
bool IsDiscardingDstRGB();
bool IsDiscardingDstAlpha();
bool PrimitiveCoversWithoutGaps(); bool PrimitiveCoversWithoutGaps();
enum class CLUTDrawTestResult enum class CLUTDrawTestResult

View File

@ -1241,7 +1241,7 @@ GSVector2i GSTextureCache::ScaleRenderTargetSize(const GSVector2i& sz, float sca
} }
GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type,
bool used, u32 fbmask, bool is_frame, bool preload, bool preserve_target, const GSVector4i draw_rect) bool used, u32 fbmask, bool is_frame, bool preload, bool preserve_rgb, bool preserve_alpha, const GSVector4i draw_rect)
{ {
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM]; const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
const u32 bp = TEX0.TBP0; const u32 bp = TEX0.TBP0;
@ -1393,6 +1393,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
} }
// If our RGB was invalidated, we need to pull it from depth. // If our RGB was invalidated, we need to pull it from depth.
const bool preserve_target = preserve_rgb || preserve_alpha;
if (type == RenderTarget && (preserve_target || !dst->m_valid.rintersect(draw_rect).eq(dst->m_valid)) && if (type == RenderTarget && (preserve_target || !dst->m_valid.rintersect(draw_rect).eq(dst->m_valid)) &&
!dst->m_valid_rgb && !FullRectDirty(dst, 0x7) && !dst->m_valid_rgb && !FullRectDirty(dst, 0x7) &&
(GSLocalMemory::m_psm[TEX0.PSM].trbpp < 24 || fbmask != 0x00FFFFFFu)) (GSLocalMemory::m_psm[TEX0.PSM].trbpp < 24 || fbmask != 0x00FFFFFFu))
@ -1479,6 +1480,15 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
if (dst_match) if (dst_match)
{ {
calcRescale(dst_match); calcRescale(dst_match);
// If we don't need A, and the existing target doesn't have valid alpha, don't bother converting it.
const bool has_alpha = dst_match->m_valid_alpha_low || dst_match->m_valid_alpha_high;
const bool preserve_target = (preserve_rgb || (preserve_alpha && has_alpha)) ||
!draw_rect.rintersect(dst_match->m_valid).eq(dst_match->m_valid);
// Clear instead of invalidating if there is anything which isn't touched.
clear |= (!preserve_target && fbmask != 0);
dst = Target::Create(TEX0, new_size.x, new_size.y, scale, type, clear); dst = Target::Create(TEX0, new_size.x, new_size.y, scale, type, clear);
if (!dst) if (!dst)
return nullptr; return nullptr;
@ -1509,7 +1519,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
shader = (fmt_16_bits) ? ShaderConvert::FLOAT16_TO_RGB5A1 : ShaderConvert::FLOAT32_TO_RGBA8; shader = (fmt_16_bits) ? ShaderConvert::FLOAT16_TO_RGB5A1 : ShaderConvert::FLOAT32_TO_RGBA8;
} }
if (!preserve_target && draw_rect.rintersect(dst_match->m_valid).eq(dst_match->m_valid))
if (!preserve_target)
{ {
GL_INS("TC: Not converting existing %s[%x] because it's fully overwritten.", to_string(!type), dst->m_TEX0.TBP0); GL_INS("TC: Not converting existing %s[%x] because it's fully overwritten.", to_string(!type), dst->m_TEX0.TBP0);
} }

View File

@ -478,7 +478,7 @@ public:
Target* FindTargetOverlap(Target* target, int type, int psm); Target* FindTargetOverlap(Target* target, int type, int psm);
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0, Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true, bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_rgb = true, bool preserve_alpha = true,
const GSVector4i draw_rc = GSVector4i::zero()); const GSVector4i draw_rc = GSVector4i::zero());
Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size,float scale, int type, bool used = true, u32 fbmask = 0, Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size,float scale, int type, bool used = true, u32 fbmask = 0,
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true, bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true,