diff --git a/src/common-tests/rectangle_tests.cpp b/src/common-tests/rectangle_tests.cpp index 803938684..3ccb7ea3f 100644 --- a/src/common-tests/rectangle_tests.cpp +++ b/src/common-tests/rectangle_tests.cpp @@ -78,3 +78,59 @@ TEST(Rectangle, RelationalOperators) ASSERT_FALSE(r1.eq(r2)); } +TEST(Rectangle, ValidRectangles) +{ + static constexpr GSVector4i cases[] = { + GSVector4i::cxpr(1, 2, 3, 4), + GSVector4i::cxpr(-5, -10, -1, -2), + GSVector4i::cxpr(0, 0, 1, 1), + GSVector4i::cxpr(100, 200, 300, 400), + GSVector4i::cxpr(-1000, -2000, 500, 600), + GSVector4i::cxpr(5, 10, 6, 12), + GSVector4i::cxpr(-10, -20, -5, -15), + GSVector4i::cxpr(-5, 0, 5, 10), + GSVector4i::cxpr(-100, -200, 100, 200), + GSVector4i::cxpr(-1, -2, 0, 1), + }; + + for (GSVector4i tcase : cases) + { + ASSERT_TRUE(tcase.rvalid()); + ASSERT_FALSE(tcase.rempty()); + } +} + +TEST(Rectangle, InvalidRectangles) +{ + static constexpr GSVector4i cases[] = { + // left < right but not top < bottom + GSVector4i::cxpr(1, 4, 3, 2), + GSVector4i::cxpr(-5, -2, -1, -10), + GSVector4i::cxpr(0, 1, 1, 0), + GSVector4i::cxpr(100, 400, 300, 200), + GSVector4i::cxpr(-1000, 600, 500, -2000), + GSVector4i::cxpr(5, 12, 6, 10), + GSVector4i::cxpr(-10, -15, -5, -20), + GSVector4i::cxpr(-5, 10, 5, 0), + GSVector4i::cxpr(-100, 200, 100, -200), + GSVector4i::cxpr(-1, 1, 0, -2), + + // not left < right but top < bottom + GSVector4i::cxpr(3, 2, 1, 4), + GSVector4i::cxpr(-1, -10, -5, -2), + GSVector4i::cxpr(1, 0, 0, 1), + GSVector4i::cxpr(300, 200, 100, 400), + GSVector4i::cxpr(500, -2000, -1000, 600), + GSVector4i::cxpr(6, 10, 5, 12), + GSVector4i::cxpr(-5, -20, -10, -15), + GSVector4i::cxpr(5, 0, -5, 10), + GSVector4i::cxpr(100, -200, -100, 200), + GSVector4i::cxpr(0, -2, -1, 1), + }; + + for (GSVector4i tcase : cases) + { + ASSERT_FALSE(tcase.rvalid()); + ASSERT_TRUE(tcase.rempty()); + } +} diff --git a/src/common/gsvector_neon.h b/src/common/gsvector_neon.h index c77a1f529..dd52f8fc9 100644 --- a/src/common/gsvector_neon.h +++ b/src/common/gsvector_neon.h @@ -1171,17 +1171,21 @@ public: ALWAYS_INLINE bool rempty() const { -#ifdef CPU_ARCH_ARM64 - return (vminv_u32(vreinterpret_u32_s32(vget_low_s32(lt32(zwzw())))) == 0); -#else - return (vget_lane_u64(vreinterpret_u64_u32(vreinterpret_u32_s32(vget_low_s32(lt32(zwzw())))), 0) == 0); -#endif + // !any((x, y) < (z, w)) i.e. !not_empty + return (vget_lane_u64(vreinterpret_u64_u32(vclt_s32(vget_low_s32(v4s), vget_high_s32(v4s))), 0) != + 0xFFFFFFFFFFFFFFFFULL); + } + + ALWAYS_INLINE bool rvalid() const + { + // !all((x, y) >= (z, w)) + return (vget_lane_u64(vreinterpret_u64_u32(vcge_s32(vget_low_s32(v4s), vget_high_s32(v4s))), 0) == 0); } ALWAYS_INLINE GSVector4i runion(const GSVector4i& a) const { return min_s32(a).upl64(max_s32(a).srl<8>()); } ALWAYS_INLINE GSVector4i rintersect(const GSVector4i& a) const { return sat_s32(a); } - ALWAYS_INLINE bool rintersects(const GSVector4i& v) const { return !rintersect(v).rempty(); } + ALWAYS_INLINE bool rintersects(const GSVector4i& v) const { return rintersect(v).rvalid(); } ALWAYS_INLINE bool rcontains(const GSVector4i& v) const { return rintersect(v).eq(v); } ALWAYS_INLINE u32 rgba32() const { return static_cast(ps32().pu16().extract32<0>()); } diff --git a/src/common/gsvector_nosimd.h b/src/common/gsvector_nosimd.h index 9c47424b3..71df7f28b 100644 --- a/src/common/gsvector_nosimd.h +++ b/src/common/gsvector_nosimd.h @@ -958,7 +958,8 @@ public: ALWAYS_INLINE s32 width() const { return right - left; } ALWAYS_INLINE s32 height() const { return bottom - top; } - ALWAYS_INLINE bool rempty() const { return lt32(zwzw()).mask() != 0x00ff; } + ALWAYS_INLINE bool rempty() const { return (lt32(zwzw()).mask() != 0x00ff); } + ALWAYS_INLINE bool rvalid() const { return ((ge32(zwzw()).mask() & 0xff) == 0); } GSVector4i runion(const GSVector4i& v) const { @@ -966,7 +967,7 @@ public: } ALWAYS_INLINE GSVector4i rintersect(const GSVector4i& v) const { return sat_s32(v); } - ALWAYS_INLINE bool rintersects(const GSVector4i& v) const { return !rintersect(v).rempty(); } + ALWAYS_INLINE bool rintersects(const GSVector4i& v) const { return rintersect(v).rvalid(); } ALWAYS_INLINE bool rcontains(const GSVector4i& v) const { return rintersect(v).eq(v); } ALWAYS_INLINE u32 rgba32() const { return static_cast(ps32().pu16().extract32<0>()); } diff --git a/src/common/gsvector_sse.h b/src/common/gsvector_sse.h index 5dc49a76d..0b875c6fc 100644 --- a/src/common/gsvector_sse.h +++ b/src/common/gsvector_sse.h @@ -1071,12 +1071,13 @@ public: ALWAYS_INLINE s32 width() const { return right - left; } ALWAYS_INLINE s32 height() const { return bottom - top; } - ALWAYS_INLINE bool rempty() const { return lt32(zwzw()).mask() != 0x00ff; } + ALWAYS_INLINE bool rempty() const { return (lt32(zwzw()).mask() != 0x00ff); } + ALWAYS_INLINE bool rvalid() const { return ((ge32(zwzw()).mask() & 0xff) == 0); } ALWAYS_INLINE GSVector4i runion(const GSVector4i& v) const { return min_s32(v).blend32<0xc>(max_s32(v)); } ALWAYS_INLINE GSVector4i rintersect(const GSVector4i& v) const { return sat_s32(v); } - ALWAYS_INLINE bool rintersects(const GSVector4i& v) const { return !rintersect(v).rempty(); } + ALWAYS_INLINE bool rintersects(const GSVector4i& v) const { return rintersect(v).rvalid(); } ALWAYS_INLINE bool rcontains(const GSVector4i& v) const { return rintersect(v).eq(v); } ALWAYS_INLINE u32 rgba32() const { return static_cast(ps32().pu16().extract32<0>()); }