mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-10-11 22:49:56 +00:00
GS: Add utility functions for vertices/quads.
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user