Skip to content

Commit

Permalink
GS: Move PrimitiveWithoutGaps function to GSState
Browse files Browse the repository at this point in the history
  • Loading branch information
refractionpcsx2 committed Apr 1, 2024
1 parent f3a75f5 commit c729a6f
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 105 deletions.
100 changes: 100 additions & 0 deletions pcsx2/GS/GSState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2981,6 +2981,106 @@ GSState::PRIM_OVERLAP GSState::PrimitiveOverlap()
return overlap;
}

bool GSState::PrimitiveCoversWithoutGaps()
{
if (m_primitive_covers_without_gaps.has_value())
return m_primitive_covers_without_gaps.value();

// Draw shouldn't be offset.
if (((m_r.eq32(GSVector4i::zero())).mask() & 0xff) != 0xff)
{
m_primitive_covers_without_gaps = false;
return false;
}

if (m_vt.m_primclass == GS_POINT_CLASS)
{
m_primitive_covers_without_gaps = (m_vertex.next < 2);
return m_primitive_covers_without_gaps.value();
}
else if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
{
m_primitive_covers_without_gaps = (m_index.tail == 6 && TrianglesAreQuads());
return m_primitive_covers_without_gaps.value();
}
else if (m_vt.m_primclass != GS_SPRITE_CLASS)
{
m_primitive_covers_without_gaps = false;
return false;
}

// Simple case: one sprite.
if (m_index.tail == 2)
{
m_primitive_covers_without_gaps = true;
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;

// Horizontal Match.
if ((first_dpX >> 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 >> 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 || 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;
}

__forceinline bool GSState::IsAutoFlushDraw(u32 prim)
{
if (!PRIM->TME || (GSConfig.UserHacks_AutoFlush == GSHWAutoFlushLevel::SpritesOnly && prim != GS_SPRITE))
Expand Down
4 changes: 4 additions & 0 deletions pcsx2/GS/GSState.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ class GSState : public GSAlignedClass<32>
u32 m_dirty_gs_regs = 0;
int m_backed_up_ctx = 0;
std::vector<GSUploadQueue> m_draw_transfers;
std::optional<bool> m_primitive_covers_without_gaps;
GSVector4i m_r = {};
GSVector4i m_r_no_scissor = {};

static int s_n;
static int s_last_transfer_draw_n;
Expand Down Expand Up @@ -408,6 +411,7 @@ class GSState : public GSAlignedClass<32>

bool TrianglesAreQuads() const;
PRIM_OVERLAP PrimitiveOverlap();
bool PrimitiveCoversWithoutGaps();
GIFRegTEX0 GetTex0Layer(u32 lod);
};

Expand Down
100 changes: 0 additions & 100 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6732,106 +6732,6 @@ bool GSRendererHW::IsDiscardingDstAlpha() const
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFF000000u) == 0); // alpha isn't masked
}

bool GSRendererHW::PrimitiveCoversWithoutGaps()
{
if (m_primitive_covers_without_gaps.has_value())
return m_primitive_covers_without_gaps.value();

// Draw shouldn't be offset.
if (((m_r.eq32(GSVector4i::zero())).mask() & 0xff) != 0xff)
{
m_primitive_covers_without_gaps = false;
return false;
}

if (m_vt.m_primclass == GS_POINT_CLASS)
{
m_primitive_covers_without_gaps = (m_vertex.next < 2);
return m_primitive_covers_without_gaps.value();
}
else if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
{
m_primitive_covers_without_gaps = (m_index.tail == 6 && TrianglesAreQuads());
return m_primitive_covers_without_gaps.value();
}
else if (m_vt.m_primclass != GS_SPRITE_CLASS)
{
m_primitive_covers_without_gaps = false;
return false;
}

// Simple case: one sprite.
if (m_index.tail == 2)
{
m_primitive_covers_without_gaps = true;
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;

// Horizontal Match.
if ((first_dpX >> 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 >> 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 || 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;
}

// Like PrimitiveCoversWithoutGaps but with texture coordinates.
bool GSRendererHW::TextureCoversWithoutGapsNotEqual()
{
Expand Down
5 changes: 0 additions & 5 deletions pcsx2/GS/Renderers/HW/GSRendererHW.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ class GSRendererHW : public GSRenderer
bool IsDiscardingDstColor();
bool IsDiscardingDstRGB();
bool IsDiscardingDstAlpha() const;
bool PrimitiveCoversWithoutGaps();
bool TextureCoversWithoutGapsNotEqual();

enum class CLUTDrawTestResult
Expand Down Expand Up @@ -123,9 +122,6 @@ class GSRendererHW : public GSRenderer
bool IsUsingCsInBlend();
bool IsUsingAsInBlend();

GSVector4i m_r = {};
GSVector4i m_r_no_scissor = {};

// We modify some of the context registers to optimize away unnecessary operations.
// Instead of messing with the real context, we copy them and use those instead.
struct HWCachedCtx
Expand Down Expand Up @@ -173,7 +169,6 @@ class GSRendererHW : public GSRenderer
u32 m_split_clear_pages = 0; // if zero, inactive
u32 m_split_clear_color = 0;

std::optional<bool> m_primitive_covers_without_gaps;
bool m_userhacks_tcoffset = false;
float m_userhacks_tcoffset_x = 0.0f;
float m_userhacks_tcoffset_y = 0.0f;
Expand Down

0 comments on commit c729a6f

Please sign in to comment.