GS: Add utility functions for vertices/quads.

This commit is contained in:
TJnotJT
2026-04-11 08:16:04 +02:00
committed by lightningterror
parent ba8804ead6
commit 26bd916e37
3 changed files with 310 additions and 0 deletions
+250
View File
@@ -4540,6 +4540,256 @@ __forceinline bool GSState::EarlyDetectShuffle(u32 prim)
return false;
}
__fi GSVector4 GSState::GetXYWindow(const GSVertex& v)
{
return GSVector4(GetVertexXY(v) - m_context->scissor.xyof.xyxy()) / 16.0f;
}
template<bool fst>
__fi GSVector4 GSState::GetTexCoordsImpl(const GSVertex& v, float q)
{
if constexpr (fst)
{
return GSVector4(GetVertexUV(v)) / 16.0f;
}
else
{
const float tw = static_cast<float>(1 << m_context->TEX0.TW);
const float th = static_cast<float>(1 << m_context->TEX0.TH);
const GSVector4 tex_size(tw, th, tw, th);
return GSVector4(GetVertexST(v) / q * tex_size);
}
}
template<bool fst>
__fi GSVector4 GSState::GetTexCoordsImpl(const GSVertex& v)
{
return GetTexCoordsImpl<fst>(v, v.RGBAQ.Q);
}
__fi GSVector4 GSState::GetTexCoords(const GSVertex& v, float q)
{
if (PRIM->FST)
{
return GetTexCoordsImpl<true>(v, q);
}
else
{
return GetTexCoordsImpl<false>(v, q);
}
}
__fi GSVector4 GSState::GetTexCoords(const GSVertex& v)
{
return GetTexCoords(v, v.RGBAQ.Q);
}
template<u32 primclass, bool tme, bool fst>
bool GSState::GetQuadCornersImpl(const GSVertex* v, const u16* i, GSVertex& vout0, GSVertex& vout1)
{
static_assert(primclass == GS_SPRITE_CLASS || primclass == GS_TRIANGLE_CLASS);
if constexpr (primclass == GS_TRIANGLE_CLASS)
{
TriangleOrdering tri0;
TriangleOrdering tri1;
const u16* i0 = i + 0;
const u16* i1 = i + 3;
if (!AreTrianglesQuad<tme, fst>(v, i0, i1, &tri0, &tri1))
return false;
vout0 = v[i0[tri0.b]];
vout1 = v[i1[tri1.b]];
}
else
{
// primclass == GS_SPRITE_CLASS
vout0 = v[i[0]];
vout1 = v[i[1]];
}
return true;
}
template<u32 primclass>
void GSState::GetQuadBBoxWindowImpl(const GSVertex& v0, const GSVertex& v1, GSVector4& xyout)
{
const GSVector4 xy0 = GetXYWindow(v0);
const GSVector4 xy1 = GetXYWindow(v1);
xyout = xy0.min(xy1).xyzw(xy0.max(xy1));
}
template<u32 primclass, bool tme, bool fst>
void GSState::GetQuadBBoxWindowImpl(const GSVertex& v0, const GSVertex& v1, GSVector4& xyout, GSVector4& texout, bool keep_tex_order)
{
if constexpr (!tme)
{
GetQuadBBoxWindowImpl<primclass>(v0, v1, xyout);
return;
}
GSVector4 xy0 = GetXYWindow(v0);
GSVector4 xy1 = GetXYWindow(v1);
GSVector4 tex0 = GetTexCoordsImpl<fst>(v0, primclass == GS_SPRITE_CLASS ? v1.RGBAQ.Q : v0.RGBAQ.Q);
GSVector4 tex1 = GetTexCoordsImpl<fst>(v1, v1.RGBAQ.Q);
if (!keep_tex_order)
{
xyout = xy0.min(xy1).xyzw(xy0.max(xy1));
texout = tex0.min(tex1).xyzw(tex0.max(tex1));
}
else
{
xyout = xy0.xyzw(xy1);
texout = tex0.xyzw(tex1);
const int swap = (xy0 > xy1).mask();
if (swap & 1)
{
xyout = xyout.zyxw();
texout = texout.zyxw();
}
if (swap & 2)
{
xyout = xyout.xwzy();
texout = texout.xwzy();
}
}
}
#define GEN_TMPL_SELECT_1(func, ...) \
if (m_vt.m_primclass == GS_TRIANGLE_CLASS) \
{ \
func<GS_TRIANGLE_CLASS>(__VA_ARGS__); \
} \
else if (m_vt.m_primclass == GS_SPRITE_CLASS) \
{ \
func<GS_SPRITE_CLASS>(__VA_ARGS__); \
} \
else \
{ \
pxFail("Wrong prim class."); \
}
#define GEN_TMPL_SELECT_2(func, ...) \
if (m_vt.m_primclass == GS_TRIANGLE_CLASS) \
{ \
if (PRIM->TME) \
{ \
if (PRIM->FST) \
{ \
return func<GS_TRIANGLE_CLASS, true, true>(__VA_ARGS__); \
} \
else \
{ \
return func<GS_TRIANGLE_CLASS, true, false>(__VA_ARGS__); \
} \
} \
else \
{ \
return func<GS_TRIANGLE_CLASS>(__VA_ARGS__); \
} \
} \
else if (m_vt.m_primclass == GS_SPRITE_CLASS) \
{ \
if (PRIM->TME) \
{ \
if (PRIM->FST) \
{ \
return func<GS_SPRITE_CLASS, true, true>(__VA_ARGS__); \
} \
else \
{ \
return func<GS_SPRITE_CLASS, true, false>(__VA_ARGS__); \
} \
} \
else \
{ \
return func<GS_SPRITE_CLASS>(__VA_ARGS__); \
} \
} \
else \
{ \
pxFail("Wrong prim class."); \
}
bool GSState::GetQuadCorners(const GSVertex* v, const u16* i, GSVertex& vout0, GSVertex& vout1)
{
GEN_TMPL_SELECT_2(GetQuadCornersImpl, v, i, vout0, vout1);
return false;
}
void GSState::GetQuadBBoxWindow(const GSVertex& v0, const GSVertex& v1, GSVector4& xyout)
{
GEN_TMPL_SELECT_1(GetQuadBBoxWindowImpl, v0, v1, xyout);
}
void GSState::GetQuadBBoxWindow(const GSVertex& v0, const GSVertex& v1, GSVector4& xyout, GSVector4& texout, bool keep_tex_order)
{
GEN_TMPL_SELECT_2(GetQuadBBoxWindowImpl, v0, v1, xyout, texout, keep_tex_order);
}
#undef GEN_TMPL_SELECT_2
#undef GEN_TMPL_SELECT_1
void GSState::GetQuadRasterizedPoints(GSVector4& xy, GSVector4& tex, bool keep_order)
{
// Swap so that coordinates are top-left and bottom-right.
const int swap = (xy.xyxy() > xy.zwzw()).mask();
if (swap & 1)
{
xy = xy.zyxw();
tex = tex.zyxw();
}
if (swap & 2)
{
xy = xy.xwzy();
tex = tex.xwzy();
}
const GSVector4 grad = (tex.zwzw() - tex.xyxy()) / (xy.zwzw() - xy.xyxy());
// Round XY to contained pixels. Omit bottom-right pixels on the edge.
GSVector4 xy_round = xy.ceil().xyzw(xy.floor());
const GSVector4 bottom_right = GSVector4::zero().xyzw(xy == xy_round);
xy_round = xy_round.blend32(xy_round - GSVector4(1.0f), bottom_right);
// Interpolate texture coords.
tex += grad * (xy_round - xy);
xy = xy_round;
// Swap back to original order if needed.
if (keep_order)
{
if (swap & 1)
{
xy = xy.zyxw();
tex = tex.zyxw();
}
if (swap & 2)
{
xy = xy.xwzy();
tex = tex.xwzy();
}
}
}
void GSState::GetQuadRasterizedPoints(GSVector4& xy, bool keep_order)
{
GSVector4 tex_ignore;
GetQuadRasterizedPoints(xy, tex_ignore, keep_order);
}
__forceinline bool GSState::IsAutoFlushDraw(u32 prim, int& tex_layer)
{
if (!PRIM->TME || (GSConfig.UserHacks_AutoFlush == GSHWAutoFlushLevel::SpritesOnly && prim != GS_SPRITE))
+26
View File
@@ -211,6 +211,32 @@ protected:
void CalcAlphaMinMax(const int tex_min, const int tex_max);
void CorrectATEAlphaMinMax(const u32 atst, const int aref);
// Utility functions for getting position/texture coordinates.
GSVector4 GetXYWindow(const GSVertex& v);
template<bool fst>
GSVector4 GetTexCoordsImpl(const GSVertex& v, float q);
template<bool fst>
GSVector4 GetTexCoordsImpl(const GSVertex& v);
GSVector4 GetTexCoords(const GSVertex& v, float q);
GSVector4 GetTexCoords(const GSVertex& v);
// Utility functions to detect and get corners of quads.
template<u32 primclass, bool tme = false, bool fst = false>
static bool GetQuadCornersImpl(const GSVertex* v, const u16* i, GSVertex& vout0, GSVertex& vout1);
bool GetQuadCorners(const GSVertex* v, const u16* i, GSVertex& vout0, GSVertex& vout1);
// Utility functions to get window/texture coordinates of a quad.
template<u32 primclass>
void GetQuadBBoxWindowImpl(const GSVertex& v0, const GSVertex& v1, GSVector4& xyout);
template<u32 primclass, bool tme = false, bool fst = false>
void GetQuadBBoxWindowImpl(const GSVertex& v0, const GSVertex& v1, GSVector4& xyout, GSVector4& texout, bool keep_tex_order = true);
void GetQuadBBoxWindow(const GSVertex& v0, const GSVertex& v1, GSVector4& xyout);
void GetQuadBBoxWindow(const GSVertex& v0, const GSVertex& v1, GSVector4& xyout, GSVector4& texout, bool keep_tex_order = true);
// Adjusts a quad so that it contains exactly the centers of the pixels that the GS would rasterize.
static void GetQuadRasterizedPoints(GSVector4& xy, bool keep_order = true);
static void GetQuadRasterizedPoints(GSVector4& xy, GSVector4& tex, bool keep_order = true);
public:
enum EEGS_TransferType
{
+34
View File
@@ -44,3 +44,37 @@ struct alignas(32) GSVertexPT1
static_assert(sizeof(GSVertexPT1) == sizeof(GSVertex));
__forceinline_odr GSVector4i GetVertexXY(const GSVertex& v)
{
return GSVector4i(v.m[1]).upl16().xyxy();
}
__forceinline_odr GSVector4i GetVertexZ(const GSVertex& v)
{
return GSVector4i(v.m[1]).yyyy();
}
__forceinline_odr GSVector4i GetVertexUV(const GSVertex& v)
{
return GSVector4i(v.m[1]).uph16().xyxy();
}
__forceinline_odr GSVector4 GetVertexST(const GSVertex& v)
{
return GSVector4::cast(GSVector4i(v.m[0])).xyxy();
}
__forceinline_odr GSVector4i GetVertexRGBA(const GSVertex& v)
{
return GSVector4i(v.m[0]).uph8().upl16();
}
__forceinline_odr GSVector4 GetVertexQ(const GSVertex& v)
{
return GSVector4::cast(GSVector4i(v.m[0])).wwww();
}
__forceinline_odr GSVector4i GetVertexFOG(const GSVertex& v)
{
return GSVector4i(v.m[1]).wwww();
}