mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: Improve quad detection on triangle strips
This commit is contained in:
parent
194a61a856
commit
89b810ce11
|
@ -1758,6 +1758,7 @@ void GSState::FlushPrim()
|
|||
|
||||
// Skip draw if Z test is enabled, but set to fail all pixels.
|
||||
const bool skip_draw = (m_context->TEST.ZTE && m_context->TEST.ZTST == ZTST_NEVER);
|
||||
m_quad_check_valid = false;
|
||||
|
||||
if (!skip_draw)
|
||||
Draw();
|
||||
|
@ -2879,11 +2880,17 @@ void GSState::GrowVertexBuffer()
|
|||
m_index.buff = index;
|
||||
}
|
||||
|
||||
bool GSState::TrianglesAreQuads(bool shuffle_check) const
|
||||
bool GSState::TrianglesAreQuads(bool shuffle_check)
|
||||
{
|
||||
// If this is a quad, there should only be two distinct values for both X and Y, which
|
||||
// also happen to be the minimum/maximum bounds of the primitive.
|
||||
if (!shuffle_check && m_quad_check_valid)
|
||||
return m_are_quads;
|
||||
|
||||
const GSVertex* const v = m_vertex.buff;
|
||||
m_are_quads = false;
|
||||
m_quad_check_valid = !shuffle_check;
|
||||
|
||||
for (u32 idx = 0; idx < m_index.tail; idx += 6)
|
||||
{
|
||||
const u16* const i = m_index.buff + idx;
|
||||
|
@ -2906,15 +2913,44 @@ bool GSState::TrianglesAreQuads(bool shuffle_check) const
|
|||
return false;
|
||||
}
|
||||
// Degenerate triangles should've been culled already, so we can check indices.
|
||||
u32 extra_verts = 0;
|
||||
for (u32 j = 3; j < 6; j++)
|
||||
// This doesn't really make much sense when it's a triangle strip as it will always have 1 extra vert, so check for distinct values for them.
|
||||
if (PRIM->PRIM != GS_TRIANGLESTRIP)
|
||||
{
|
||||
const u16 tri2_idx = i[j];
|
||||
if (tri2_idx != i[0] && tri2_idx != i[1] && tri2_idx != i[2])
|
||||
extra_verts++;
|
||||
u32 extra_verts = 0;
|
||||
for (u32 j = 3; j < 6; j++)
|
||||
{
|
||||
const u16 tri2_idx = i[j];
|
||||
if (tri2_idx != i[0] && tri2_idx != i[1] && tri2_idx != i[2])
|
||||
extra_verts++;
|
||||
}
|
||||
if (extra_verts == 1)
|
||||
continue;
|
||||
}
|
||||
else if (m_index.tail == 6)
|
||||
{
|
||||
const int first_X = m_vertex.buff[m_index.buff[0]].XYZ.X;
|
||||
const int first_Y = m_vertex.buff[m_index.buff[0]].XYZ.Y;
|
||||
const int second_X = m_vertex.buff[m_index.buff[1]].XYZ.X;
|
||||
const int second_Y = m_vertex.buff[m_index.buff[1]].XYZ.Y;
|
||||
const int third_X = m_vertex.buff[m_index.buff[2]].XYZ.X;
|
||||
const int third_Y = m_vertex.buff[m_index.buff[2]].XYZ.Y;
|
||||
const int new_X = m_vertex.buff[m_index.buff[5]].XYZ.X;
|
||||
const int new_Y = m_vertex.buff[m_index.buff[5]].XYZ.Y;
|
||||
|
||||
const int middle_Y = (second_Y >= third_Y) ? (third_Y + ((second_Y - third_Y) / 2)) : (second_Y + ((third_Y - second_Y) / 2));
|
||||
const int middle_X = (second_X >= third_X) ? (third_X + ((second_X - third_X) / 2)) : (second_X + ((third_X - second_X) / 2));
|
||||
const bool first_lt_X = first_X <= middle_X;
|
||||
const bool first_lt_Y = first_Y <= middle_Y;
|
||||
const bool new_lt_X = new_X <= middle_X;
|
||||
const bool new_lt_Y = new_Y <= middle_Y;
|
||||
|
||||
// Check if verts are on the same side. Not totally accurate, but should be good enough.
|
||||
if (first_lt_X == new_lt_X && new_lt_Y == first_lt_Y)
|
||||
return false;
|
||||
|
||||
m_prim_overlap = PRIM_OVERLAP_NO;
|
||||
break;
|
||||
}
|
||||
if (extra_verts == 1)
|
||||
continue;
|
||||
|
||||
// As a fallback, they might've used different vertices with a tri list, not strip.
|
||||
// Note that this won't work unless the quad is axis-aligned.
|
||||
|
@ -2942,6 +2978,7 @@ bool GSState::TrianglesAreQuads(bool shuffle_check) const
|
|||
}
|
||||
}
|
||||
|
||||
m_are_quads = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3104,6 +3141,46 @@ bool GSState::SpriteDrawWithoutGaps()
|
|||
return true;
|
||||
}
|
||||
|
||||
// Assume it's small sprites. NFSMW and a few other games draw 32x32 sprites in rows to fill the screen.
|
||||
if (((first_dpY + 8) >> 4) == GSLocalMemory::m_psm[m_context->FRAME.PSM].pgs.y)
|
||||
{
|
||||
int lastXEdge = std::max(v[1].XYZ.X, v[0].XYZ.X);
|
||||
int lastYEdge = std::max(v[1].XYZ.Y, v[0].XYZ.Y);
|
||||
for (u32 i = 2; i < m_vertex.next; i += 2)
|
||||
{
|
||||
const int dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y;
|
||||
|
||||
if (first_dpY != dpY)
|
||||
return false;
|
||||
|
||||
const int newYStart = std::min(v[i + 1].XYZ.Y, v[i].XYZ.Y);
|
||||
const int newXEdge = std::max(v[i + 1].XYZ.X, v[i].XYZ.X);
|
||||
if (lastYEdge != newYStart)
|
||||
{
|
||||
if (newYStart != static_cast<int>(m_context->XYOFFSET.OFY))
|
||||
return false;
|
||||
|
||||
const int newXStart = std::min(v[i + 1].XYZ.X, v[i].XYZ.X);
|
||||
|
||||
if (newXStart != lastXEdge)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int dpX = v[i + 1].XYZ.X - v[i].XYZ.X;
|
||||
if (first_dpX != dpX || lastXEdge != newXEdge)
|
||||
return false;
|
||||
}
|
||||
|
||||
lastXEdge = newXEdge;
|
||||
lastYEdge = std::max(v[i + 1].XYZ.Y, v[i].XYZ.Y);
|
||||
}
|
||||
|
||||
m_prim_overlap = PRIM_OVERLAP_NO;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -234,6 +234,8 @@ public:
|
|||
GSVector4i temp_draw_rect = {};
|
||||
std::unique_ptr<GSDumpBase> m_dump;
|
||||
bool m_scissor_invalid = false;
|
||||
bool m_quad_check_valid = false;
|
||||
bool m_are_quads = false;
|
||||
bool m_nativeres = false;
|
||||
bool m_mipmap = false;
|
||||
bool m_texflush_flag = false;
|
||||
|
@ -439,7 +441,7 @@ public:
|
|||
|
||||
void DumpVertices(const std::string& filename);
|
||||
|
||||
bool TrianglesAreQuads(bool shuffle_check = false) const;
|
||||
bool TrianglesAreQuads(bool shuffle_check = false);
|
||||
PRIM_OVERLAP PrimitiveOverlap();
|
||||
bool SpriteDrawWithoutGaps();
|
||||
void CalculatePrimitiveCoversWithoutGaps();
|
||||
|
|
|
@ -1103,12 +1103,14 @@ GSVector2i GSRendererHW::GetValidSize(const GSTextureCache::Source* tex)
|
|||
if (tex_width_pgs == half_draw_width_pgs)
|
||||
{
|
||||
GL_CACHE("Halving width due to texture shuffle with double width, %dx%d -> %dx%d", width, height, width / 2, height);
|
||||
width /= 2;
|
||||
const int src_width = tex ? (tex->m_from_target ? tex->m_from_target->m_valid.width() : tex->GetUnscaledWidth()) : (width / 2);
|
||||
width = std::min(width / 2, src_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL_CACHE("Halving height due to texture shuffle, %dx%d -> %dx%d", width, height, width, height / 2);
|
||||
height /= 2;
|
||||
const int src_height = tex ? (tex->m_from_target ? tex->m_from_target->m_valid.height() : tex->GetUnscaledHeight()) : (height / 2);
|
||||
height = std::min(height / 2, src_height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2294,15 +2296,13 @@ void GSRendererHW::Draw()
|
|||
|
||||
if (GSConfig.DumpGSData)
|
||||
{
|
||||
std::string s;
|
||||
|
||||
if (GSConfig.ShouldDump(s_n - 1, g_perfmon.GetFrame()))
|
||||
{
|
||||
if (m_last_rt && GSConfig.SaveRT)
|
||||
{
|
||||
const u64 frame = g_perfmon.GetFrame();
|
||||
|
||||
s = GetDrawDumpPath("%05d_f%05lld_rt1_%05x_(%05x)_%s.bmp", s_n - 1, frame, m_last_channel_shuffle_fbp, m_last_rt->m_TEX0.TBP0, psm_str(m_cached_ctx.FRAME.PSM));
|
||||
std::string s = GetDrawDumpPath("%05d_f%05lld_rt1_%05x_(%05x)_%s.bmp", s_n - 1, frame, m_last_channel_shuffle_fbp, m_last_rt->m_TEX0.TBP0, psm_str(m_cached_ctx.FRAME.PSM));
|
||||
|
||||
m_last_rt->m_texture->Save(s);
|
||||
}
|
||||
|
@ -2704,7 +2704,6 @@ void GSRendererHW::Draw()
|
|||
g_texture_cache->InvalidateTemporaryZ();
|
||||
}
|
||||
|
||||
|
||||
if (overwriting_whole_rt && overwriting_whole_ds &&
|
||||
TryGSMemClear(no_rt, preserve_rt_color, is_zero_color_clear, rt_end_bp,
|
||||
no_ds, preserve_depth, is_zero_depth_clear, ds_end_bp))
|
||||
|
@ -3061,9 +3060,10 @@ void GSRendererHW::Draw()
|
|||
|
||||
GSTextureCache::Target* ds = nullptr;
|
||||
GIFRegTEX0 ZBUF_TEX0;
|
||||
ZBUF_TEX0.U64 = 0;
|
||||
|
||||
if (!no_ds)
|
||||
{
|
||||
ZBUF_TEX0.U64 = 0;
|
||||
ZBUF_TEX0.TBP0 = m_cached_ctx.ZBUF.Block();
|
||||
ZBUF_TEX0.TBW = m_cached_ctx.FRAME.FBW;
|
||||
ZBUF_TEX0.PSM = m_cached_ctx.ZBUF.PSM;
|
||||
|
@ -3229,7 +3229,7 @@ void GSRendererHW::Draw()
|
|||
|
||||
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src), (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw < 0 && is_possible_mem_clear != ClearType::NormalClear) ? src->m_from_target->GetScale() : target_scale,
|
||||
GSTextureCache::RenderTarget, true, fm, false, force_preload, preserve_rt_color || possible_shuffle, lookup_rect, src);
|
||||
|
||||
|
||||
if (!rt) [[unlikely]]
|
||||
{
|
||||
GL_INS("ERROR: Failed to create FRAME target, skipping.");
|
||||
|
@ -3906,6 +3906,10 @@ void GSRendererHW::Draw()
|
|||
|
||||
const bool rt_update = can_update_size || (m_texture_shuffle && (src && rt && src->m_from_target != rt));
|
||||
|
||||
// If it's updating from a texture shuffle, limit the size to the source size.
|
||||
if (rt_update && !can_update_size && src->m_from_target)
|
||||
update_rect = update_rect.rintersect(src->m_from_target->m_valid);
|
||||
|
||||
// if frame is masked or afailing always to never write frame, wanna make sure we don't touch it. This might happen if DATE or Alpha Test is being used to write to Z.
|
||||
const bool frame_masked = ((m_cached_ctx.FRAME.FBMSK & frame_psm.fmsk) == frame_psm.fmsk) || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_NEVER && !(m_cached_ctx.TEST.AFAIL & AFAIL_FB_ONLY));
|
||||
// Limit to 2x the vertical height of the resolution (for double buffering)
|
||||
|
@ -5023,7 +5027,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
|||
m_last_channel_shuffle_fbmsk = 0xFFFFFFFF;
|
||||
|
||||
// If we're doing per page copying, then set the valid 1 frame ahead if we're continuing, as this will save the target lookup making a new target for the new row.
|
||||
u32 frame_offset = m_cached_ctx.FRAME.Block() + (IsPageCopy() ? 0x20 : 0);
|
||||
const u32 frame_offset = m_cached_ctx.FRAME.Block() + (IsPageCopy() ? 0x20 : 0);
|
||||
GSVector4i new_valid = rt->m_valid;
|
||||
int offset_height = static_cast<int>((((frame_offset - rt->m_TEX0.TBP0) >> 5) / rt->m_TEX0.TBW) * frame_psm.pgs.y) + frame_psm.pgs.y;
|
||||
|
||||
|
@ -8618,7 +8622,7 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
|
|||
|
||||
ClearType GSRendererHW::IsConstantDirectWriteMemClear()
|
||||
{
|
||||
const bool direct_draw = (m_vt.m_primclass == GS_SPRITE_CLASS) || (((m_index.tail % 6) == 0 && TrianglesAreQuads()) && m_vt.m_primclass == GS_TRIANGLE_CLASS);
|
||||
const bool direct_draw = (m_vt.m_primclass == GS_SPRITE_CLASS) || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads());
|
||||
// Constant Direct Write without texture/test/blending (aka a GS mem clear)
|
||||
if (direct_draw && !PRIM->TME // Direct write
|
||||
&& !(m_draw_env->SCANMSK.MSK & 2) && !m_cached_ctx.TEST.ATE // no alpha test
|
||||
|
|
Loading…
Reference in New Issue