Path: blob/master/src/common-tests/gsvector_tests.cpp
7322 views
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <[email protected]>1// SPDX-License-Identifier: CC-BY-NC-ND-4.023#include "common/gsvector.h"45#include "gtest/gtest.h"67static constexpr s8 s8t(int v)8{9return static_cast<s8>(static_cast<s32>(v));10}1112static constexpr s16 s16t(int v)13{14return static_cast<s16>(static_cast<s32>(v));15}1617// GSVector2i Tests18TEST(GSVector2iTest, Construction)19{20// Default constructor21[[maybe_unused]] GSVector2i v1;22// Values are uninitialized, so we don't test them2324// Single value constructor25GSVector2i v2(42);26EXPECT_EQ(v2.x, 42);27EXPECT_EQ(v2.y, 42);2829// Two value constructor30GSVector2i v3(10, 20);31EXPECT_EQ(v3.x, 10);32EXPECT_EQ(v3.y, 20);3334// 16-bit constructor35GSVector2i v4(s16(1), s16(2), s16(3), s16(4));36EXPECT_EQ(v4.S16[0], 1);37EXPECT_EQ(v4.S16[1], 2);38EXPECT_EQ(v4.S16[2], 3);39EXPECT_EQ(v4.S16[3], 4);4041// 8-bit constructor42GSVector2i v5(s8t(1), s8t(2), s8t(3), s8t(4), s8t(5), s8t(6), s8t(7), s8t(8));43for (int i = 0; i < 8; i++)44{45EXPECT_EQ(v5.S8[i], i + 1);46}4748// Copy constructor49GSVector2i v6(v3);50EXPECT_EQ(v6.x, 10);51EXPECT_EQ(v6.y, 20);52}5354TEST(GSVector2iTest, ConstexprCreation)55{56constexpr auto v1 = GSVector2i::cxpr(5, 10);57EXPECT_EQ(v1.x, 5);58EXPECT_EQ(v1.y, 10);5960constexpr auto v2 = GSVector2i::cxpr(7);61EXPECT_EQ(v2.x, 7);62EXPECT_EQ(v2.y, 7);6364constexpr auto v3 = GSVector2i::cxpr16(s16(255));65for (int i = 0; i < 4; i++)66{67EXPECT_EQ(v3.S16[i], 255);68}69}7071TEST(GSVector2iTest, SaturationOperations)72{73GSVector2i v1(100, 200);74GSVector2i min_val(-50, -100);75GSVector2i max_val(150, 250);7677auto sat_result = v1.sat_s32(min_val, max_val);78EXPECT_EQ(sat_result.x, 100); // Within range79EXPECT_EQ(sat_result.y, 200); // Within range8081GSVector2i v2(300, -150);82auto sat_result2 = v2.sat_s32(min_val, max_val);83EXPECT_EQ(sat_result2.x, 150); // Clamped to max84EXPECT_EQ(sat_result2.y, -100); // Clamped to min85}8687TEST(GSVector2iTest, MinMaxVertical)88{89GSVector2i v1(10, 20);9091EXPECT_EQ(v1.minv_s32(), 10);92EXPECT_EQ(v1.maxv_s32(), 20);93EXPECT_EQ(v1.addv_s32(), 30);9495GSVector2i v2(s8t(0x50), s8t(0x40), s8t(0x30), s8t(0x20), s8t(0x80), s8t(0x70), s8t(0x60), s8t(0x10)); // 8-bit values96EXPECT_EQ(v2.minv_u8(), 0x10u);97EXPECT_EQ(v2.maxv_u8(), 0x80u);9899GSVector2i v3(s16t(0x1000), s16t(0x2000), s16t(0x3000), s16t(0x4000)); // 16-bit values100EXPECT_EQ(v3.minv_u16(), 0x1000u);101EXPECT_EQ(v3.maxv_u16(), 0x4000u);102}103104TEST(GSVector2iTest, ClampOperations)105{106// Test clamp8 which does pu16().upl8()107GSVector2i v1(300, 400, -100, 500); // Values that exceed 8-bit range108auto clamped = v1.clamp8();109// This should pack to 16-bit unsigned with saturation, then unpack low 8-bit110for (int i = 0; i < 8; i++)111{112EXPECT_GE(clamped.U8[i], 0);113EXPECT_LE(clamped.U8[i], 255);114}115}116117TEST(GSVector2iTest, BlendOperations)118{119GSVector2i v1(s8t(0x11), s8t(0x22), s8t(0x33), s8t(0x44), s8t(0x55), s8t(0x66), s8t(0x77), s8t(0x88));120GSVector2i v2(s8t(0xAA), s8t(0xBB), s8t(0xCC), s8t(0xDD), s8t(0xEE), s8t(0xFF), s8t(0x00), s8t(0x11));121GSVector2i mask(s8t(0x80), s8t(0x00), s8t(0x80), s8t(0x00), s8t(0x80), s8t(0x00), s8t(0x80),122s8t(0x00)); // Alternate selection123124auto blend_result = v1.blend8(v2, mask);125EXPECT_EQ(blend_result.U8[0], 0xAAu); // mask bit set, select from v2126EXPECT_EQ(blend_result.U8[1], 0x22u); // mask bit clear, select from v1127EXPECT_EQ(blend_result.U8[2], 0xCCu); // mask bit set, select from v2128EXPECT_EQ(blend_result.U8[3], 0x44u); // mask bit clear, select from v1129}130131TEST(GSVector2iTest, BlendTemplated)132{133GSVector2i v1(s16t(0x1111), s16t(0x2222), s16t(0x3333), s16t(0x4444));134GSVector2i v2(s16t(0xAAAA), s16t(0xBBBB), s16t(0xCCCC), s16t(0xDDDD));135136// Test blend16 with mask 0x5 (binary 0101) - select elements 0 and 2 from v2137auto blend16_result = v1.blend16<0x5>(v2);138EXPECT_EQ(blend16_result.U16[0], 0xAAAAu); // bit 0 set, select from v2139EXPECT_EQ(blend16_result.U16[1], 0x2222u); // bit 1 clear, select from v1140EXPECT_EQ(blend16_result.U16[2], 0xCCCCu); // bit 2 set, select from v2141EXPECT_EQ(blend16_result.U16[3], 0x4444u); // bit 3 clear, select from v1142143// Test blend32 with mask 0x1 - select element 0 from v2144auto blend32_result = v1.blend32<0x1>(v2);145EXPECT_EQ(blend32_result.U32[0], 0xBBBBAAAAu); // bit 0 set, select from v2146EXPECT_EQ(blend32_result.U32[1], 0x44443333u); // bit 1 clear, select from v1147}148149TEST(GSVector2iTest, ShuffleOperations)150{151GSVector2i v1(s8t(0x10), s8t(0x20), s8t(0x30), s8t(0x40), s8t(0x50), s8t(0x60), s8t(0x70), s8t(0x80));152GSVector2i shuffle_mask(s8t(0x00), s8t(0x02), s8t(0x04), s8t(0x06), s8t(0x80), s8t(0x81), s8t(0x82),153s8t(0x83)); // Mix indices and zero154155auto shuffled = v1.shuffle8(shuffle_mask);156EXPECT_EQ(shuffled.S8[0], s8t(0x10)); // Index 0157EXPECT_EQ(shuffled.S8[1], s8t(0x30)); // Index 2158EXPECT_EQ(shuffled.S8[2], s8t(0x50)); // Index 4159EXPECT_EQ(shuffled.S8[3], s8t(0x70)); // Index 6160EXPECT_EQ(shuffled.S8[4], s8t(0)); // High bit set, zero161EXPECT_EQ(shuffled.S8[5], s8t(0)); // High bit set, zero162}163164TEST(GSVector2iTest, PackingOperations)165{166// Test ps16 - pack signed 16-bit to signed 8-bit with saturation167GSVector2i v1(300, -200, 100, 400); // 16-bit values, some out of 8-bit range168auto packed_s = v1.ps16();169EXPECT_EQ(packed_s.S8[0], 127); // 300 saturated to max s8170EXPECT_EQ(packed_s.S8[1], -128); // -200 saturated to min s8171EXPECT_EQ(packed_s.S8[2], 100); // 100 within range172EXPECT_EQ(packed_s.S8[3], 127); // 400 saturated to max s8173174// Test pu16 - pack unsigned 16-bit to unsigned 8-bit with saturation175GSVector2i v2(100, 300, 50, 400);176auto packed_u = v2.pu16();177EXPECT_EQ(packed_u.U8[0], 100); // 100 within range178EXPECT_EQ(packed_u.U8[1], 255); // 300 saturated to max u8179EXPECT_EQ(packed_u.U8[2], 50); // 50 within range180EXPECT_EQ(packed_u.U8[3], 255); // 400 saturated to max u8181}182183TEST(GSVector2iTest, UnpackOperations)184{185GSVector2i v1(0x12, 0x34, 0x56, 0x78);186187auto upl8_result = v1.upl8();188EXPECT_EQ(upl8_result.U8[0], 0x12);189EXPECT_EQ(upl8_result.U8[1], 0);190EXPECT_EQ(upl8_result.U8[2], 0);191EXPECT_EQ(upl8_result.U8[3], 0);192EXPECT_EQ(upl8_result.U8[4], 0x34);193EXPECT_EQ(upl8_result.U8[5], 0);194EXPECT_EQ(upl8_result.U8[6], 0);195EXPECT_EQ(upl8_result.U8[7], 0);196197auto upl16_result = v1.upl16();198EXPECT_EQ(upl16_result.U16[0], 0x12);199EXPECT_EQ(upl16_result.U16[1], 0);200EXPECT_EQ(upl16_result.U16[2], 0x34);201EXPECT_EQ(upl16_result.U16[3], 0);202}203204TEST(GSVector2iTest, TypeConversions)205{206GSVector2i v1(0x12, 0x34, 0x56, 0x78);207208// Test u8to16209auto s8to16_result = v1.u8to16();210EXPECT_EQ(s8to16_result.S16[0], 0x12);211EXPECT_EQ(s8to16_result.S16[1], 0);212EXPECT_EQ(s8to16_result.S16[2], 0x34);213EXPECT_EQ(s8to16_result.S16[3], 0);214215// Test u8to32216auto u8to32_result = v1.u8to32();217EXPECT_EQ(u8to32_result.U32[0], 0x12u);218EXPECT_EQ(u8to32_result.U32[1], 0u);219}220221TEST(GSVector2iTest, ByteShifts)222{223GSVector2i v1(s8t(0x12), s8t(0x34), s8t(0x56), s8t(0x78), s8t(0x9A), s8t(0xBC), s8t(0xDE), s8t(0xF0));224225// Test srl<2> - shift right logical by 2 bytes226auto srl_result = v1.srl<2>();227EXPECT_EQ(srl_result.U8[0], 0x56u);228EXPECT_EQ(srl_result.U8[1], 0x78u);229EXPECT_EQ(srl_result.U8[2], 0x9Au);230EXPECT_EQ(srl_result.U8[3], 0xBCu);231EXPECT_EQ(srl_result.U8[4], 0xDEu);232EXPECT_EQ(srl_result.U8[5], 0xF0u);233EXPECT_EQ(srl_result.U8[6], 0u);234EXPECT_EQ(srl_result.U8[7], 0u);235236// Test sll<3> - shift left logical by 3 bytes237auto sll_result = v1.sll<3>();238EXPECT_EQ(sll_result.U8[0], 0u);239EXPECT_EQ(sll_result.U8[1], 0u);240EXPECT_EQ(sll_result.U8[2], 0u);241EXPECT_EQ(sll_result.U8[3], 0x12u);242EXPECT_EQ(sll_result.U8[4], 0x34u);243EXPECT_EQ(sll_result.U8[5], 0x56u);244EXPECT_EQ(sll_result.U8[6], 0x78u);245EXPECT_EQ(sll_result.U8[7], 0x9Au);246}247248TEST(GSVector2iTest, ArithmeticWith16BitElements)249{250GSVector2i v1(100, 200, 300, 400);251GSVector2i v2(50, 60, 70, 80);252253auto add16_result = v1.add16(v2);254EXPECT_EQ(add16_result.S16[0], 150);255EXPECT_EQ(add16_result.S16[1], 260);256EXPECT_EQ(add16_result.S16[2], 370);257EXPECT_EQ(add16_result.S16[3], 480);258259auto sub16_result = v1.sub16(v2);260EXPECT_EQ(sub16_result.S16[0], 50);261EXPECT_EQ(sub16_result.S16[1], 140);262EXPECT_EQ(sub16_result.S16[2], 230);263EXPECT_EQ(sub16_result.S16[3], 320);264265auto mul16_result = v1.mul16l(v2);266EXPECT_EQ(mul16_result.S16[0], 5000);267EXPECT_EQ(mul16_result.S16[1], 12000);268EXPECT_EQ(mul16_result.S16[2], 21000);269EXPECT_EQ(mul16_result.S16[3], 32000);270}271272TEST(GSVector2iTest, ArithmeticWith8BitElements)273{274GSVector2i v1(10, 20, 30, 40, 50, 60, 70, 80);275GSVector2i v2(5, 8, 12, 16, 20, 24, 28, 32);276277auto add8_result = v1.add8(v2);278for (int i = 0; i < 8; i++)279{280EXPECT_EQ(add8_result.S8[i], v1.S8[i] + v2.S8[i]);281}282283auto sub8_result = v1.sub8(v2);284for (int i = 0; i < 8; i++)285{286EXPECT_EQ(sub8_result.S8[i], v1.S8[i] - v2.S8[i]);287}288}289290TEST(GSVector2iTest, SaturatedArithmetic)291{292// Test signed saturation293GSVector2i v1(120, -120, 100, -100, 0, 0, 0, 0);294GSVector2i v2(50, -50, 60, -60, 0, 0, 0, 0);295296auto adds8_result = v1.adds8(v2);297EXPECT_EQ(adds8_result.S8[0], 127); // 120 + 50 = 170, saturated to 127298EXPECT_EQ(adds8_result.S8[1], -128); // -120 + (-50) = -170, saturated to -128299EXPECT_EQ(adds8_result.S8[2], 127); // 100 + 60 = 160, saturated to 127300EXPECT_EQ(adds8_result.S8[3], -128); // -100 + (-60) = -160, saturated to -128301302auto subs8_result = v1.subs8(v2);303EXPECT_EQ(subs8_result.S8[0], 70); // 120 - 50 = 70304EXPECT_EQ(subs8_result.S8[1], -70); // -120 - (-50) = -70305EXPECT_EQ(subs8_result.S8[2], 40); // 100 - 60 = 40306EXPECT_EQ(subs8_result.S8[3], -40); // -100 - (-60) = -40307}308309TEST(GSVector2iTest, UnsignedSaturatedArithmetic)310{311GSVector2i v1(s8t(200), s8t(100), s8t(150), s8t(50), s8t(0), s8t(0), s8t(0), s8t(0));312GSVector2i v2(s8t(80), s8t(120), s8t(30), s8t(70), s8t(0), s8t(0), s8t(0), s8t(0));313314auto addus8_result = v1.addus8(v2);315EXPECT_EQ(addus8_result.U8[0], 255); // 200 + 80 = 280, saturated to 255316EXPECT_EQ(addus8_result.U8[1], 220); // 100 + 120 = 220317EXPECT_EQ(addus8_result.U8[2], 180); // 150 + 30 = 180318EXPECT_EQ(addus8_result.U8[3], 120); // 50 + 70 = 120319320auto subus8_result = v1.subus8(v2);321EXPECT_EQ(subus8_result.U8[0], 120); // 200 - 80 = 120322EXPECT_EQ(subus8_result.U8[1], 0); // 100 - 120 = -20, saturated to 0323EXPECT_EQ(subus8_result.U8[2], 120); // 150 - 30 = 120324EXPECT_EQ(subus8_result.U8[3], 0); // 50 - 70 = -20, saturated to 0325}326327TEST(GSVector2iTest, AverageOperations)328{329GSVector2i v1(s8t(100), s8t(200), s8t(50), s8t(150), s8t(0), s8t(0), s8t(0), s8t(0));330GSVector2i v2(s8t(80), s8t(180), s8t(70), s8t(130), s8t(0), s8t(0), s8t(0), s8t(0));331332auto avg8_result = v1.avg8(v2);333EXPECT_EQ(avg8_result.U8[0], 90); // (100 + 80) / 2 = 90334EXPECT_EQ(avg8_result.U8[1], 190); // (200 + 180) / 2 = 190335EXPECT_EQ(avg8_result.U8[2], 60); // (50 + 70) / 2 = 60336EXPECT_EQ(avg8_result.U8[3], 140); // (150 + 130) / 2 = 140337338auto avg16_result = v1.avg16(v2);339EXPECT_EQ(avg16_result.U16[0], (51300 + 46160) / 2); // Average of packed 16-bit values340EXPECT_EQ(avg16_result.U16[1], (38450 + 33350) / 2);341}342343TEST(GSVector2iTest, ComparisonOperations)344{345GSVector2i v1(10, 20, 30, 40, 50, 60, 70, 80);346GSVector2i v2(5, 25, 30, 45, 55, 55, 75, 75);347348// Test eq8349auto eq8_result = v1.eq8(v2);350EXPECT_EQ(eq8_result.S8[0], 0); // 10 != 5351EXPECT_EQ(eq8_result.S8[1], 0); // 20 != 25352EXPECT_EQ(eq8_result.S8[2], -1); // 30 == 30353EXPECT_EQ(eq8_result.S8[3], 0); // 40 != 45354355// Test neq8356auto neq8_result = v1.neq8(v2);357EXPECT_EQ(neq8_result.S8[0], -1); // 10 != 5358EXPECT_EQ(neq8_result.S8[1], -1); // 20 != 25359EXPECT_EQ(neq8_result.S8[2], 0); // 30 == 30360EXPECT_EQ(neq8_result.S8[3], -1); // 40 != 45361362// Test gt8363auto gt8_result = v1.gt8(v2);364EXPECT_EQ(gt8_result.S8[0], -1); // 10 > 5365EXPECT_EQ(gt8_result.S8[1], 0); // 20 < 25366EXPECT_EQ(gt8_result.S8[2], 0); // 30 == 30367EXPECT_EQ(gt8_result.S8[3], 0); // 40 < 45368369// Test ge8370auto ge8_result = v1.ge8(v2);371EXPECT_EQ(ge8_result.S8[0], -1); // 10 >= 5372EXPECT_EQ(ge8_result.S8[1], 0); // 20 < 25373EXPECT_EQ(ge8_result.S8[2], -1); // 30 >= 30374EXPECT_EQ(ge8_result.S8[3], 0); // 40 < 45375376// Test lt8377auto lt8_result = v1.lt8(v2);378EXPECT_EQ(lt8_result.S8[0], 0); // 10 > 5379EXPECT_EQ(lt8_result.S8[1], -1); // 20 < 25380EXPECT_EQ(lt8_result.S8[2], 0); // 30 == 30381EXPECT_EQ(lt8_result.S8[3], -1); // 40 < 45382383// Test le8384auto le8_result = v1.le8(v2);385EXPECT_EQ(le8_result.S8[0], 0); // 10 > 5386EXPECT_EQ(le8_result.S8[1], -1); // 20 <= 25387EXPECT_EQ(le8_result.S8[2], -1); // 30 <= 30388EXPECT_EQ(le8_result.S8[3], -1); // 40 <= 45389}390391TEST(GSVector2iTest, MaskAndBooleanOperations)392{393GSVector2i v1(s8t(0x80), s8t(0x40), s8t(0x80), s8t(0x00), s8t(0x80), s8t(0x80), s8t(0x00), s8t(0x80));394395s32 mask_result = v1.mask();396// Mask should be formed from high bits of each byte397s32 expected_mask = 0x01 | 0x04 | 0x10 | 0x20 | 0x80; // Bits 0, 2, 4, 5, 7398EXPECT_EQ(mask_result & 0xB5, expected_mask & 0xB5); // Check set bits399400// Test alltrue and allfalse401GSVector2i all_ones;402all_ones.U64[0] = 0xFFFFFFFFFFFFFFFFULL;403EXPECT_TRUE(all_ones.alltrue());404EXPECT_FALSE(all_ones.allfalse());405406GSVector2i all_zeros;407all_zeros.U64[0] = 0;408EXPECT_FALSE(all_zeros.alltrue());409EXPECT_TRUE(all_zeros.allfalse());410}411412TEST(GSVector2iTest, InsertExtractOperations)413{414GSVector2i v1(0x12345678, 0x9ABCDEF0);415416// Test insert/extract 8-bit417auto v_insert8 = v1.insert8<0>(0x55);418EXPECT_EQ(v_insert8.extract8<0>(), 0x55);419EXPECT_EQ(v1.extract8<1>(), s8t(0x56));420421// Test insert/extract 16-bit422auto v_insert16 = v1.insert16<1>(0x1234);423EXPECT_EQ(v_insert16.extract16<1>(), 0x1234);424EXPECT_EQ(v1.extract16<0>(), static_cast<s16>(0x5678));425426// Test insert/extract 32-bit427auto v_insert32 = v1.insert32<0>(0xAABBCCDD);428EXPECT_EQ(v_insert32.extract32<0>(), static_cast<s32>(0xAABBCCDD));429EXPECT_EQ(v1.extract32<1>(), static_cast<s32>(0x9ABCDEF0));430}431432TEST(GSVector2iTest, LoadStoreOperations)433{434// Test load32435s32 value = 0x12345678;436auto loaded32 = GSVector2i::load32(&value);437EXPECT_EQ(loaded32.x, 0x12345678);438EXPECT_EQ(loaded32.y, 0);439440// Test set32441auto set32_result = GSVector2i::set32(0xAABBCCDD);442EXPECT_EQ(set32_result.x, static_cast<s32>(0xAABBCCDD));443EXPECT_EQ(set32_result.y, 0);444445// Test store32446s32 output_value;447GSVector2i::store32(&output_value, loaded32);448EXPECT_EQ(output_value, 0x12345678);449450// Test full load/store451s32 data[2] = {0x11111111, 0x22222222};452auto loaded = GSVector2i::load<true>(data);453EXPECT_EQ(loaded.S32[0], 0x11111111);454EXPECT_EQ(loaded.S32[1], 0x22222222);455456s32 output[2];457GSVector2i::store<true>(output, loaded);458EXPECT_EQ(output[0], 0x11111111);459EXPECT_EQ(output[1], 0x22222222);460}461462TEST(GSVector2iTest, BitwiseAssignmentOperations)463{464GSVector2i v1(0xF0F0F0F0, 0x0F0F0F0F);465GSVector2i v2(0xAAAAAAAA, 0x55555555);466467// Test &=468GSVector2i v_and = v1;469v_and &= v2;470EXPECT_EQ(v_and.U32[0], 0xA0A0A0A0u);471EXPECT_EQ(v_and.U32[1], 0x05050505u);472473// Test |=474GSVector2i v_or = v1;475v_or |= v2;476EXPECT_EQ(v_or.U32[0], 0xFAFAFAFAu);477EXPECT_EQ(v_or.U32[1], 0x5F5F5F5Fu);478479// Test ^=480GSVector2i v_xor = v1;481v_xor ^= v2;482EXPECT_EQ(v_xor.U32[0], 0x5A5A5A5Au);483EXPECT_EQ(v_xor.U32[1], 0x5A5A5A5Au);484}485486TEST(GSVector2iTest, BitwiseScalarOperations)487{488GSVector2i v1(0xF0F0F0F0, 0x0F0F0F0F);489s32 scalar = 0xAAAAAAAA;490491auto and_result = v1 & scalar;492EXPECT_EQ(and_result.U32[0], 0xA0A0A0A0u);493EXPECT_EQ(and_result.U32[1], 0x0A0A0A0Au);494495auto or_result = v1 | scalar;496EXPECT_EQ(or_result.U32[0], 0xFAFAFAFAu);497EXPECT_EQ(or_result.U32[1], 0xAFAFAFAFu);498499auto xor_result = v1 ^ scalar;500EXPECT_EQ(xor_result.U32[0], 0x5A5A5A5Au);501EXPECT_EQ(xor_result.U32[1], 0xA5A5A5A5u);502}503504TEST(GSVector2iTest, NotOperation)505{506GSVector2i v1(0xF0F0F0F0, 0x0F0F0F0F);507auto not_result = ~v1;508EXPECT_EQ(not_result.U32[0], 0x0F0F0F0Fu);509EXPECT_EQ(not_result.U32[1], 0xF0F0F0F0u);510}511512// GSVector2 Tests513TEST(GSVector2Test, Construction)514{515// Single value constructor516GSVector2 v1(3.14f);517EXPECT_FLOAT_EQ(v1.x, 3.14f);518EXPECT_FLOAT_EQ(v1.y, 3.14f);519520// Two value constructor (float)521GSVector2 v2(1.5f, 2.5f);522EXPECT_FLOAT_EQ(v2.x, 1.5f);523EXPECT_FLOAT_EQ(v2.y, 2.5f);524525// Two value constructor (int)526GSVector2 v3(10, 20);527EXPECT_FLOAT_EQ(v3.x, 10.0f);528EXPECT_FLOAT_EQ(v3.y, 20.0f);529530// Single int constructor531GSVector2 v4(42);532EXPECT_FLOAT_EQ(v4.x, 42.0f);533EXPECT_FLOAT_EQ(v4.y, 42.0f);534}535536TEST(GSVector2Test, BlendOperations)537{538GSVector2 v1(1.0f, 2.0f);539GSVector2 v2(3.0f, 4.0f);540541// Test templated blend32542auto blend_result = v1.blend32<1>(v2); // mask = 1, select x from v1, y from v2543EXPECT_FLOAT_EQ(blend_result.x, 3.0f); // From v2544EXPECT_FLOAT_EQ(blend_result.y, 2.0f); // From v1545546// Test mask-based blend32547GSVector2 mask;548mask.U32[0] = 0x80000000u; // High bit set549mask.U32[1] = 0x00000000u; // High bit clear550auto mask_blend_result = v1.blend32(v2, mask);551EXPECT_FLOAT_EQ(mask_blend_result.x, 3.0f); // From v2 (mask high bit set)552EXPECT_FLOAT_EQ(mask_blend_result.y, 2.0f); // From v1 (mask high bit clear)553}554555TEST(GSVector2Test, MaskOperations)556{557GSVector2 v1;558v1.U32[0] = 0x80000000u; // High bit set559v1.U32[1] = 0x40000000u; // Second bit set560561int mask_result = v1.mask();562EXPECT_EQ(mask_result, 0x1); // One bit should be set in result563}564565TEST(GSVector2Test, ReplaceNaN)566{567GSVector2 v1(1.0f, std::numeric_limits<float>::quiet_NaN());568GSVector2 replacement(99.0f, 88.0f);569570auto result = v1.replace_nan(replacement);571EXPECT_FLOAT_EQ(result.x, 1.0f); // Not NaN, keep original572EXPECT_FLOAT_EQ(result.y, 88.0f); // Was NaN, use replacement573}574575TEST(GSVector2Test, InsertExtract)576{577GSVector2 v1(1.0f, 2.0f);578GSVector2 v2(3.0f, 4.0f);579580// Test insert32581auto insert_result = v1.insert32<1, 0>(v2); // Insert v2[1] into v1[0]582EXPECT_FLOAT_EQ(insert_result.x, 4.0f); // v2[1]583EXPECT_FLOAT_EQ(insert_result.y, 2.0f); // Original v1[1]584585// Test extract32586GSVector2 v3;587v3.I32[0] = 0x12345678;588v3.I32[1] = 0x9ABCDEF0;589EXPECT_EQ(v3.extract32<0>(), 0x12345678);590EXPECT_EQ(v3.extract32<1>(), static_cast<s32>(0x9ABCDEF0));591}592593TEST(GSVector2Test, ComparisonOperators)594{595GSVector2 v1(1.0f, 2.0f);596GSVector2 v2(1.0f, 3.0f);597598auto eq_result = v1 == v2;599EXPECT_EQ(eq_result.I32[0], -1); // 1.0 == 1.0600EXPECT_EQ(eq_result.I32[1], 0); // 2.0 != 3.0601602auto neq_result = v1 != v2;603EXPECT_EQ(neq_result.I32[0], 0); // 1.0 == 1.0604EXPECT_EQ(neq_result.I32[1], -1); // 2.0 != 3.0605606auto gt_result = v1 > v2;607EXPECT_EQ(gt_result.I32[0], 0); // 1.0 == 1.0608EXPECT_EQ(gt_result.I32[1], 0); // 2.0 < 3.0609610auto lt_result = v1 < v2;611EXPECT_EQ(lt_result.I32[0], 0); // 1.0 == 1.0612EXPECT_EQ(lt_result.I32[1], -1); // 2.0 < 3.0613614auto ge_result = v1 >= v2;615EXPECT_EQ(ge_result.I32[0], -1); // 1.0 >= 1.0616EXPECT_EQ(ge_result.I32[1], 0); // 2.0 < 3.0617618auto le_result = v1 <= v2;619EXPECT_EQ(le_result.I32[0], -1); // 1.0 <= 1.0620EXPECT_EQ(le_result.I32[1], -1); // 2.0 <= 3.0621}622623TEST(GSVector2Test, XfffffffffConstant)624{625const auto all_ones = GSVector2::xffffffff();626EXPECT_EQ(all_ones.U64[0], 0xFFFFFFFFFFFFFFFFULL);627}628629// GSVector4i Tests630TEST(GSVector4iTest, ConstexprCreation8Bit)631{632constexpr auto v1 = GSVector4i::cxpr8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);633for (int i = 0; i < 16; i++)634{635EXPECT_EQ(v1.S8[i], i + 1);636}637}638639TEST(GSVector4iTest, MaddOperations)640{641GSVector4i v1(1, 2, 3, 4, 5, 6, 7, 8); // 16-bit values642GSVector4i v2(2, 3, 4, 5, 6, 7, 8, 9);643644auto madd_result = v1.madd_s16(v2);645EXPECT_EQ(madd_result.S32[0], 1 * 2 + 2 * 3); // 2 + 6 = 8646EXPECT_EQ(madd_result.S32[1], 3 * 4 + 4 * 5); // 12 + 20 = 32647EXPECT_EQ(madd_result.S32[2], 5 * 6 + 6 * 7); // 30 + 42 = 72648EXPECT_EQ(madd_result.S32[3], 7 * 8 + 8 * 9); // 56 + 72 = 128649}650651TEST(GSVector4iTest, HorizontalAdd)652{653GSVector4i v1(10, 20, 30, 40);654655auto addp_result = v1.addp_s32();656EXPECT_EQ(addp_result.x, 30); // 10 + 20657EXPECT_EQ(addp_result.y, 70); // 30 + 40658EXPECT_EQ(addp_result.z, 30);659EXPECT_EQ(addp_result.w, 70);660}661662TEST(GSVector4iTest, VerticalMinMaxU8)663{664GSVector4i v1(s8t(10), s8t(50), s8t(30), s8t(200), s8t(15), s8t(100), s8t(5), s8t(250), s8t(80), s8t(20), s8t(60),665s8t(40), s8t(90), s8t(70), s8t(180), s8t(1));666667EXPECT_EQ(v1.minv_u8(), 1u);668EXPECT_EQ(v1.maxv_u8(), 250u);669}670671TEST(GSVector4iTest, VerticalMinMaxU16)672{673GSVector4i v1(1000, 2000, 500, 3000, 1500, 800, 2500, 100);674675EXPECT_EQ(v1.minv_u16(), 100u);676EXPECT_EQ(v1.maxv_u16(), 3000u);677}678679TEST(GSVector4iTest, HaddS16)680{681GSVector4i v1(10, 20, 30, 40, 50, 60, 70, 80);682GSVector4i v2(1, 2, 3, 4, 5, 6, 7, 8);683684auto hadds_result = v1.hadds16(v2);685// First vector: pairs (10,20), (30,40), (50,60), (70,80)686// Second vector: pairs (1,2), (3,4), (5,6), (7,8)687EXPECT_EQ(hadds_result.S16[0], 30); // 10 + 20688EXPECT_EQ(hadds_result.S16[1], 70); // 30 + 40689EXPECT_EQ(hadds_result.S16[2], 110); // 50 + 60690EXPECT_EQ(hadds_result.S16[3], 150); // 70 + 80691EXPECT_EQ(hadds_result.S16[4], 3); // 1 + 2692EXPECT_EQ(hadds_result.S16[5], 7); // 3 + 4693EXPECT_EQ(hadds_result.S16[6], 11); // 5 + 6694EXPECT_EQ(hadds_result.S16[7], 15); // 7 + 8695}696697TEST(GSVector4iTest, BlendOperationsAdvanced)698{699GSVector4i v1(s8t(0x11), s8t(0x22), s8t(0x33), s8t(0x44), s8t(0x55), s8t(0x66), s8t(0x77), s8t(0x88), s8t(0x99),700s8t(0xAA), s8t(0xBB), s8t(0xCC), s8t(0xDD), s8t(0xEE), s8t(0xFF), s8t(0x00));701GSVector4i v2(s8t(0xA1), s8t(0xB2), s8t(0xC3), s8t(0xD4), s8t(0xE5), s8t(0xF6), s8t(0x07), s8t(0x18), s8t(0x29),702s8t(0x3A), s8t(0x4B), s8t(0x5C), s8t(0x6D), s8t(0x7E), s8t(0x8F), s8t(0x90));703GSVector4i mask_blend(s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00),704s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00));705706auto blend_result = v1.blend(v2, mask_blend);707// The blend operation should mix bits based on the mask708// Where mask bit is 1, select from v2; where 0, select from v1709for (int i = 0; i < 2; i++)710{711u64 expected = (v2.U64[i] & mask_blend.U64[i]) | (v1.U64[i] & ~mask_blend.U64[i]);712EXPECT_EQ(blend_result.U64[i], expected);713}714}715716TEST(GSVector4iTest, AdvancedPackingWithTwoVectors)717{718GSVector4i v1(100, 200, 300, 400); // 32-bit signed values719GSVector4i v2(500, 600, 700, 800);720721auto ps32_result = v1.ps32(v2);722// Should pack both vectors' 32-bit values to 16-bit with saturation723EXPECT_EQ(ps32_result.S16[0], 100);724EXPECT_EQ(ps32_result.S16[1], 200);725EXPECT_EQ(ps32_result.S16[2], 300);726EXPECT_EQ(ps32_result.S16[3], 400);727EXPECT_EQ(ps32_result.S16[4], 500);728EXPECT_EQ(ps32_result.S16[5], 600);729EXPECT_EQ(ps32_result.S16[6], 700);730EXPECT_EQ(ps32_result.S16[7], 800);731}732733TEST(GSVector4iTest, AdvancedUnpackingWithTwoVectors)734{735GSVector4i v1(s8t(0x11), s8t(0x22), s8t(0x33), s8t(0x44), s8t(0x55), s8t(0x66), s8t(0x77), s8t(0x88), s8t(0x99),736s8t(0xAA), s8t(0xBB), s8t(0xCC), s8t(0xDD), s8t(0xEE), s8t(0xFF), s8t(0x00));737GSVector4i v2(s8t(0xA1), s8t(0xB2), s8t(0xC3), s8t(0xD4), s8t(0xE5), s8t(0xF6), s8t(0x07), s8t(0x18), s8t(0x29),738s8t(0x3A), s8t(0x4B), s8t(0x5C), s8t(0x6D), s8t(0x7E), s8t(0x8F), s8t(0x90));739740auto upl8_result = v1.upl8(v2);741// Should interleave low 8 bytes from both vectors742EXPECT_EQ(upl8_result.S8[0], s8t(0x11)); // v1[0]743EXPECT_EQ(upl8_result.S8[1], s8t(0xA1)); // v2[0]744EXPECT_EQ(upl8_result.S8[2], s8t(0x22)); // v1[1]745EXPECT_EQ(upl8_result.S8[3], s8t(0xB2)); // v2[1]746747auto uph8_result = v1.uph8(v2);748// Should interleave high 8 bytes from both vectors749EXPECT_EQ(uph8_result.S8[0], s8t(0x99)); // v1[8]750EXPECT_EQ(uph8_result.S8[1], s8t(0x29)); // v2[8]751EXPECT_EQ(uph8_result.S8[2], s8t(0xAA)); // v1[9]752EXPECT_EQ(uph8_result.S8[3], s8t(0x3A)); // v2[9]753}754755TEST(GSVector4iTest, Type64BitConversions)756{757GSVector4i v1(s8t(0x12), s8t(0x34), s8t(0x56), s8t(0x78), s8t(0x9A), s8t(0xBC), s8t(0xDE), s8t(0xF0), s8t(0x11),758s8t(0x22), s8t(0x33), s8t(0x44), s8t(0x55), s8t(0x66), s8t(0x77), s8t(0x88));759760// Test s8to64761auto s8to64_result = v1.s8to64();762EXPECT_EQ(s8to64_result.S64[0], 0x12);763EXPECT_EQ(s8to64_result.S64[1], 0x34);764765// Test u16to64766auto u16to64_result = v1.u16to64();767EXPECT_EQ(u16to64_result.U64[0], 0x3412u); // Little endian 16-bit768EXPECT_EQ(u16to64_result.U64[1], 0x7856u);769770// Test s32to64771auto s32to64_result = v1.s32to64();772EXPECT_EQ(s32to64_result.S64[0], static_cast<s64>(0x0000000078563412LL));773EXPECT_EQ(s32to64_result.S64[1], static_cast<s64>(0xFFFFFFFFF0DEBC9ALL));774}775776TEST(GSVector4iTest, Shift64BitOperations)777{778GSVector4i v1;779v1.U64[0] = 0x123456789ABCDEF0ULL;780v1.U64[1] = 0xFEDCBA0987654321ULL;781782// Test sll64783auto sll64_result = v1.sll64<4>();784EXPECT_EQ(sll64_result.U64[0], 0x23456789ABCDEF00ULL);785EXPECT_EQ(sll64_result.U64[1], 0xEDCBA09876543210ULL);786787// Test srl64788auto srl64_result = v1.srl64<4>();789EXPECT_EQ(srl64_result.U64[0], 0x0123456789ABCDEFULL);790EXPECT_EQ(srl64_result.U64[1], 0x0FEDCBA098765432ULL);791}792793#ifdef GSVECTOR_HAS_SRLV794TEST(GSVector4iTest, VariableShifts)795{796GSVector4i v1(0x1000, 0x2000, 0x4000, 0x8000, 0x1000, 0x2000, 0x4000, 0x8000);797GSVector4i shift_amounts(1, 2, 3, 4, 1, 2, 3, 4);798799auto sllv16_result = v1.sllv16(shift_amounts);800EXPECT_EQ(sllv16_result.U16[0], 0x2000); // 0x1000 << 1801EXPECT_EQ(sllv16_result.U16[1], 0x8000); // 0x2000 << 2802EXPECT_EQ(sllv16_result.U16[2], 0x0000); // 0x4000 << 3 (overflow)803EXPECT_EQ(sllv16_result.U16[3], 0x0000); // 0x8000 << 4 (overflow)804EXPECT_EQ(sllv16_result.U16[4], 0x2000); // 0x1000 << 1805EXPECT_EQ(sllv16_result.U16[5], 0x8000); // 0x2000 << 2806EXPECT_EQ(sllv16_result.U16[6], 0x0000); // 0x4000 << 3 (overflow)807EXPECT_EQ(sllv16_result.U16[7], 0x0000); // 0x8000 << 4 (overflow)808809auto srlv16_result = v1.srlv16(shift_amounts);810EXPECT_EQ(srlv16_result.U16[0], 0x0800); // 0x1000 >> 1811EXPECT_EQ(srlv16_result.U16[1], 0x0800); // 0x2000 >> 2812EXPECT_EQ(srlv16_result.U16[2], 0x0800); // 0x4000 >> 3813EXPECT_EQ(srlv16_result.U16[3], 0x0800); // 0x8000 >> 4814EXPECT_EQ(srlv16_result.U16[4], 0x0800); // 0x1000 >> 1815EXPECT_EQ(srlv16_result.U16[5], 0x0800); // 0x2000 >> 2816EXPECT_EQ(srlv16_result.U16[6], 0x0800); // 0x4000 >> 3817EXPECT_EQ(srlv16_result.U16[7], 0x0800); // 0x8000 >> 4818}819#endif820821TEST(GSVector4iTest, MultiplicationOperations)822{823GSVector4i v1(10, 20, 30, 40, 50, 60, 70, 80);824GSVector4i v2(2, 3, 4, 5, 6, 7, 8, 9);825826// Test mul16hs - high 16 bits of 16-bit multiplication827auto mul16hs_result = v1.mul16hs(v2);828// For 16-bit values, this should mostly be 0 unless we have large values829for (int i = 0; i < 8; i++)830{831s32 expected = (v1.S16[i] * v2.S16[i]) >> 16;832EXPECT_EQ(mul16hs_result.S16[i], expected);833}834835// Test mul16hrs - rounded high 16 bits836auto mul16hrs_result = v1.mul16hrs(v2);837for (int i = 0; i < 8; i++)838{839const s16 expected = static_cast<s16>((((v1.S16[i] * v2.S16[i]) >> 14) + 1) >> 1);840EXPECT_EQ(mul16hrs_result.S16[i], expected);841}842}843844TEST(GSVector4iTest, Eq64Operations)845{846GSVector4i v1;847GSVector4i v2;848v1.S64[0] = 0x123456789ABCDEF0LL;849v1.S64[1] = 0xFEDCBA0987654321LL;850v2.S64[0] = 0x123456789ABCDEF0LL; // Same as v1[0]851v2.S64[1] = 0x1111111111111111LL; // Different from v1[1]852853auto eq64_result = v1.eq64(v2);854EXPECT_EQ(eq64_result.S64[0], -1); // Equal855EXPECT_EQ(eq64_result.S64[1], 0); // Not equal856}857858TEST(GSVector4iTest, InsertExtract64Bit)859{860GSVector4i v1(0x12345678, 0x9ABCDEF0, 0x11111111, 0x22222222);861862// Test insert64863auto v_insert64 = v1.insert64<0>(static_cast<s64>(0x9999888877776666ULL));864EXPECT_EQ(v_insert64.extract64<0>(), static_cast<s64>(0x9999888877776666ULL));865EXPECT_EQ(v_insert64.extract64<1>(), v1.extract64<1>());866867// Test extract64868EXPECT_EQ(v1.extract64<0>(), static_cast<s64>(0x9ABCDEF012345678ULL)); // Little endian combination869EXPECT_EQ(v1.extract64<1>(), static_cast<s64>(0x2222222211111111ULL));870}871872TEST(GSVector4iTest, LoadStoreSpecialOperations)873{874// Test loadnt (non-temporal load)875alignas(VECTOR_ALIGNMENT) static constexpr const s32 data[4] = {0x11111111, 0x22222222, 0x33333333, 0x44444444};876auto loaded_nt = GSVector4i::loadnt(data);877for (int i = 0; i < 4; i++)878{879EXPECT_EQ(loaded_nt.S32[i], data[i]);880}881882// Test storent (non-temporal store)883alignas(VECTOR_ALIGNMENT) s32 output_nt[4];884GSVector4i::storent(output_nt, loaded_nt);885for (int i = 0; i < 4; i++)886{887EXPECT_EQ(output_nt[i], data[i]);888}889890// Test zext32891auto zext_result = GSVector4i::zext32(0x12345678);892EXPECT_EQ(zext_result.x, 0x12345678);893EXPECT_EQ(zext_result.y, 0);894EXPECT_EQ(zext_result.z, 0);895EXPECT_EQ(zext_result.w, 0);896}897898TEST(GSVector4iTest, LoadStoreHalfOperations)899{900// Test loadl and loadh901u64 data[2] = {0x123456789ABCDEF0ULL, 0xFEDCBA0987654321ULL};902903auto loaded_low = GSVector4i::loadl<true>(data);904EXPECT_EQ(loaded_low.U64[0], data[0]);905EXPECT_EQ(loaded_low.U64[1], 0u);906907auto loaded_high = GSVector4i::loadh<true>(data);908EXPECT_EQ(loaded_high.U64[0], 0u);909EXPECT_EQ(loaded_high.U64[1], data[0]);910911// Test storel and storeh912GSVector4i test_vec;913test_vec.U64[0] = 0xAAAABBBBCCCCDDDDULL;914test_vec.U64[1] = 0xEEEEFFFF00001111ULL;915916s32 output_low[2];917GSVector4i::storel<true>(output_low, test_vec);918EXPECT_EQ(reinterpret_cast<u64*>(output_low)[0], test_vec.U64[0]);919920s32 output_high[2];921GSVector4i::storeh<true>(output_high, test_vec);922EXPECT_EQ(reinterpret_cast<u64*>(output_high)[0], test_vec.U64[1]);923}924925TEST(GSVector4iTest, BroadcastOperations)926{927GSVector4i v1(10, 20, 30, 40);928929auto broadcast_result = GSVector4i::broadcast128(v1);930// In no-SIMD implementation, this just returns the same vector931EXPECT_EQ(broadcast_result.x, v1.x);932EXPECT_EQ(broadcast_result.y, v1.y);933EXPECT_EQ(broadcast_result.z, v1.z);934EXPECT_EQ(broadcast_result.w, v1.w);935}936937TEST(GSVector4iTest, StaticHelperFunctions)938{939GSVector2i xy(10, 20);940GSVector2i zw(30, 40);941942auto xyxy_result1 = GSVector4i::xyxy(xy, zw);943EXPECT_EQ(xyxy_result1.x, 10);944EXPECT_EQ(xyxy_result1.y, 20);945EXPECT_EQ(xyxy_result1.z, 30);946EXPECT_EQ(xyxy_result1.w, 40);947948auto xyxy_result2 = GSVector4i::xyxy(xy);949EXPECT_EQ(xyxy_result2.x, 10);950EXPECT_EQ(xyxy_result2.y, 20);951EXPECT_EQ(xyxy_result2.z, 10);952EXPECT_EQ(xyxy_result2.w, 20);953}954955// GSVector4 Tests956TEST(GSVector4Test, DoubleOperations)957{958// Test all 64-bit double operations959GSVector4 v1 = GSVector4::f64(3.14159, 2.71828);960GSVector4 v2 = GSVector4::f64(1.41421, 1.73205);961962auto add64_result = v1.add64(v2);963EXPECT_DOUBLE_EQ(add64_result.F64[0], 3.14159 + 1.41421);964EXPECT_DOUBLE_EQ(add64_result.F64[1], 2.71828 + 1.73205);965966auto sub64_result = v1.sub64(v2);967EXPECT_DOUBLE_EQ(sub64_result.F64[0], 3.14159 - 1.41421);968EXPECT_DOUBLE_EQ(sub64_result.F64[1], 2.71828 - 1.73205);969970auto mul64_result = v1.mul64(v2);971EXPECT_DOUBLE_EQ(mul64_result.F64[0], 3.14159 * 1.41421);972EXPECT_DOUBLE_EQ(mul64_result.F64[1], 2.71828 * 1.73205);973974auto div64_result = v1.div64(v2);975EXPECT_DOUBLE_EQ(div64_result.F64[0], 3.14159 / 1.41421);976EXPECT_DOUBLE_EQ(div64_result.F64[1], 2.71828 / 1.73205);977}978979TEST(GSVector4Test, BasicOps)980{981GSVector4 v(1.0f, -2.0f, 3.5f, -4.5f);982983EXPECT_FLOAT_EQ(v.addv(), (1.0f - 2.0f + 3.5f - 4.5f));984EXPECT_FLOAT_EQ(v.minv(), -4.5f);985EXPECT_FLOAT_EQ(v.maxv(), 3.5f);986987auto av = v.abs();988EXPECT_FLOAT_EQ(av.x, 1.0f);989EXPECT_FLOAT_EQ(av.y, 2.0f);990EXPECT_FLOAT_EQ(av.z, 3.5f);991EXPECT_FLOAT_EQ(av.w, 4.5f);992993auto nv = v.neg();994EXPECT_FLOAT_EQ(nv.x, -1.0f);995EXPECT_FLOAT_EQ(nv.y, 2.0f);996EXPECT_FLOAT_EQ(nv.z, -3.5f);997EXPECT_FLOAT_EQ(nv.w, 4.5f);998999auto fl = GSVector4(1.9f, -1.2f, 3.01f, -3.99f).floor();1000EXPECT_FLOAT_EQ(fl.x, 1.0f);1001EXPECT_FLOAT_EQ(fl.y, -2.0f);1002EXPECT_FLOAT_EQ(fl.z, 3.0f);1003EXPECT_FLOAT_EQ(fl.w, -4.0f);10041005auto cl = GSVector4(1.1f, -1.2f, 3.01f, -3.99f).ceil();1006EXPECT_FLOAT_EQ(cl.x, 2.0f);1007EXPECT_FLOAT_EQ(cl.y, -1.0f);1008EXPECT_FLOAT_EQ(cl.z, 4.0f);1009EXPECT_FLOAT_EQ(cl.w, -3.0f);10101011// sat(scale)1012auto sat_scaled = GSVector4(-5.0f, 10.0f, 500.0f, 260.0f).sat(255.0f);1013EXPECT_FLOAT_EQ(sat_scaled.x, 0.0f);1014EXPECT_FLOAT_EQ(sat_scaled.y, 10.0f);1015EXPECT_FLOAT_EQ(sat_scaled.z, 255.0f);1016EXPECT_FLOAT_EQ(sat_scaled.w, 255.0f);10171018// sat(minmax vector) : x/z clamped to [min.x, min.z], y/w to [min.y, min.w]1019GSVector4 range(0.0f, -1.0f, 2.0f, 1.0f);1020auto sat_pair = v.sat(range);1021EXPECT_FLOAT_EQ(sat_pair.x, 1.0f); // within [0,2]1022EXPECT_FLOAT_EQ(sat_pair.y, -1.0f); // clamped to -11023EXPECT_FLOAT_EQ(sat_pair.z, 2.0f); // clamped to 21024EXPECT_FLOAT_EQ(sat_pair.w, -1.0f); // clamped to -11025}10261027TEST(GSVector4Test, BlendAndMask)1028{1029GSVector4 a(1, 2, 3, 4);1030GSVector4 b(5, 6, 7, 8);10311032// Template blend32<mask> (selects only lanes 0/1 from the 'v' argument per bit)1033auto tb = a.blend32<0b1010>(b);1034EXPECT_FLOAT_EQ(tb.x, 1.0f); // bit0 = 0 -> v[0]1035EXPECT_FLOAT_EQ(tb.y, 6.0f); // bit1 = 1 -> v[1]1036EXPECT_FLOAT_EQ(tb.z, 3.0f); // bit2 = 0 -> v[0]1037EXPECT_FLOAT_EQ(tb.w, 8.0f); // bit3 = 1 -> v[1]10381039// Masked blend: high bit set -> take from second vector argument (b); else from 'a'1040GSVector4 mask;1041mask.U32[0] = 0x00000000u;1042mask.U32[1] = 0x80000000u;1043mask.U32[2] = 0x00000000u;1044mask.U32[3] = 0x80000000u;1045auto mb = a.blend32(b, mask);1046EXPECT_FLOAT_EQ(mb.x, a.x);1047EXPECT_FLOAT_EQ(mb.y, b.y);1048EXPECT_FLOAT_EQ(mb.z, a.z);1049EXPECT_FLOAT_EQ(mb.w, b.w);10501051// mask() bit packing (bits 31,23,15,7)1052GSVector4 m;1053m.U32[0] = 0x80000000u; // sets bit 01054m.U32[1] = 0x40000000u; // sets bit 11055m.U32[2] = 0x20000000u; // sets bit 21056m.U32[3] = 0x10000000u; // sets bit 31057EXPECT_EQ(m.mask(), 0x1);1058}10591060TEST(GSVector4Test, HorizontalAndInterleave)1061{1062GSVector4 v(1, 2, 10, 20);1063auto hadd0 = v.hadd();1064EXPECT_FLOAT_EQ(hadd0.x, 3);1065EXPECT_FLOAT_EQ(hadd0.y, 30);1066EXPECT_FLOAT_EQ(hadd0.z, 3);1067EXPECT_FLOAT_EQ(hadd0.w, 30);10681069auto hsub0 = v.hsub();1070EXPECT_FLOAT_EQ(hsub0.x, -1);1071EXPECT_FLOAT_EQ(hsub0.y, -10);1072EXPECT_FLOAT_EQ(hsub0.z, -1);1073EXPECT_FLOAT_EQ(hsub0.w, -10);10741075GSVector4 v2(3, 4, 5, 6);1076auto hadd1 = v.hadd(v2);1077EXPECT_FLOAT_EQ(hadd1.x, 3);1078EXPECT_FLOAT_EQ(hadd1.y, 30);1079EXPECT_FLOAT_EQ(hadd1.z, 7);1080EXPECT_FLOAT_EQ(hadd1.w, 11);10811082auto hsub1 = v.hsub(v2);1083EXPECT_FLOAT_EQ(hsub1.x, -1);1084EXPECT_FLOAT_EQ(hsub1.y, -10);1085EXPECT_FLOAT_EQ(hsub1.z, -1);1086EXPECT_FLOAT_EQ(hsub1.w, -1);10871088// Interleave / low-high helpers1089GSVector4 a(1, 2, 3, 4);1090GSVector4 b(5, 6, 7, 8);1091auto upl = a.upl(b);1092EXPECT_FLOAT_EQ(upl.x, 1);1093EXPECT_FLOAT_EQ(upl.y, 5);1094EXPECT_FLOAT_EQ(upl.z, 2);1095EXPECT_FLOAT_EQ(upl.w, 6);1096auto uph = a.uph(b);1097EXPECT_FLOAT_EQ(uph.x, 3);1098EXPECT_FLOAT_EQ(uph.y, 7);1099EXPECT_FLOAT_EQ(uph.z, 4);1100EXPECT_FLOAT_EQ(uph.w, 8);1101auto l2h = a.l2h(b);1102EXPECT_FLOAT_EQ(l2h.x, 1);1103EXPECT_FLOAT_EQ(l2h.y, 2);1104EXPECT_FLOAT_EQ(l2h.z, 5);1105EXPECT_FLOAT_EQ(l2h.w, 6);1106auto h2l = a.h2l(b);1107EXPECT_FLOAT_EQ(h2l.x, 7);1108EXPECT_FLOAT_EQ(h2l.y, 8);1109EXPECT_FLOAT_EQ(h2l.z, 3);1110EXPECT_FLOAT_EQ(h2l.w, 4);1111}11121113TEST(GSVector4Test, BroadcastAndInsertExtract)1114{1115GSVector4 v(9, 2, 3, 4);1116auto bc_self = v.broadcast32();1117EXPECT_FLOAT_EQ(bc_self.x, 9);1118EXPECT_FLOAT_EQ(bc_self.y, 9);1119EXPECT_FLOAT_EQ(bc_self.z, 9);1120EXPECT_FLOAT_EQ(bc_self.w, 9);11211122auto bc_static = GSVector4::broadcast32(v);1123EXPECT_FLOAT_EQ(bc_static.z, 9);11241125GSVector4 a(1, 2, 3, 4);1126GSVector4 b(5, 6, 7, 8);1127auto ins_from_other = a.insert32<2, 0>(b); // copy b.z into a.x1128EXPECT_FLOAT_EQ(ins_from_other.x, 7);1129EXPECT_FLOAT_EQ(ins_from_other.y, 2);1130EXPECT_FLOAT_EQ(ins_from_other.z, 3);1131EXPECT_FLOAT_EQ(ins_from_other.w, 4);11321133auto ins_scalar = a.insert32<1>(42.0f);1134EXPECT_FLOAT_EQ(ins_scalar.x, 1);1135EXPECT_FLOAT_EQ(ins_scalar.y, 42.0f);1136EXPECT_FLOAT_EQ(ins_scalar.z, 3);1137EXPECT_FLOAT_EQ(ins_scalar.w, 4);11381139EXPECT_FLOAT_EQ(a.extract32<0>(), 1.0f);1140EXPECT_FLOAT_EQ(a.extract32<3>(), 4.0f);1141}11421143TEST(GSVector4Test, BitwiseAndAndNot)1144{1145GSVector4 a;1146a.U32[0] = 0xFFFFFFFFu;1147a.U32[1] = 0x00FF00FFu;1148a.U32[2] = 0x12345678u;1149a.U32[3] = 0xAAAAAAAAu;11501151GSVector4 b;1152b.U32[0] = 0x0F0F0F0Fu;1153b.U32[1] = 0xFF00FF00u;1154b.U32[2] = 0xFFFFFFFFu;1155b.U32[3] = 0x55555555u;11561157auto vand = a & b;1158EXPECT_EQ(vand.U32[0], 0x0F0F0F0Fu);1159EXPECT_EQ(vand.U32[1], 0x00000000u);1160EXPECT_EQ(vand.U32[2], 0x12345678u);1161EXPECT_EQ(vand.U32[3], 0x00000000u);11621163auto vor = a | b;1164EXPECT_EQ(vor.U32[0], 0xFFFFFFFFu);1165EXPECT_EQ(vor.U32[1], 0xFFFFFFFFu);1166EXPECT_EQ(vor.U32[2], 0xFFFFFFFFu);1167EXPECT_EQ(vor.U32[3], 0xFFFFFFFFu);11681169auto vxor = a ^ b;1170EXPECT_EQ(vxor.U32[0], 0xF0F0F0F0u);1171EXPECT_EQ(vxor.U32[1], 0xFFFFFFFFu);1172EXPECT_EQ(vxor.U32[2], 0xEDCBA987u);1173EXPECT_EQ(vxor.U32[3], 0xFFFFFFFFu);11741175auto an = a.andnot(b); // (~b) & a1176EXPECT_EQ(an.U32[0], (~b.U32[0]) & a.U32[0]);1177EXPECT_EQ(an.U32[1], (~b.U32[1]) & a.U32[1]);1178EXPECT_EQ(an.U32[2], (~b.U32[2]) & a.U32[2]);1179EXPECT_EQ(an.U32[3], (~b.U32[3]) & a.U32[3]);1180}11811182TEST(GSVector4Test, ReplaceNaN)1183{1184GSVector4 v(1.0f, std::numeric_limits<float>::quiet_NaN(), -5.0f, std::numeric_limits<float>::quiet_NaN());1185GSVector4 repl(10.0f, 20.0f, 30.0f, 40.0f);1186auto r = v.replace_nan(repl);1187EXPECT_FLOAT_EQ(r.x, 1.0f); // kept1188EXPECT_FLOAT_EQ(r.y, 20.0f); // replaced1189EXPECT_FLOAT_EQ(r.z, -5.0f); // kept1190EXPECT_FLOAT_EQ(r.w, 40.0f); // replaced1191}11921193TEST(GSVector4Test, DoubleExtendedOps)1194{1195GSVector4 d = GSVector4::f64(-4.0, 9.0);1196auto sq = d.sqr64();1197EXPECT_DOUBLE_EQ(sq.F64[0], 16.0);1198EXPECT_DOUBLE_EQ(sq.F64[1], 81.0);11991200auto rt = GSVector4::f64(4.0, 9.0).sqrt64();1201EXPECT_DOUBLE_EQ(rt.F64[0], 2.0);1202EXPECT_DOUBLE_EQ(rt.F64[1], 3.0);12031204auto ab = d.abs64();1205EXPECT_DOUBLE_EQ(ab.F64[0], 4.0);1206EXPECT_DOUBLE_EQ(ab.F64[1], 9.0);12071208auto ng = d.neg64();1209EXPECT_DOUBLE_EQ(ng.F64[0], 4.0);1210EXPECT_DOUBLE_EQ(ng.F64[1], -9.0);12111212GSVector4 d2 = GSVector4::f64(-2.0, 10.0);1213EXPECT_DOUBLE_EQ(d.min64(d2).F64[0], -4.0);1214EXPECT_DOUBLE_EQ(d.min64(d2).F64[1], 9.0);1215EXPECT_DOUBLE_EQ(d.max64(d2).F64[0], -2.0);1216EXPECT_DOUBLE_EQ(d.max64(d2).F64[1], 10.0);12171218auto gt = d.gt64(d2);1219EXPECT_EQ(gt.U64[0], 0ULL); // -4 > -2 ? no1220EXPECT_EQ(gt.U64[1], 0ULL); // 9 > 10 ? no1221auto lt = d.lt64(d2);1222EXPECT_NE(lt.U64[0], 0ULL); // -4 < -21223EXPECT_NE(lt.U64[1], 0ULL); // 9 < 101224auto ge = d.ge64(d2);1225EXPECT_EQ(ge.U64[0], 0ULL); // -4 >= -2 ? no1226EXPECT_EQ(ge.U64[1], 0ULL); // 9 >= 10 ? no1227auto le = d.le64(d2);1228EXPECT_NE(le.U64[0], 0ULL);1229EXPECT_NE(le.U64[1], 0ULL);1230auto eq = d.eq64(d);1231EXPECT_EQ(eq.U64[0], 0xFFFFFFFFFFFFFFFFULL);1232EXPECT_EQ(eq.U64[1], 0xFFFFFFFFFFFFFFFFULL);1233}12341235TEST(GSVector4Test, FloatToDoubleConversions)1236{1237GSVector4 vf(1.25f, 2.75f, 3.0f, 4.0f);1238auto fd = GSVector4::f32to64(vf);1239EXPECT_DOUBLE_EQ(fd.F64[0], 1.25);1240EXPECT_DOUBLE_EQ(fd.F64[1], 2.75);12411242GSVector4 vd = GSVector4::f64(5.9, -2.1);1243auto i32 = vd.f64toi32();1244EXPECT_EQ(i32.S32[0], 5);1245EXPECT_EQ(i32.S32[1], -2);1246}12471248// Cross-class conversion tests1249TEST(GSVectorTest, ConversionsGSVector2iGSVector2)1250{1251GSVector2i vi(42, 84);1252GSVector2 vf(vi);1253EXPECT_FLOAT_EQ(vf.x, 42.0f);1254EXPECT_FLOAT_EQ(vf.y, 84.0f);12551256GSVector2 vf2(3.14f, 2.71f);1257GSVector2i vi2(vf2);1258EXPECT_EQ(vi2.x, 3);1259EXPECT_EQ(vi2.y, 2);12601261// Test cast operations1262auto cast_result = GSVector2::cast(vi);1263// Cast preserves bit pattern, so we can't directly compare float values1264EXPECT_EQ(cast_result.I32[0], 42);1265EXPECT_EQ(cast_result.I32[1], 84);12661267auto cast_result2 = GSVector2i::cast(vf2);1268// Cast preserves bit pattern1269EXPECT_EQ(cast_result2.U32[0], vf2.U32[0]);1270EXPECT_EQ(cast_result2.U32[1], vf2.U32[1]);1271}12721273// width() tests1274TEST(GSVectorTest, Width_ReturnsCorrectValue)1275{1276const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=801277const GSVector4 rect2 = GSVector4(30.0f, 40.0f, 100.0f, 120.0f);12781279EXPECT_FLOAT_EQ(rect1.width(), 40.0f); // 50 - 10 = 401280EXPECT_FLOAT_EQ(rect2.width(), 70.0f); // 100 - 30 = 701281}12821283TEST(GSVectorTest, Width_EmptyRect_ReturnsZero)1284{1285const GSVector4 emptyRect = GSVector4(0.0f, 0.0f, 0.0f, 0.0f);1286const GSVector4 zeroSizeRect = GSVector4(25.0f, 35.0f, 25.0f, 35.0f);12871288EXPECT_FLOAT_EQ(emptyRect.width(), 0.0f);1289EXPECT_FLOAT_EQ(zeroSizeRect.width(), 0.0f);1290}12911292TEST(GSVectorTest, Width_InvalidRect_ReturnsNegative)1293{1294const GSVector4 invalidRect = GSVector4(50.0f, 80.0f, 10.0f, 20.0f); // right < left, bottom < top12951296EXPECT_FLOAT_EQ(invalidRect.width(), -40.0f); // 10 - 50 = -401297}12981299// height() tests1300TEST(GSVectorTest, Height_ReturnsCorrectValue)1301{1302const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=801303const GSVector4 rect2 = GSVector4(30.0f, 40.0f, 100.0f, 120.0f);13041305EXPECT_FLOAT_EQ(rect1.height(), 60.0f); // 80 - 20 = 601306EXPECT_FLOAT_EQ(rect2.height(), 80.0f); // 120 - 40 = 801307}13081309TEST(GSVectorTest, Height_EmptyRect_ReturnsZero)1310{1311const GSVector4 emptyRect = GSVector4(0.0f, 0.0f, 0.0f, 0.0f);1312const GSVector4 zeroSizeRect = GSVector4(25.0f, 35.0f, 25.0f, 35.0f);13131314EXPECT_FLOAT_EQ(emptyRect.height(), 0.0f);1315EXPECT_FLOAT_EQ(zeroSizeRect.height(), 0.0f);1316}13171318TEST(GSVectorTest, Height_InvalidRect_ReturnsNegative)1319{1320const GSVector4 invalidRect = GSVector4(50.0f, 80.0f, 10.0f, 20.0f); // right < left, bottom < top13211322EXPECT_FLOAT_EQ(invalidRect.height(), -60.0f); // 20 - 80 = -601323}13241325// rsize() tests1326TEST(GSVectorTest, Rsize_ReturnsCorrectSize)1327{1328const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=801329const GSVector4 rect2 = GSVector4(30.0f, 40.0f, 100.0f, 120.0f);13301331GSVector2 size1 = rect1.rsize();1332EXPECT_FLOAT_EQ(size1.x, 40.0f);1333EXPECT_FLOAT_EQ(size1.y, 60.0f);13341335GSVector2 size2 = rect2.rsize();1336EXPECT_FLOAT_EQ(size2.x, 70.0f);1337EXPECT_FLOAT_EQ(size2.y, 80.0f);1338}13391340TEST(GSVectorTest, Rsize_EmptyRect_ReturnsZeroSize)1341{1342const GSVector4 emptyRect = GSVector4(0.0f, 0.0f, 0.0f, 0.0f);13431344GSVector2 size = emptyRect.rsize();1345EXPECT_FLOAT_EQ(size.x, 0.0f);1346EXPECT_FLOAT_EQ(size.y, 0.0f);1347}13481349// rvalid() tests1350TEST(GSVectorTest, Rvalid_ValidRect_ReturnsTrue)1351{1352const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=801353const GSVector4 rect2 = GSVector4(30.0f, 40.0f, 100.0f, 120.0f);1354EXPECT_TRUE(rect1.rvalid());1355EXPECT_TRUE(rect2.rvalid());1356}13571358TEST(GSVectorTest, Rvalid_EmptyRect_ReturnsFalse)1359{1360const GSVector4 emptyRect = GSVector4(0.0f, 0.0f, 0.0f, 0.0f);1361const GSVector4 zeroSizeRect = GSVector4(25.0f, 35.0f, 25.0f, 35.0f);13621363// Empty rect where left==right and top==bottom is considered invalid1364EXPECT_FALSE(emptyRect.rvalid());1365EXPECT_FALSE(zeroSizeRect.rvalid());1366}13671368TEST(GSVectorTest, Rvalid_InvalidRect_ReturnsFalse)1369{1370const GSVector4 invalidRect = GSVector4(50.0f, 80.0f, 10.0f, 20.0f); // right < left, bottom < top1371EXPECT_FALSE(invalidRect.rvalid());1372}13731374TEST(GSVectorTest, Rvalid_PartiallyInvalid_ReturnsFalse)1375{1376const GSVector4 invalidWidth(50.0f, 20.0f, 10.0f, 80.0f); // right < left1377const GSVector4 invalidHeight(10.0f, 80.0f, 50.0f, 20.0f); // bottom < top13781379EXPECT_FALSE(invalidWidth.rvalid());1380EXPECT_FALSE(invalidHeight.rvalid());1381}13821383// rempty() tests1384TEST(GSVectorTest, Rempty_EmptyRect_ReturnsTrue)1385{1386const GSVector4 emptyRect = GSVector4(0.0f, 0.0f, 0.0f, 0.0f);1387const GSVector4 zeroSizeRect = GSVector4(25.0f, 35.0f, 25.0f, 35.0f);1388EXPECT_TRUE(emptyRect.rempty());1389EXPECT_TRUE(zeroSizeRect.rempty());1390}13911392TEST(GSVectorTest, Rempty_NonEmptyRect_ReturnsFalse)1393{1394const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=801395const GSVector4 rect2 = GSVector4(30.0f, 40.0f, 100.0f, 120.0f);1396EXPECT_FALSE(rect1.rempty());1397EXPECT_FALSE(rect2.rempty());1398}13991400TEST(GSVectorTest, Rempty_ZeroWidthOnly_ReturnsTrue)1401{1402GSVector4 zeroWidth(25.0f, 20.0f, 25.0f, 80.0f); // width = 0, height > 01403EXPECT_TRUE(zeroWidth.rempty());1404}14051406TEST(GSVectorTest, Rempty_ZeroHeightOnly_ReturnsTrue)1407{1408GSVector4 zeroHeight(10.0f, 50.0f, 40.0f, 50.0f); // width > 0, height = 01409EXPECT_TRUE(zeroHeight.rempty());1410}14111412TEST(GSVectorTest, Rempty_InvalidRect_ReturnsTrue)1413{1414const GSVector4 invalidRect = GSVector4(50.0f, 80.0f, 10.0f, 20.0f); // right < left, bottom < top14151416// Invalid rects are considered empty1417EXPECT_TRUE(invalidRect.rempty());1418}14191420// runion() tests1421TEST(GSVectorTest, Runion_OverlappingRects_ReturnsCorrectUnion)1422{1423const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=801424const GSVector4 rect2 = GSVector4(30.0f, 40.0f, 100.0f, 120.0f);14251426GSVector4 result = rect1.runion(rect2);14271428// Union should be min of lefts/tops and max of rights/bottoms1429EXPECT_FLOAT_EQ(result.left, 10.0f); // min(10, 30)1430EXPECT_FLOAT_EQ(result.top, 20.0f); // min(20, 40)1431EXPECT_FLOAT_EQ(result.right, 100.0f); // max(50, 100)1432EXPECT_FLOAT_EQ(result.bottom, 120.0f); // max(80, 120)1433}14341435TEST(GSVectorTest, Runion_NonOverlappingRects_ReturnsEnclosingRect)1436{1437GSVector4 rectA(0.0f, 0.0f, 10.0f, 10.0f);1438GSVector4 rectB(50.0f, 50.0f, 60.0f, 60.0f);14391440GSVector4 result = rectA.runion(rectB);14411442EXPECT_FLOAT_EQ(result.left, 0.0f);1443EXPECT_FLOAT_EQ(result.top, 0.0f);1444EXPECT_FLOAT_EQ(result.right, 60.0f);1445EXPECT_FLOAT_EQ(result.bottom, 60.0f);1446}14471448TEST(GSVectorTest, Runion_ContainedRect_ReturnsOuterRect)1449{1450GSVector4 outer(0.0f, 0.0f, 100.0f, 100.0f);1451GSVector4 inner(25.0f, 25.0f, 75.0f, 75.0f);14521453GSVector4 result = outer.runion(inner);14541455EXPECT_FLOAT_EQ(result.left, 0.0f);1456EXPECT_FLOAT_EQ(result.top, 0.0f);1457EXPECT_FLOAT_EQ(result.right, 100.0f);1458EXPECT_FLOAT_EQ(result.bottom, 100.0f);1459}14601461TEST(GSVectorTest, Runion_WithEmptyRect_ReturnsOtherRect)1462{1463const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=801464const GSVector4 rect2 = GSVector4(30.0f, 40.0f, 100.0f, 120.0f);1465const GSVector4 emptyRect = GSVector4(0.0f, 0.0f, 0.0f, 0.0f);14661467GSVector4 result = rect1.runion(emptyRect);14681469// Union with empty rect at origin1470EXPECT_FLOAT_EQ(result.left, 0.0f); // min(10, 0)1471EXPECT_FLOAT_EQ(result.top, 0.0f); // min(20, 0)1472EXPECT_FLOAT_EQ(result.right, 50.0f); // max(50, 0)1473EXPECT_FLOAT_EQ(result.bottom, 80.0f); // max(80, 0)1474}14751476TEST(GSVectorTest, Runion_IdenticalRects_ReturnsSameRect)1477{1478const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=8014791480GSVector4 result = rect1.runion(rect1);14811482EXPECT_FLOAT_EQ(result.left, rect1.left);1483EXPECT_FLOAT_EQ(result.top, rect1.top);1484EXPECT_FLOAT_EQ(result.right, rect1.right);1485EXPECT_FLOAT_EQ(result.bottom, rect1.bottom);1486}14871488TEST(GSVectorTest, Runion_NegativeCoordinates_ReturnsCorrectUnion)1489{1490GSVector4 rectA(-50.0f, -40.0f, -10.0f, -5.0f);1491GSVector4 rectB(-30.0f, -20.0f, 10.0f, 15.0f);14921493GSVector4 result = rectA.runion(rectB);14941495EXPECT_FLOAT_EQ(result.left, -50.0f); // min(-50, -30)1496EXPECT_FLOAT_EQ(result.top, -40.0f); // min(-40, -20)1497EXPECT_FLOAT_EQ(result.right, 10.0f); // max(-10, 10)1498EXPECT_FLOAT_EQ(result.bottom, 15.0f); // max(-5, 15)1499}15001501TEST(GSVectorTest, Runion_IsCommutative)1502{1503const GSVector4 rect1 = GSVector4(10.0f, 20.0f, 50.0f, 80.0f); // left=10, top=20, right=50, bottom=801504const GSVector4 rect2 = GSVector4(30.0f, 40.0f, 100.0f, 120.0f);15051506GSVector4 result1 = rect1.runion(rect2);1507GSVector4 result2 = rect2.runion(rect1);15081509EXPECT_TRUE(result1.eq(result2));1510}151115121513