@@ -4540,6 +4540,256 @@ __forceinline bool GSState::EarlyDetectShuffle(u32 prim)
45404540 return false ;
45414541}
45424542
4543+ __fi GSVector4 GSState::GetXYWindow (const GSVertex& v)
4544+ {
4545+ return GSVector4 (GetVertexXY (v) - m_context->scissor .xyof .xyxy ()) / 16 .0f ;
4546+ }
4547+
4548+ template <bool fst>
4549+ __fi GSVector4 GSState::GetTexCoordsImpl (const GSVertex& v, float q)
4550+ {
4551+ if constexpr (fst)
4552+ {
4553+ return GSVector4 (GetVertexUV (v)) / 16 .0f ;
4554+ }
4555+ else
4556+ {
4557+ const float tw = static_cast <float >(1 << m_context->TEX0 .TW );
4558+ const float th = static_cast <float >(1 << m_context->TEX0 .TH );
4559+ const GSVector4 tex_size (tw, th, tw, th);
4560+ return GSVector4 (GetVertexST (v) / q * tex_size);
4561+ }
4562+ }
4563+
4564+ template <bool fst>
4565+ __fi GSVector4 GSState::GetTexCoordsImpl (const GSVertex& v)
4566+ {
4567+ return GetTexCoordsImpl<fst>(v, v.RGBAQ .Q );
4568+ }
4569+
4570+ __fi GSVector4 GSState::GetTexCoords (const GSVertex& v, float q)
4571+ {
4572+ if (PRIM->FST )
4573+ {
4574+ return GetTexCoordsImpl<true >(v, q);
4575+ }
4576+ else
4577+ {
4578+ return GetTexCoordsImpl<false >(v, q);
4579+ }
4580+ }
4581+
4582+ __fi GSVector4 GSState::GetTexCoords (const GSVertex& v)
4583+ {
4584+ return GetTexCoords (v, v.RGBAQ .Q );
4585+ }
4586+
4587+ template <u32 primclass, bool tme, bool fst>
4588+ bool GSState::GetQuadCornersImpl (const GSVertex* v, const u16 * i, GSVertex& vout0, GSVertex& vout1)
4589+ {
4590+ static_assert (primclass == GS_SPRITE_CLASS || primclass == GS_TRIANGLE_CLASS);
4591+
4592+ if constexpr (primclass == GS_TRIANGLE_CLASS)
4593+ {
4594+ TriangleOrdering tri0;
4595+ TriangleOrdering tri1;
4596+
4597+ const u16 * i0 = i + 0 ;
4598+ const u16 * i1 = i + 3 ;
4599+
4600+ if (!AreTrianglesQuad<tme, fst>(v, i0, i1, &tri0, &tri1))
4601+ return false ;
4602+
4603+ vout0 = v[i0[tri0.b ]];
4604+ vout1 = v[i1[tri1.b ]];
4605+ }
4606+ else
4607+ {
4608+ // primclass == GS_SPRITE_CLASS
4609+ vout0 = v[i[0 ]];
4610+ vout1 = v[i[1 ]];
4611+ }
4612+
4613+ return true ;
4614+ }
4615+
4616+ template <u32 primclass>
4617+ void GSState::GetQuadBBoxWindowImpl (const GSVertex& v0, const GSVertex& v1, GSVector4& xyout)
4618+ {
4619+ const GSVector4 xy0 = GetXYWindow (v0);
4620+ const GSVector4 xy1 = GetXYWindow (v1);
4621+
4622+ xyout = xy0.min (xy1).xyzw (xy0.max (xy1));
4623+ }
4624+
4625+ template <u32 primclass, bool tme, bool fst>
4626+ void GSState::GetQuadBBoxWindowImpl (const GSVertex& v0, const GSVertex& v1, GSVector4& xyout, GSVector4& texout, bool keep_tex_order)
4627+ {
4628+ if constexpr (!tme)
4629+ {
4630+ GetQuadBBoxWindowImpl<primclass>(v0, v1, xyout);
4631+ return ;
4632+ }
4633+
4634+ GSVector4 xy0 = GetXYWindow (v0);
4635+ GSVector4 xy1 = GetXYWindow (v1);
4636+ GSVector4 tex0 = GetTexCoordsImpl<fst>(v0, primclass == GS_SPRITE_CLASS ? v1.RGBAQ .Q : v0.RGBAQ .Q );
4637+ GSVector4 tex1 = GetTexCoordsImpl<fst>(v1, v1.RGBAQ .Q );
4638+
4639+ if (!keep_tex_order)
4640+ {
4641+ xyout = xy0.min (xy1).xyzw (xy0.max (xy1));
4642+ texout = tex0.min (tex1).xyzw (tex0.max (tex1));
4643+ }
4644+ else
4645+ {
4646+ xyout = xy0.xyzw (xy1);
4647+ texout = tex0.xyzw (tex1);
4648+
4649+ const int swap = (xy0 > xy1).mask ();
4650+
4651+ if (swap & 1 )
4652+ {
4653+ xyout = xyout.zyxw ();
4654+ texout = texout.zyxw ();
4655+ }
4656+
4657+ if (swap & 2 )
4658+ {
4659+ xyout = xyout.xwzy ();
4660+ texout = texout.xwzy ();
4661+ }
4662+ }
4663+ }
4664+
4665+ #define GEN_TMPL_SELECT_1 (func, ...) \
4666+ if (m_vt.m_primclass == GS_TRIANGLE_CLASS) \
4667+ { \
4668+ func<GS_TRIANGLE_CLASS>(__VA_ARGS__); \
4669+ } \
4670+ else if (m_vt.m_primclass == GS_SPRITE_CLASS) \
4671+ { \
4672+ func<GS_SPRITE_CLASS>(__VA_ARGS__); \
4673+ } \
4674+ else \
4675+ { \
4676+ pxFail (" Wrong prim class." ); \
4677+ }
4678+
4679+
4680+ #define GEN_TMPL_SELECT_2 (func, ...) \
4681+ if (m_vt.m_primclass == GS_TRIANGLE_CLASS) \
4682+ { \
4683+ if (PRIM->TME ) \
4684+ { \
4685+ if (PRIM->FST ) \
4686+ { \
4687+ return func<GS_TRIANGLE_CLASS, true , true >(__VA_ARGS__); \
4688+ } \
4689+ else \
4690+ { \
4691+ return func<GS_TRIANGLE_CLASS, true , false >(__VA_ARGS__); \
4692+ } \
4693+ } \
4694+ else \
4695+ { \
4696+ return func<GS_TRIANGLE_CLASS>(__VA_ARGS__); \
4697+ } \
4698+ } \
4699+ else if (m_vt.m_primclass == GS_SPRITE_CLASS) \
4700+ { \
4701+ if (PRIM->TME ) \
4702+ { \
4703+ if (PRIM->FST ) \
4704+ { \
4705+ return func<GS_SPRITE_CLASS, true , true >(__VA_ARGS__); \
4706+ } \
4707+ else \
4708+ { \
4709+ return func<GS_SPRITE_CLASS, true , false >(__VA_ARGS__); \
4710+ } \
4711+ } \
4712+ else \
4713+ { \
4714+ return func<GS_SPRITE_CLASS>(__VA_ARGS__); \
4715+ } \
4716+ } \
4717+ else \
4718+ { \
4719+ pxFail (" Wrong prim class." ); \
4720+ }
4721+
4722+ bool GSState::GetQuadCorners (const GSVertex* v, const u16 * i, GSVertex& vout0, GSVertex& vout1)
4723+ {
4724+ GEN_TMPL_SELECT_2 (GetQuadCornersImpl, v, i, vout0, vout1);
4725+ return false ;
4726+ }
4727+
4728+ void GSState::GetQuadBBoxWindow (const GSVertex& v0, const GSVertex& v1, GSVector4& xyout)
4729+ {
4730+ GEN_TMPL_SELECT_1 (GetQuadBBoxWindowImpl, v0, v1, xyout);
4731+ }
4732+
4733+ void GSState::GetQuadBBoxWindow (const GSVertex& v0, const GSVertex& v1, GSVector4& xyout, GSVector4& texout, bool keep_tex_order)
4734+ {
4735+ GEN_TMPL_SELECT_2 (GetQuadBBoxWindowImpl, v0, v1, xyout, texout, keep_tex_order);
4736+ }
4737+
4738+ #undef GEN_TMPL_SELECT_2
4739+ #undef GEN_TMPL_SELECT_1
4740+
4741+ void GSState::GetQuadRasterizedPoints (GSVector4& xy, GSVector4& tex, bool keep_order)
4742+ {
4743+ // Swap so that coordinates are top-left and bottom-right.
4744+ const int swap = (xy.xyxy () > xy.zwzw ()).mask ();
4745+
4746+ if (swap & 1 )
4747+ {
4748+ xy = xy.zyxw ();
4749+ tex = tex.zyxw ();
4750+ }
4751+
4752+ if (swap & 2 )
4753+ {
4754+ xy = xy.xwzy ();
4755+ tex = tex.xwzy ();
4756+ }
4757+
4758+ const GSVector4 grad = (tex.zwzw () - tex.xyxy ()) / (xy.zwzw () - xy.xyxy ());
4759+
4760+ // Round XY to contained pixels. Omit bottom-right pixels on the edge.
4761+ GSVector4 xy_round = xy.ceil ().xyzw (xy.floor ());
4762+ const GSVector4 bottom_right = GSVector4::zero ().xyzw (xy == xy_round);
4763+ xy_round = xy_round.blend32 (xy_round - GSVector4 (1 .0f ), bottom_right);
4764+
4765+ // Interpolate texture coords.
4766+ tex += grad * (xy_round - xy);
4767+
4768+ xy = xy_round;
4769+
4770+ // Swap back to original order if needed.
4771+ if (keep_order)
4772+ {
4773+ if (swap & 1 )
4774+ {
4775+ xy = xy.zyxw ();
4776+ tex = tex.zyxw ();
4777+ }
4778+
4779+ if (swap & 2 )
4780+ {
4781+ xy = xy.xwzy ();
4782+ tex = tex.xwzy ();
4783+ }
4784+ }
4785+ }
4786+
4787+ void GSState::GetQuadRasterizedPoints (GSVector4& xy, bool keep_order)
4788+ {
4789+ GSVector4 tex_ignore;
4790+ GetQuadRasterizedPoints (xy, tex_ignore, keep_order);
4791+ }
4792+
45434793__forceinline bool GSState::IsAutoFlushDraw (u32 prim, int & tex_layer)
45444794{
45454795 if (!PRIM->TME || (GSConfig.UserHacks_AutoFlush == GSHWAutoFlushLevel::SpritesOnly && prim != GS_SPRITE))
0 commit comments