From 839a6daa634011d04a421297f74d1b6a9c47de8b Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Thu, 6 Jun 2024 13:47:55 +0100 Subject: [PATCH] GS: Split out sprite gap check for downscale gap checking --- pcsx2/GS/GSState.cpp | 121 +++++++++++------------ pcsx2/GS/GSState.h | 1 + pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 27 +++-- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 1 - 4 files changed, 77 insertions(+), 73 deletions(-) diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index 38929fdd36..e6c8fdeb7f 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -2998,6 +2998,62 @@ GSState::PRIM_OVERLAP GSState::PrimitiveOverlap() return overlap; } +bool GSState::SpriteDrawWithoutGaps() +{ + // Check that the height matches. Xenosaga 3 draws a letterbox around + // the FMV with a sprite at the top and bottom of the framebuffer. + const GSVertex* v = &m_vertex.buff[0]; + const int first_dpY = v[1].XYZ.Y - v[0].XYZ.Y; + const int first_dpX = v[1].XYZ.X - v[0].XYZ.X; + + // Horizontal Match. + if (((first_dpX + 8) >> 4) == m_r_no_scissor.z) + { + // Borrowed from MergeSprite() modified to calculate heights. + for (u32 i = 2; i < m_vertex.next; i += 2) + { + const int last_pY = v[i - 1].XYZ.Y; + const int dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y; + + if (std::abs(dpY - first_dpY) >= 16 || std::abs(static_cast(v[i].XYZ.Y) - last_pY) >= 16) + return false; + } + + return true; + } + + // Vertical Match. + if (((first_dpY + 8) >> 4) == m_r_no_scissor.w) + { + // Borrowed from MergeSprite(). + const int offset_X = m_context->XYOFFSET.OFX; + for (u32 i = 2; i < m_vertex.next; i += 2) + { + const int last_pX = v[i - 1].XYZ.X; + const int this_start_X = v[i].XYZ.X; + const int last_start_X = v[i - 2].XYZ.X; + + const int dpX = v[i + 1].XYZ.X - v[i].XYZ.X; + + if (this_start_X < last_start_X) + { + const int prev_X = last_start_X - offset_X; + if (std::abs(dpX - prev_X) >= 16 || std::abs(this_start_X - offset_X) >= 16) + return false; + } + else + { + if ((std::abs(dpX - first_dpX) >= 16 && (i + 2) < m_vertex.next) || std::abs(this_start_X - last_pX) >= 16) + return false; + } + } + + return true; + } + + return false; +} + bool GSState::PrimitiveCoversWithoutGaps() { if (m_primitive_covers_without_gaps.has_value()) @@ -3033,69 +3089,10 @@ bool GSState::PrimitiveCoversWithoutGaps() return true; } - // Check that the height matches. Xenosaga 3 draws a letterbox around - // the FMV with a sprite at the top and bottom of the framebuffer. - const GSVertex* v = &m_vertex.buff[0]; - const int first_dpY = v[1].XYZ.Y - v[0].XYZ.Y; - const int first_dpX = v[1].XYZ.X - v[0].XYZ.X; + const bool result = SpriteDrawWithoutGaps(); + m_primitive_covers_without_gaps = result; - // Horizontal Match. - if (((first_dpX + 8) >> 4) == m_r_no_scissor.z) - { - // Borrowed from MergeSprite() modified to calculate heights. - for (u32 i = 2; i < m_vertex.next; i += 2) - { - const int last_pY = v[i - 1].XYZ.Y; - const int dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y; - if (std::abs(dpY - first_dpY) >= 16 || std::abs(static_cast(v[i].XYZ.Y) - last_pY) >= 16) - { - m_primitive_covers_without_gaps = false; - return false; - } - } - - m_primitive_covers_without_gaps = true; - return true; - } - - // Vertical Match. - if (((first_dpY + 8) >> 4) == m_r_no_scissor.w) - { - // Borrowed from MergeSprite(). - const int offset_X = m_context->XYOFFSET.OFX; - for (u32 i = 2; i < m_vertex.next; i += 2) - { - const int last_pX = v[i - 1].XYZ.X; - const int this_start_X = v[i].XYZ.X; - const int last_start_X = v[i - 2].XYZ.X; - - const int dpX = v[i + 1].XYZ.X - v[i].XYZ.X; - - if (this_start_X < last_start_X) - { - const int prev_X = last_start_X - offset_X; - if (std::abs(dpX - prev_X) >= 16 || std::abs(this_start_X - offset_X) >= 16) - { - m_primitive_covers_without_gaps = false; - return false; - } - } - else - { - if ((std::abs(dpX - first_dpX) >= 16 && (i + 2) < m_vertex.next) || std::abs(this_start_X - last_pX) >= 16) - { - m_primitive_covers_without_gaps = false; - return false; - } - } - } - - m_primitive_covers_without_gaps = true; - return true; - } - - m_primitive_covers_without_gaps = false; - return false; + return result; } __forceinline bool GSState::IsAutoFlushDraw(u32 prim) diff --git a/pcsx2/GS/GSState.h b/pcsx2/GS/GSState.h index 201acee109..c2963edfc3 100644 --- a/pcsx2/GS/GSState.h +++ b/pcsx2/GS/GSState.h @@ -410,6 +410,7 @@ public: bool TrianglesAreQuads(bool shuffle_check = false) const; PRIM_OVERLAP PrimitiveOverlap(); + bool SpriteDrawWithoutGaps(); bool PrimitiveCoversWithoutGaps(); GIFRegTEX0 GetTex0Layer(u32 lod); }; diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 4267fa56a3..a29c8cc645 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -2619,9 +2619,13 @@ void GSRendererHW::Draw() { // 1 == Downscale, so we need to reduce the size of the target also. // 2 == Upscale, so likely putting it over the top of the render target. - if(scale_draw == 1) + if (scale_draw == 1) + { target_scale = 1.0f; - m_downscale_source = src->m_from_target->GetScale() > 1.0f; + m_downscale_source = src->m_from_target->GetScale() > 1.0f; + } + else + m_downscale_source = false; //src->m_from_target->GetScale() > 1.0f; // Bad for GTA + Full Spectrum Warrior, good for Sacred Blaze + Parappa. } else m_downscale_source = false; @@ -5213,7 +5217,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c src_copy.reset(src_target->m_texture->IsDepthStencil() ? g_gs_device->CreateDepthStencil( scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) : - (m_downscale_source ? g_gs_device->CreateRenderTarget(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), true, + (m_downscale_source ? g_gs_device->CreateRenderTarget(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), true, true) : g_gs_device->CreateTexture( scaled_copy_size.x, scaled_copy_size.y, 1, src_target->m_texture->GetFormat(), true))); @@ -5226,10 +5230,9 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c } if (m_downscale_source) { - GL_INS("Rescaling %f -> %f", src_scale, scale); const GSVector4 dst_rect = GSVector4(0, 0, src_unscaled_size.x, src_unscaled_size.y); const GSVector4 src_rect = GSVector4(scaled_copy_range) / GSVector4(src_unscaled_size * src_scale).xyxy(); - g_gs_device->StretchRect(src_target->m_texture, GSVector4::cxpr(0.0f,0.0f,1.0f,1.0f), src_copy.get(), dst_rect, src_target->m_texture->IsDepthStencil() ? ShaderConvert::DEPTH_COPY : ShaderConvert::COPY, false); + g_gs_device->StretchRect(src_target->m_texture, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), src_copy.get(), dst_rect, src_target->m_texture->IsDepthStencil() ? ShaderConvert::DEPTH_COPY : ShaderConvert::COPY, false); } else { @@ -7210,14 +7213,18 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps) if (is_downscale && draw_size.x >= PCRTCDisplays.GetResolution().x) return 0; + // Check if we're already downscaled and drawing in current size, try not to rescale it. + if (src && src->m_from_target && 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; + const bool is_upscale = (draw_size.x / 2.0f) >= tex_size.x && (draw_size.y / 2.0f) >= tex_size.y; - + const bool target_scale = is_downscale ? true : false; // 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 = (no_gaps || (m_vt.m_primclass == GS_SPRITE_CLASS && m_index.tail == 2)); - if (no_gaps_or_single_sprite && m_vt.m_primclass >= GS_TRIANGLE_CLASS && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp > 8 && m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0 && !IsMipMapDraw() && - ((is_upscale && !IsDiscardingDstColor()) || (IsDiscardingDstColor() && is_downscale)) && - src && src->m_from_target && !src->m_from_target->m_downscaled && m_context->TEX1.MMAG == 1) + const bool no_gaps_or_single_sprite = (no_gaps || (m_vt.m_primclass == GS_SPRITE_CLASS && SpriteDrawWithoutGaps())); + if (no_gaps_or_single_sprite && m_vt.m_primclass >= GS_TRIANGLE_CLASS && m_context->TEX1.MMAG == 1 && src && src->m_from_target && + GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp > 8 && m_cached_ctx.FRAME.Block() != m_cached_ctx.TEX0.TBP0 && !IsMipMapDraw() && + ((is_upscale && !IsDiscardingDstColor()) || (IsDiscardingDstColor() && is_downscale))) { GL_INS("%s draw detected - from %dx%d to %dx%d", is_downscale ? "Downscale" : "Upscale", tex_size.x, tex_size.y, draw_size.x, draw_size.y); return is_upscale ? 2 : 1; diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index b50d618d6c..8384a4c4a6 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -2398,7 +2398,6 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe dst->readbacks_since_draw = 0; dst->m_last_draw = GSState::s_n; - dst->m_downscaled = scale != GSRendererHW::GetInstance()->GetTextureScaleFactor(); if (dst->m_dirty.empty() && GSLocalMemory::m_psm[TEX0.PSM].depth == 0 && (GSUtil::GetChannelMask(TEX0.PSM) & 0x8)) dst->m_rt_alpha_scale = true;