@@ -235,6 +235,180 @@ GSRendererType GSUtil::GetPreferredRenderer()
235235 return preferred_renderer;
236236}
237237
238+ // Helper struct for IsTriangleRight and AreTrianglesRight
239+ struct ComparisonResult
240+ {
241+ u8 value;
242+ u8 FinalCmp () const { return value & 3 ; }
243+ constexpr ComparisonResult (u8 final_cmp, u8 final_order)
244+ : value(final_cmp | (final_order << 2 ))
245+ {
246+ }
247+ GSUtil::TriangleOrdering FinalOrder () const
248+ {
249+ struct alignas (2 ) TriangleOrderingBC
250+ {
251+ u8 b;
252+ u8 c;
253+ };
254+ alignas (16 ) static constexpr TriangleOrderingBC order_lut[6 ] =
255+ {
256+ TriangleOrderingBC{/* a=0,*/ 1 , 2 },
257+ TriangleOrderingBC{/* a=0,*/ 2 , 1 },
258+ TriangleOrderingBC{/* a=1,*/ 0 , 2 },
259+ TriangleOrderingBC{/* a=1,*/ 2 , 0 },
260+ TriangleOrderingBC{/* a=2,*/ 0 , 1 },
261+ TriangleOrderingBC{/* a=2,*/ 1 , 0 },
262+ };
263+ u32 order = static_cast <u32 >(value) >> 2 ;
264+ TriangleOrderingBC bc = order_lut[order];
265+ return {order >> 1 , bc.b , bc.c };
266+ }
267+ };
268+
269+ // Helper table for IsTriangleRight/AreTrianglesRight functions
270+ static constexpr ComparisonResult comparison_lut[16 ] =
271+ {
272+ ComparisonResult (0 , 0 ), // 0000 => None equal, no sprite possible
273+ ComparisonResult (2 , 0 ), // 0001 => x0 = x1, requires y1 = y2
274+ ComparisonResult (1 , 5 ), // 0010 => y0 = y1, requires x1 = x2
275+ ComparisonResult (2 , 0 ), // 0011 => x0 = x1, y0 = y1, (no area) requires x1 = x2 or y1 = y2
276+ ComparisonResult (2 , 1 ), // 0100 => x0 = x2, requires y1 = y2
277+ ComparisonResult (2 , 0 ), // 0101 => x0 = x1, x0 = x2, (no area) requires y1 = y2
278+ ComparisonResult (0 , 4 ), // 0110 => y0 = y1, x0 = x2, requires nothing
279+ ComparisonResult (0 , 4 ), // 0111 => x0 = y1, y0 = y1, x0 = x2, (no area) requires nothing
280+ ComparisonResult (1 , 3 ), // 1000 => y0 = y2, requires x1 = x2
281+ ComparisonResult (0 , 2 ), // 1001 => x0 = x1, y0 = y2, requires nothing
282+ ComparisonResult (1 , 3 ), // 1010 => y0 = y1, y0 = y2, (no area) requires x1 = x2
283+ ComparisonResult (0 , 2 ), // 1011 => x0 = x1, y0 = y1, y0 = y2, (unlikely) requires nothing
284+ ComparisonResult (2 , 1 ), // 1100 => x0 = x2, y0 = y2, (no area) requires x1 = x2 or y1 = y2
285+ ComparisonResult (0 , 2 ), // 1101 => x0 = x1, x0 = x2, y0 = y2, (no area) requires nothing
286+ ComparisonResult (0 , 4 ), // 1110 => y0 = y1, x0 = x2, y0 = y2, (no area) requires nothing
287+ ComparisonResult (0 , 2 ), // 1111 => x0 = x1, y0 = y1, x0 = x2, y0 = y2, (no area) requires nothing
288+ };
289+
290+ template <u32 tme, u32 fst>
291+ bool GSUtil::AreTrianglesRight (const GSVertex* RESTRICT vin, const u16 * index0, const u16 * index1,
292+ TriangleOrdering* out_triangle0, TriangleOrdering* out_triangle1)
293+ {
294+ GSVector4i mask;
295+ if (tme && fst)
296+ {
297+ // Compare xy and uv together
298+ mask = GSVector4i::cxpr8 (
299+ (s8)0 , (s8)1 , (s8)8 , (s8)9 ,
300+ (s8)2 , (s8)3 , (s8)10 , (s8)11 ,
301+ (s8)0 , (s8)1 , (s8)8 , (s8)9 ,
302+ (s8)2 , (s8)3 , (s8)10 , (s8)11 );
303+ }
304+ else
305+ {
306+ // ignore uv, compare st instead later
307+ mask = GSVector4i::cxpr8 (
308+ (s8)0 , (s8)1 , (s8)0x80 , (s8)0x80 ,
309+ (s8)2 , (s8)3 , (s8)0x80 , (s8)0x80 ,
310+ (s8)0 , (s8)1 , (s8)0x80 , (s8)0x80 ,
311+ (s8)2 , (s8)3 , (s8)0x80 , (s8)0x80 );
312+ }
313+ GSVector4i xy0 = GSVector4i (vin[index0[0 ]].m [1 ]).shuffle8 (mask); // Triangle 0 vertex 0
314+ GSVector4i xy1 = GSVector4i (vin[index0[1 ]].m [1 ]).shuffle8 (mask); // Triangle 0 vertex 1
315+ GSVector4i xy2 = GSVector4i (vin[index0[2 ]].m [1 ]).shuffle8 (mask); // Triangle 0 vertex 2
316+ GSVector4i xy3 = GSVector4i (vin[index1[0 ]].m [1 ]).shuffle8 (mask); // Triangle 1 vertex 0
317+ GSVector4i xy4 = GSVector4i (vin[index1[1 ]].m [1 ]).shuffle8 (mask); // Triangle 1 vertex 1
318+ GSVector4i xy5 = GSVector4i (vin[index1[2 ]].m [1 ]).shuffle8 (mask); // Triangle 1 vertex 2
319+ GSVector4i vcmp0 = xy0.eq32 (xy1.upl64 (xy2));
320+ GSVector4i vcmp1 = xy3.eq32 (xy4.upl64 (xy5));
321+ GSVector4i vcmp2 = xy1.upl64 (xy4).eq32 (xy2.upl64 (xy5));
322+ if (tme && !fst)
323+ {
324+ // do the st comparisons
325+ GSVector4 st0 = GSVector4::cast (GSVector4i (vin[index0[0 ]].m [0 ]));
326+ GSVector4 st1 = GSVector4::cast (GSVector4i (vin[index0[1 ]].m [0 ]));
327+ GSVector4 st2 = GSVector4::cast (GSVector4i (vin[index0[2 ]].m [0 ]));
328+ GSVector4 st3 = GSVector4::cast (GSVector4i (vin[index1[0 ]].m [0 ]));
329+ GSVector4 st4 = GSVector4::cast (GSVector4i (vin[index1[1 ]].m [0 ]));
330+ GSVector4 st5 = GSVector4::cast (GSVector4i (vin[index1[2 ]].m [0 ]));
331+
332+ vcmp0 = vcmp0 & GSVector4i::cast (st0.xyxy () == st1.upld (st2));
333+ vcmp1 = vcmp1 & GSVector4i::cast (st3.xyxy () == st4.upld (st5));
334+ vcmp2 = vcmp2 & GSVector4i::cast (st1.upld (st4) == st2.upld (st5));
335+ }
336+ int cmp0 = GSVector4::cast (vcmp0).mask ();
337+ int cmp1 = GSVector4::cast (vcmp1).mask ();
338+ int cmp2 = GSVector4::cast (vcmp2).mask ();
339+ if (!cmp0 || !cmp1) // Either triangle 0 or triangle 1 isn't a right triangle
340+ return false ;
341+ ComparisonResult triangle0cmp = comparison_lut[cmp0];
342+ ComparisonResult triangle1cmp = comparison_lut[cmp1];
343+ int required_cmp2 = triangle0cmp.FinalCmp () | (triangle1cmp.FinalCmp () << 2 );
344+ if ((cmp2 & required_cmp2) != required_cmp2)
345+ return false ;
346+ // Both t0 and t1 are right triangles!
347+ *out_triangle0 = triangle0cmp.FinalOrder ();
348+ *out_triangle1 = triangle1cmp.FinalOrder ();
349+ return true ;
350+ }
351+
352+ template <u32 tme, u32 fst>
353+ bool GSUtil::IsTriangleRight (const GSVertex* RESTRICT vin, const u16 * index, TriangleOrdering* out_triangle)
354+ {
355+ GSVector4i mask;
356+ if (tme && fst)
357+ {
358+ // Compare xy and uv together
359+ mask = GSVector4i::cxpr8 (
360+ (s8)0 , (s8)1 , (s8) 8 , (s8) 9 ,
361+ (s8)2 , (s8)3 , (s8)10 , (s8)11 ,
362+ (s8)0 , (s8)1 , (s8) 8 , (s8) 9 ,
363+ (s8)2 , (s8)3 , (s8)10 , (s8)11 );
364+ }
365+ else
366+ {
367+ // ignore uv, compare st instead later
368+ mask = GSVector4i::cxpr8 (
369+ (s8)0 , (s8)1 , (s8)0x80 , (s8)0x80 ,
370+ (s8)2 , (s8)3 , (s8)0x80 , (s8)0x80 ,
371+ (s8)0 , (s8)1 , (s8)0x80 , (s8)0x80 ,
372+ (s8)2 , (s8)3 , (s8)0x80 , (s8)0x80 );
373+ }
374+ GSVector4i xy0 = GSVector4i (vin[index[0 ]].m [1 ]).shuffle8 (mask); // Triangle 0 vertex 0
375+ GSVector4i xy1 = GSVector4i (vin[index[1 ]].m [1 ]).shuffle8 (mask); // Triangle 0 vertex 1
376+ GSVector4i xy2 = GSVector4i (vin[index[2 ]].m [1 ]).shuffle8 (mask); // Triangle 0 vertex 2
377+ GSVector4i vcmp0 = xy0.eq32 (xy1.upl64 (xy2));
378+ GSVector4i vcmp1 = xy1.eq32 (xy2); // ignore top 64 bits
379+ if (tme && !fst)
380+ {
381+ // do the st comparisons
382+ GSVector4 st0 = GSVector4::cast (GSVector4i (vin[index[0 ]].m [0 ]));
383+ GSVector4 st1 = GSVector4::cast (GSVector4i (vin[index[1 ]].m [0 ]));
384+ GSVector4 st2 = GSVector4::cast (GSVector4i (vin[index[2 ]].m [0 ]));
385+
386+ vcmp0 = vcmp0 & GSVector4i::cast (st0.xyxy () == st1.upld (st2));
387+ vcmp1 = vcmp1 & GSVector4i::cast (st1 == st2); // ignore top 64 bits
388+ }
389+ int cmp0 = GSVector4::cast (vcmp0).mask ();
390+ int cmp1 = GSVector4::cast (vcmp1).mask () & 0x3 ;
391+ if (!cmp0) // Either triangle 0 or triangle 1 isn't a right triangle
392+ return false ;
393+ ComparisonResult trianglecmp = comparison_lut[cmp0];
394+ int required_cmp1 = trianglecmp.FinalCmp ();
395+ if (cmp1 != required_cmp1)
396+ return false ;
397+ // Both t0 and t1 are right triangles!
398+ *out_triangle = trianglecmp.FinalOrder ();
399+ return true ;
400+ }
401+
402+ // Instantiate the template functions for Is/AreTrianglesRight
403+ template bool GSUtil::AreTrianglesRight<0 , 0 >(const GSVertex* RESTRICT, const u16 *, const u16 *, TriangleOrdering*, TriangleOrdering*);
404+ template bool GSUtil::AreTrianglesRight<1 , 0 >(const GSVertex* RESTRICT, const u16 *, const u16 *, TriangleOrdering*, TriangleOrdering*);
405+ template bool GSUtil::AreTrianglesRight<0 , 1 >(const GSVertex* RESTRICT, const u16 *, const u16 *, TriangleOrdering*, TriangleOrdering*);
406+ template bool GSUtil::AreTrianglesRight<1 , 1 >(const GSVertex* RESTRICT, const u16 *, const u16 *, TriangleOrdering*, TriangleOrdering*);
407+ template bool GSUtil::IsTriangleRight<0 , 0 >(const GSVertex* RESTRICT, const u16 *, TriangleOrdering*);
408+ template bool GSUtil::IsTriangleRight<1 , 0 >(const GSVertex* RESTRICT, const u16 *, TriangleOrdering*);
409+ template bool GSUtil::IsTriangleRight<0 , 1 >(const GSVertex* RESTRICT, const u16 *, TriangleOrdering*);
410+ template bool GSUtil::IsTriangleRight<1 , 1 >(const GSVertex* RESTRICT, const u16 *, TriangleOrdering*);
411+
238412const char * GSUtil::GetPSMName (int psm)
239413{
240414 switch (psm)
0 commit comments