GS: Split out sprite gap check for downscale gap checking

This commit is contained in:
refractionpcsx2 2024-06-06 13:47:55 +01:00
parent ae57878b27
commit 839a6daa63
4 changed files with 77 additions and 73 deletions

View File

@ -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<int>(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<int>(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)

View File

@ -410,6 +410,7 @@ public:
bool TrianglesAreQuads(bool shuffle_check = false) const;
PRIM_OVERLAP PrimitiveOverlap();
bool SpriteDrawWithoutGaps();
bool PrimitiveCoversWithoutGaps();
GIFRegTEX0 GetTex0Layer(u32 lod);
};

View File

@ -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;

View File

@ -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;