Path: blob/master/src/common-tests/gsvector_tests.cpp
4214 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);196EXPECT_EQ(upl8_result.U8[8], 0x56);197EXPECT_EQ(upl8_result.U8[9], 0);198EXPECT_EQ(upl8_result.U8[10], 0);199EXPECT_EQ(upl8_result.U8[11], 0);200EXPECT_EQ(upl8_result.U8[12], 0x78);201EXPECT_EQ(upl8_result.U8[13], 0);202EXPECT_EQ(upl8_result.U8[14], 0);203EXPECT_EQ(upl8_result.U8[15], 0);204205auto upl16_result = v1.upl16();206EXPECT_EQ(upl16_result.U16[0], 0x12);207EXPECT_EQ(upl16_result.U16[1], 0);208EXPECT_EQ(upl16_result.U16[2], 0x34);209EXPECT_EQ(upl16_result.U16[3], 0);210EXPECT_EQ(upl16_result.U16[4], 0x56);211EXPECT_EQ(upl16_result.U16[5], 0);212EXPECT_EQ(upl16_result.U16[6], 0x78);213EXPECT_EQ(upl16_result.U16[7], 0);214}215216TEST(GSVector2iTest, TypeConversions)217{218GSVector2i v1(0x12, 0x34, 0x56, 0x78);219220// Test u8to16221auto s8to16_result = v1.u8to16();222EXPECT_EQ(s8to16_result.S16[0], 0x12);223EXPECT_EQ(s8to16_result.S16[1], 0);224EXPECT_EQ(s8to16_result.S16[2], 0x34);225EXPECT_EQ(s8to16_result.S16[3], 0);226227// Test u8to32228auto u8to32_result = v1.u8to32();229EXPECT_EQ(u8to32_result.U32[0], 0x12u);230EXPECT_EQ(u8to32_result.U32[1], 0u);231}232233TEST(GSVector2iTest, ByteShifts)234{235GSVector2i v1(s8t(0x12), s8t(0x34), s8t(0x56), s8t(0x78), s8t(0x9A), s8t(0xBC), s8t(0xDE), s8t(0xF0));236237// Test srl<2> - shift right logical by 2 bytes238auto srl_result = v1.srl<2>();239EXPECT_EQ(srl_result.U8[0], 0x56u);240EXPECT_EQ(srl_result.U8[1], 0x78u);241EXPECT_EQ(srl_result.U8[2], 0x9Au);242EXPECT_EQ(srl_result.U8[3], 0xBCu);243EXPECT_EQ(srl_result.U8[4], 0xDEu);244EXPECT_EQ(srl_result.U8[5], 0xF0u);245EXPECT_EQ(srl_result.U8[6], 0u);246EXPECT_EQ(srl_result.U8[7], 0u);247248// Test sll<3> - shift left logical by 3 bytes249auto sll_result = v1.sll<3>();250EXPECT_EQ(sll_result.U8[0], 0u);251EXPECT_EQ(sll_result.U8[1], 0u);252EXPECT_EQ(sll_result.U8[2], 0u);253EXPECT_EQ(sll_result.U8[3], 0x12u);254EXPECT_EQ(sll_result.U8[4], 0x34u);255EXPECT_EQ(sll_result.U8[5], 0x56u);256EXPECT_EQ(sll_result.U8[6], 0x78u);257EXPECT_EQ(sll_result.U8[7], 0x9Au);258}259260TEST(GSVector2iTest, ArithmeticWith16BitElements)261{262GSVector2i v1(100, 200, 300, 400);263GSVector2i v2(50, 60, 70, 80);264265auto add16_result = v1.add16(v2);266EXPECT_EQ(add16_result.S16[0], 150);267EXPECT_EQ(add16_result.S16[1], 260);268EXPECT_EQ(add16_result.S16[2], 370);269EXPECT_EQ(add16_result.S16[3], 480);270271auto sub16_result = v1.sub16(v2);272EXPECT_EQ(sub16_result.S16[0], 50);273EXPECT_EQ(sub16_result.S16[1], 140);274EXPECT_EQ(sub16_result.S16[2], 230);275EXPECT_EQ(sub16_result.S16[3], 320);276277auto mul16_result = v1.mul16l(v2);278EXPECT_EQ(mul16_result.S16[0], 5000);279EXPECT_EQ(mul16_result.S16[1], 12000);280EXPECT_EQ(mul16_result.S16[2], 21000);281EXPECT_EQ(mul16_result.S16[3], 32000);282}283284TEST(GSVector2iTest, ArithmeticWith8BitElements)285{286GSVector2i v1(10, 20, 30, 40, 50, 60, 70, 80);287GSVector2i v2(5, 8, 12, 16, 20, 24, 28, 32);288289auto add8_result = v1.add8(v2);290for (int i = 0; i < 8; i++)291{292EXPECT_EQ(add8_result.S8[i], v1.S8[i] + v2.S8[i]);293}294295auto sub8_result = v1.sub8(v2);296for (int i = 0; i < 8; i++)297{298EXPECT_EQ(sub8_result.S8[i], v1.S8[i] - v2.S8[i]);299}300}301302TEST(GSVector2iTest, SaturatedArithmetic)303{304// Test signed saturation305GSVector2i v1(120, -120, 100, -100, 0, 0, 0, 0);306GSVector2i v2(50, -50, 60, -60, 0, 0, 0, 0);307308auto adds8_result = v1.adds8(v2);309EXPECT_EQ(adds8_result.S8[0], 127); // 120 + 50 = 170, saturated to 127310EXPECT_EQ(adds8_result.S8[1], -128); // -120 + (-50) = -170, saturated to -128311EXPECT_EQ(adds8_result.S8[2], 127); // 100 + 60 = 160, saturated to 127312EXPECT_EQ(adds8_result.S8[3], -128); // -100 + (-60) = -160, saturated to -128313314auto subs8_result = v1.subs8(v2);315EXPECT_EQ(subs8_result.S8[0], 70); // 120 - 50 = 70316EXPECT_EQ(subs8_result.S8[1], -70); // -120 - (-50) = -70317EXPECT_EQ(subs8_result.S8[2], 40); // 100 - 60 = 40318EXPECT_EQ(subs8_result.S8[3], -40); // -100 - (-60) = -40319}320321TEST(GSVector2iTest, UnsignedSaturatedArithmetic)322{323GSVector2i v1(s8t(200), s8t(100), s8t(150), s8t(50), s8t(0), s8t(0), s8t(0), s8t(0));324GSVector2i v2(s8t(80), s8t(120), s8t(30), s8t(70), s8t(0), s8t(0), s8t(0), s8t(0));325326auto addus8_result = v1.addus8(v2);327EXPECT_EQ(addus8_result.U8[0], 255); // 200 + 80 = 280, saturated to 255328EXPECT_EQ(addus8_result.U8[1], 220); // 100 + 120 = 220329EXPECT_EQ(addus8_result.U8[2], 180); // 150 + 30 = 180330EXPECT_EQ(addus8_result.U8[3], 120); // 50 + 70 = 120331332auto subus8_result = v1.subus8(v2);333EXPECT_EQ(subus8_result.U8[0], 120); // 200 - 80 = 120334EXPECT_EQ(subus8_result.U8[1], 0); // 100 - 120 = -20, saturated to 0335EXPECT_EQ(subus8_result.U8[2], 120); // 150 - 30 = 120336EXPECT_EQ(subus8_result.U8[3], 0); // 50 - 70 = -20, saturated to 0337}338339TEST(GSVector2iTest, AverageOperations)340{341GSVector2i v1(s8t(100), s8t(200), s8t(50), s8t(150), s8t(0), s8t(0), s8t(0), s8t(0));342GSVector2i v2(s8t(80), s8t(180), s8t(70), s8t(130), s8t(0), s8t(0), s8t(0), s8t(0));343344auto avg8_result = v1.avg8(v2);345EXPECT_EQ(avg8_result.U8[0], 90); // (100 + 80) / 2 = 90346EXPECT_EQ(avg8_result.U8[1], 190); // (200 + 180) / 2 = 190347EXPECT_EQ(avg8_result.U8[2], 60); // (50 + 70) / 2 = 60348EXPECT_EQ(avg8_result.U8[3], 140); // (150 + 130) / 2 = 140349350auto avg16_result = v1.avg16(v2);351EXPECT_EQ(avg16_result.U16[0], (51300 + 46160) / 2); // Average of packed 16-bit values352EXPECT_EQ(avg16_result.U16[1], (38450 + 33350) / 2);353}354355TEST(GSVector2iTest, ComparisonOperations)356{357GSVector2i v1(10, 20, 30, 40, 50, 60, 70, 80);358GSVector2i v2(5, 25, 30, 45, 55, 55, 75, 75);359360// Test eq8361auto eq8_result = v1.eq8(v2);362EXPECT_EQ(eq8_result.S8[0], 0); // 10 != 5363EXPECT_EQ(eq8_result.S8[1], 0); // 20 != 25364EXPECT_EQ(eq8_result.S8[2], -1); // 30 == 30365EXPECT_EQ(eq8_result.S8[3], 0); // 40 != 45366367// Test neq8368auto neq8_result = v1.neq8(v2);369EXPECT_EQ(neq8_result.S8[0], -1); // 10 != 5370EXPECT_EQ(neq8_result.S8[1], -1); // 20 != 25371EXPECT_EQ(neq8_result.S8[2], 0); // 30 == 30372EXPECT_EQ(neq8_result.S8[3], -1); // 40 != 45373374// Test gt8375auto gt8_result = v1.gt8(v2);376EXPECT_EQ(gt8_result.S8[0], -1); // 10 > 5377EXPECT_EQ(gt8_result.S8[1], 0); // 20 < 25378EXPECT_EQ(gt8_result.S8[2], 0); // 30 == 30379EXPECT_EQ(gt8_result.S8[3], 0); // 40 < 45380381// Test ge8382auto ge8_result = v1.ge8(v2);383EXPECT_EQ(ge8_result.S8[0], -1); // 10 >= 5384EXPECT_EQ(ge8_result.S8[1], 0); // 20 < 25385EXPECT_EQ(ge8_result.S8[2], -1); // 30 >= 30386EXPECT_EQ(ge8_result.S8[3], 0); // 40 < 45387388// Test lt8389auto lt8_result = v1.lt8(v2);390EXPECT_EQ(lt8_result.S8[0], 0); // 10 > 5391EXPECT_EQ(lt8_result.S8[1], -1); // 20 < 25392EXPECT_EQ(lt8_result.S8[2], 0); // 30 == 30393EXPECT_EQ(lt8_result.S8[3], -1); // 40 < 45394395// Test le8396auto le8_result = v1.le8(v2);397EXPECT_EQ(le8_result.S8[0], 0); // 10 > 5398EXPECT_EQ(le8_result.S8[1], -1); // 20 <= 25399EXPECT_EQ(le8_result.S8[2], -1); // 30 <= 30400EXPECT_EQ(le8_result.S8[3], -1); // 40 <= 45401}402403TEST(GSVector2iTest, MaskAndBooleanOperations)404{405GSVector2i v1(s8t(0x80), s8t(0x40), s8t(0x80), s8t(0x00), s8t(0x80), s8t(0x80), s8t(0x00), s8t(0x80));406407s32 mask_result = v1.mask();408// Mask should be formed from high bits of each byte409s32 expected_mask = 0x01 | 0x04 | 0x10 | 0x20 | 0x80; // Bits 0, 2, 4, 5, 7410EXPECT_EQ(mask_result & 0xB5, expected_mask & 0xB5); // Check set bits411412// Test alltrue and allfalse413GSVector2i all_ones;414all_ones.U64[0] = 0xFFFFFFFFFFFFFFFFULL;415EXPECT_TRUE(all_ones.alltrue());416EXPECT_FALSE(all_ones.allfalse());417418GSVector2i all_zeros;419all_zeros.U64[0] = 0;420EXPECT_FALSE(all_zeros.alltrue());421EXPECT_TRUE(all_zeros.allfalse());422}423424TEST(GSVector2iTest, InsertExtractOperations)425{426GSVector2i v1(0x12345678, 0x9ABCDEF0);427428// Test insert/extract 8-bit429auto v_insert8 = v1.insert8<0>(0x55);430EXPECT_EQ(v_insert8.extract8<0>(), 0x55);431EXPECT_EQ(v1.extract8<1>(), s8t(0x56));432433// Test insert/extract 16-bit434auto v_insert16 = v1.insert16<1>(0x1234);435EXPECT_EQ(v_insert16.extract16<1>(), 0x1234);436EXPECT_EQ(v1.extract16<0>(), static_cast<s16>(0x5678));437438// Test insert/extract 32-bit439auto v_insert32 = v1.insert32<0>(0xAABBCCDD);440EXPECT_EQ(v_insert32.extract32<0>(), static_cast<s32>(0xAABBCCDD));441EXPECT_EQ(v1.extract32<1>(), static_cast<s32>(0x9ABCDEF0));442}443444TEST(GSVector2iTest, LoadStoreOperations)445{446// Test load32447s32 value = 0x12345678;448auto loaded32 = GSVector2i::load32(&value);449EXPECT_EQ(loaded32.x, 0x12345678);450EXPECT_EQ(loaded32.y, 0);451452// Test set32453auto set32_result = GSVector2i::set32(0xAABBCCDD);454EXPECT_EQ(set32_result.x, static_cast<s32>(0xAABBCCDD));455EXPECT_EQ(set32_result.y, 0);456457// Test store32458s32 output_value;459GSVector2i::store32(&output_value, loaded32);460EXPECT_EQ(output_value, 0x12345678);461462// Test full load/store463s32 data[2] = {0x11111111, 0x22222222};464auto loaded = GSVector2i::load<true>(data);465EXPECT_EQ(loaded.S32[0], 0x11111111);466EXPECT_EQ(loaded.S32[1], 0x22222222);467468s32 output[2];469GSVector2i::store<true>(output, loaded);470EXPECT_EQ(output[0], 0x11111111);471EXPECT_EQ(output[1], 0x22222222);472}473474TEST(GSVector2iTest, BitwiseAssignmentOperations)475{476GSVector2i v1(0xF0F0F0F0, 0x0F0F0F0F);477GSVector2i v2(0xAAAAAAAA, 0x55555555);478479// Test &=480GSVector2i v_and = v1;481v_and &= v2;482EXPECT_EQ(v_and.U32[0], 0xA0A0A0A0u);483EXPECT_EQ(v_and.U32[1], 0x05050505u);484485// Test |=486GSVector2i v_or = v1;487v_or |= v2;488EXPECT_EQ(v_or.U32[0], 0xFAFAFAFAu);489EXPECT_EQ(v_or.U32[1], 0x5F5F5F5Fu);490491// Test ^=492GSVector2i v_xor = v1;493v_xor ^= v2;494EXPECT_EQ(v_xor.U32[0], 0x5A5A5A5Au);495EXPECT_EQ(v_xor.U32[1], 0x5A5A5A5Au);496}497498TEST(GSVector2iTest, BitwiseScalarOperations)499{500GSVector2i v1(0xF0F0F0F0, 0x0F0F0F0F);501s32 scalar = 0xAAAAAAAA;502503auto and_result = v1 & scalar;504EXPECT_EQ(and_result.U32[0], 0xA0A0A0A0u);505EXPECT_EQ(and_result.U32[1], 0x0A0A0A0Au);506507auto or_result = v1 | scalar;508EXPECT_EQ(or_result.U32[0], 0xFAFAFAFAu);509EXPECT_EQ(or_result.U32[1], 0xAFAFAFAFu);510511auto xor_result = v1 ^ scalar;512EXPECT_EQ(xor_result.U32[0], 0x5A5A5A5Au);513EXPECT_EQ(xor_result.U32[1], 0xA5A5A5A5u);514}515516TEST(GSVector2iTest, NotOperation)517{518GSVector2i v1(0xF0F0F0F0, 0x0F0F0F0F);519auto not_result = ~v1;520EXPECT_EQ(not_result.U32[0], 0x0F0F0F0Fu);521EXPECT_EQ(not_result.U32[1], 0xF0F0F0F0u);522}523524// GSVector2 Tests525TEST(GSVector2Test, Construction)526{527// Single value constructor528GSVector2 v1(3.14f);529EXPECT_FLOAT_EQ(v1.x, 3.14f);530EXPECT_FLOAT_EQ(v1.y, 3.14f);531532// Two value constructor (float)533GSVector2 v2(1.5f, 2.5f);534EXPECT_FLOAT_EQ(v2.x, 1.5f);535EXPECT_FLOAT_EQ(v2.y, 2.5f);536537// Two value constructor (int)538GSVector2 v3(10, 20);539EXPECT_FLOAT_EQ(v3.x, 10.0f);540EXPECT_FLOAT_EQ(v3.y, 20.0f);541542// Single int constructor543GSVector2 v4(42);544EXPECT_FLOAT_EQ(v4.x, 42.0f);545EXPECT_FLOAT_EQ(v4.y, 42.0f);546}547548TEST(GSVector2Test, BlendOperations)549{550GSVector2 v1(1.0f, 2.0f);551GSVector2 v2(3.0f, 4.0f);552553// Test templated blend32554auto blend_result = v1.blend32<1>(v2); // mask = 1, select x from v1, y from v2555EXPECT_FLOAT_EQ(blend_result.x, 3.0f); // From v2556EXPECT_FLOAT_EQ(blend_result.y, 2.0f); // From v1557558// Test mask-based blend32559GSVector2 mask;560mask.U32[0] = 0x80000000u; // High bit set561mask.U32[1] = 0x00000000u; // High bit clear562auto mask_blend_result = v1.blend32(v2, mask);563EXPECT_FLOAT_EQ(mask_blend_result.x, 3.0f); // From v2 (mask high bit set)564EXPECT_FLOAT_EQ(mask_blend_result.y, 2.0f); // From v1 (mask high bit clear)565}566567TEST(GSVector2Test, MaskOperations)568{569GSVector2 v1;570v1.U32[0] = 0x80000000u; // High bit set571v1.U32[1] = 0x40000000u; // Second bit set572573int mask_result = v1.mask();574EXPECT_EQ(mask_result, 0x1); // One bit should be set in result575}576577TEST(GSVector2Test, ReplaceNaN)578{579GSVector2 v1(1.0f, std::numeric_limits<float>::quiet_NaN());580GSVector2 replacement(99.0f, 88.0f);581582auto result = v1.replace_nan(replacement);583EXPECT_FLOAT_EQ(result.x, 1.0f); // Not NaN, keep original584EXPECT_FLOAT_EQ(result.y, 88.0f); // Was NaN, use replacement585}586587TEST(GSVector2Test, InsertExtract)588{589GSVector2 v1(1.0f, 2.0f);590GSVector2 v2(3.0f, 4.0f);591592// Test insert32593auto insert_result = v1.insert32<1, 0>(v2); // Insert v2[1] into v1[0]594EXPECT_FLOAT_EQ(insert_result.x, 4.0f); // v2[1]595EXPECT_FLOAT_EQ(insert_result.y, 2.0f); // Original v1[1]596597// Test extract32598GSVector2 v3;599v3.I32[0] = 0x12345678;600v3.I32[1] = 0x9ABCDEF0;601EXPECT_EQ(v3.extract32<0>(), 0x12345678);602EXPECT_EQ(v3.extract32<1>(), static_cast<s32>(0x9ABCDEF0));603}604605TEST(GSVector2Test, ComparisonOperators)606{607GSVector2 v1(1.0f, 2.0f);608GSVector2 v2(1.0f, 3.0f);609610auto eq_result = v1 == v2;611EXPECT_EQ(eq_result.I32[0], -1); // 1.0 == 1.0612EXPECT_EQ(eq_result.I32[1], 0); // 2.0 != 3.0613614auto neq_result = v1 != v2;615EXPECT_EQ(neq_result.I32[0], 0); // 1.0 == 1.0616EXPECT_EQ(neq_result.I32[1], -1); // 2.0 != 3.0617618auto gt_result = v1 > v2;619EXPECT_EQ(gt_result.I32[0], 0); // 1.0 == 1.0620EXPECT_EQ(gt_result.I32[1], 0); // 2.0 < 3.0621622auto lt_result = v1 < v2;623EXPECT_EQ(lt_result.I32[0], 0); // 1.0 == 1.0624EXPECT_EQ(lt_result.I32[1], -1); // 2.0 < 3.0625626auto ge_result = v1 >= v2;627EXPECT_EQ(ge_result.I32[0], -1); // 1.0 >= 1.0628EXPECT_EQ(ge_result.I32[1], 0); // 2.0 < 3.0629630auto le_result = v1 <= v2;631EXPECT_EQ(le_result.I32[0], -1); // 1.0 <= 1.0632EXPECT_EQ(le_result.I32[1], -1); // 2.0 <= 3.0633}634635TEST(GSVector2Test, XfffffffffConstant)636{637const auto all_ones = GSVector2::xffffffff();638EXPECT_EQ(all_ones.U64[0], 0xFFFFFFFFFFFFFFFFULL);639}640641// GSVector4i Tests642TEST(GSVector4iTest, ConstexprCreation8Bit)643{644constexpr auto v1 = GSVector4i::cxpr8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);645for (int i = 0; i < 16; i++)646{647EXPECT_EQ(v1.S8[i], i + 1);648}649}650651TEST(GSVector4iTest, MaddOperations)652{653GSVector4i v1(1, 2, 3, 4, 5, 6, 7, 8); // 16-bit values654GSVector4i v2(2, 3, 4, 5, 6, 7, 8, 9);655656auto madd_result = v1.madd_s16(v2);657EXPECT_EQ(madd_result.S32[0], 1 * 2 + 2 * 3); // 2 + 6 = 8658EXPECT_EQ(madd_result.S32[1], 3 * 4 + 4 * 5); // 12 + 20 = 32659EXPECT_EQ(madd_result.S32[2], 5 * 6 + 6 * 7); // 30 + 42 = 72660EXPECT_EQ(madd_result.S32[3], 7 * 8 + 8 * 9); // 56 + 72 = 128661}662663TEST(GSVector4iTest, HorizontalAdd)664{665GSVector4i v1(10, 20, 30, 40);666667auto addp_result = v1.addp_s32();668EXPECT_EQ(addp_result.x, 30); // 10 + 20669EXPECT_EQ(addp_result.y, 70); // 30 + 40670EXPECT_EQ(addp_result.z, 30);671EXPECT_EQ(addp_result.w, 70);672}673674TEST(GSVector4iTest, VerticalMinMaxU8)675{676GSVector4i v1(s8t(10), s8t(50), s8t(30), s8t(200), s8t(15), s8t(100), s8t(5), s8t(250), s8t(80), s8t(20), s8t(60),677s8t(40), s8t(90), s8t(70), s8t(180), s8t(1));678679EXPECT_EQ(v1.minv_u8(), 1u);680EXPECT_EQ(v1.maxv_u8(), 250u);681}682683TEST(GSVector4iTest, VerticalMinMaxU16)684{685GSVector4i v1(1000, 2000, 500, 3000, 1500, 800, 2500, 100);686687EXPECT_EQ(v1.minv_u16(), 100u);688EXPECT_EQ(v1.maxv_u16(), 3000u);689}690691TEST(GSVector4iTest, HaddS16)692{693GSVector4i v1(10, 20, 30, 40, 50, 60, 70, 80);694GSVector4i v2(1, 2, 3, 4, 5, 6, 7, 8);695696auto hadds_result = v1.hadds16(v2);697// First vector: pairs (10,20), (30,40), (50,60), (70,80)698// Second vector: pairs (1,2), (3,4), (5,6), (7,8)699EXPECT_EQ(hadds_result.S16[0], 30); // 10 + 20700EXPECT_EQ(hadds_result.S16[1], 70); // 30 + 40701EXPECT_EQ(hadds_result.S16[2], 110); // 50 + 60702EXPECT_EQ(hadds_result.S16[3], 150); // 70 + 80703EXPECT_EQ(hadds_result.S16[4], 3); // 1 + 2704EXPECT_EQ(hadds_result.S16[5], 7); // 3 + 4705EXPECT_EQ(hadds_result.S16[6], 11); // 5 + 6706EXPECT_EQ(hadds_result.S16[7], 15); // 7 + 8707}708709TEST(GSVector4iTest, BlendOperationsAdvanced)710{711GSVector4i v1(s8t(0x11), s8t(0x22), s8t(0x33), s8t(0x44), s8t(0x55), s8t(0x66), s8t(0x77), s8t(0x88), s8t(0x99),712s8t(0xAA), s8t(0xBB), s8t(0xCC), s8t(0xDD), s8t(0xEE), s8t(0xFF), s8t(0x00));713GSVector4i v2(s8t(0xA1), s8t(0xB2), s8t(0xC3), s8t(0xD4), s8t(0xE5), s8t(0xF6), s8t(0x07), s8t(0x18), s8t(0x29),714s8t(0x3A), s8t(0x4B), s8t(0x5C), s8t(0x6D), s8t(0x7E), s8t(0x8F), s8t(0x90));715GSVector4i mask_blend(s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00),716s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00), s8t(0xFF), s8t(0x00));717718auto blend_result = v1.blend(v2, mask_blend);719// The blend operation should mix bits based on the mask720// Where mask bit is 1, select from v2; where 0, select from v1721for (int i = 0; i < 2; i++)722{723u64 expected = (v2.U64[i] & mask_blend.U64[i]) | (v1.U64[i] & ~mask_blend.U64[i]);724EXPECT_EQ(blend_result.U64[i], expected);725}726}727728TEST(GSVector4iTest, AdvancedPackingWithTwoVectors)729{730GSVector4i v1(100, 200, 300, 400); // 32-bit signed values731GSVector4i v2(500, 600, 700, 800);732733auto ps32_result = v1.ps32(v2);734// Should pack both vectors' 32-bit values to 16-bit with saturation735EXPECT_EQ(ps32_result.S16[0], 100);736EXPECT_EQ(ps32_result.S16[1], 200);737EXPECT_EQ(ps32_result.S16[2], 300);738EXPECT_EQ(ps32_result.S16[3], 400);739EXPECT_EQ(ps32_result.S16[4], 500);740EXPECT_EQ(ps32_result.S16[5], 600);741EXPECT_EQ(ps32_result.S16[6], 700);742EXPECT_EQ(ps32_result.S16[7], 800);743}744745TEST(GSVector4iTest, AdvancedUnpackingWithTwoVectors)746{747GSVector4i v1(s8t(0x11), s8t(0x22), s8t(0x33), s8t(0x44), s8t(0x55), s8t(0x66), s8t(0x77), s8t(0x88), s8t(0x99),748s8t(0xAA), s8t(0xBB), s8t(0xCC), s8t(0xDD), s8t(0xEE), s8t(0xFF), s8t(0x00));749GSVector4i v2(s8t(0xA1), s8t(0xB2), s8t(0xC3), s8t(0xD4), s8t(0xE5), s8t(0xF6), s8t(0x07), s8t(0x18), s8t(0x29),750s8t(0x3A), s8t(0x4B), s8t(0x5C), s8t(0x6D), s8t(0x7E), s8t(0x8F), s8t(0x90));751752auto upl8_result = v1.upl8(v2);753// Should interleave low 8 bytes from both vectors754EXPECT_EQ(upl8_result.S8[0], s8t(0x11)); // v1[0]755EXPECT_EQ(upl8_result.S8[1], s8t(0xA1)); // v2[0]756EXPECT_EQ(upl8_result.S8[2], s8t(0x22)); // v1[1]757EXPECT_EQ(upl8_result.S8[3], s8t(0xB2)); // v2[1]758759auto uph8_result = v1.uph8(v2);760// Should interleave high 8 bytes from both vectors761EXPECT_EQ(uph8_result.S8[0], s8t(0x99)); // v1[8]762EXPECT_EQ(uph8_result.S8[1], s8t(0x29)); // v2[8]763EXPECT_EQ(uph8_result.S8[2], s8t(0xAA)); // v1[9]764EXPECT_EQ(uph8_result.S8[3], s8t(0x3A)); // v2[9]765}766767TEST(GSVector4iTest, Type64BitConversions)768{769GSVector4i v1(s8t(0x12), s8t(0x34), s8t(0x56), s8t(0x78), s8t(0x9A), s8t(0xBC), s8t(0xDE), s8t(0xF0), s8t(0x11),770s8t(0x22), s8t(0x33), s8t(0x44), s8t(0x55), s8t(0x66), s8t(0x77), s8t(0x88));771772// Test s8to64773auto s8to64_result = v1.s8to64();774EXPECT_EQ(s8to64_result.S64[0], 0x12);775EXPECT_EQ(s8to64_result.S64[1], 0x34);776777// Test u16to64778auto u16to64_result = v1.u16to64();779EXPECT_EQ(u16to64_result.U64[0], 0x3412u); // Little endian 16-bit780EXPECT_EQ(u16to64_result.U64[1], 0x7856u);781782// Test s32to64783auto s32to64_result = v1.s32to64();784EXPECT_EQ(s32to64_result.S64[0], static_cast<s64>(0x0000000078563412LL));785EXPECT_EQ(s32to64_result.S64[1], static_cast<s64>(0xFFFFFFFFF0DEBC9ALL));786}787788TEST(GSVector4iTest, Shift64BitOperations)789{790GSVector4i v1;791v1.U64[0] = 0x123456789ABCDEF0ULL;792v1.U64[1] = 0xFEDCBA0987654321ULL;793794// Test sll64795auto sll64_result = v1.sll64<4>();796EXPECT_EQ(sll64_result.U64[0], 0x23456789ABCDEF00ULL);797EXPECT_EQ(sll64_result.U64[1], 0xEDCBA09876543210ULL);798799// Test srl64800auto srl64_result = v1.srl64<4>();801EXPECT_EQ(srl64_result.U64[0], 0x0123456789ABCDEFULL);802EXPECT_EQ(srl64_result.U64[1], 0x0FEDCBA098765432ULL);803}804805#ifdef GSVECTOR_HAS_SRLV806TEST(GSVector4iTest, VariableShifts)807{808GSVector4i v1(0x1000, 0x2000, 0x4000, 0x8000);809GSVector4i shift_amounts(1, 2, 3, 4);810811auto sllv16_result = v1.sllv16(shift_amounts);812EXPECT_EQ(sllv16_result.U16[0], 0x2000); // 0x1000 << 1813EXPECT_EQ(sllv16_result.U16[1], 0x8000); // 0x2000 << 2814EXPECT_EQ(sllv16_result.U16[2], 0x0000); // 0x4000 << 3 (overflow)815EXPECT_EQ(sllv16_result.U16[3], 0x0000); // 0x8000 << 4 (overflow)816817auto srlv16_result = v1.srlv16(shift_amounts);818EXPECT_EQ(srlv16_result.U16[0], 0x0800); // 0x1000 >> 1819EXPECT_EQ(srlv16_result.U16[1], 0x0800); // 0x2000 >> 2820EXPECT_EQ(srlv16_result.U16[2], 0x0800); // 0x4000 >> 3821EXPECT_EQ(srlv16_result.U16[3], 0x0800); // 0x8000 >> 4822}823#endif824825TEST(GSVector4iTest, MultiplicationOperations)826{827GSVector4i v1(10, 20, 30, 40, 50, 60, 70, 80);828GSVector4i v2(2, 3, 4, 5, 6, 7, 8, 9);829830// Test mul16hs - high 16 bits of 16-bit multiplication831auto mul16hs_result = v1.mul16hs(v2);832// For 16-bit values, this should mostly be 0 unless we have large values833for (int i = 0; i < 8; i++)834{835s32 expected = (v1.S16[i] * v2.S16[i]) >> 16;836EXPECT_EQ(mul16hs_result.S16[i], expected);837}838839// Test mul16hrs - rounded high 16 bits840auto mul16hrs_result = v1.mul16hrs(v2);841for (int i = 0; i < 8; i++)842{843const s16 expected = static_cast<s16>((((v1.S16[i] * v2.S16[i]) >> 14) + 1) >> 1);844EXPECT_EQ(mul16hrs_result.S16[i], expected);845}846}847848TEST(GSVector4iTest, Eq64Operations)849{850GSVector4i v1;851GSVector4i v2;852v1.S64[0] = 0x123456789ABCDEF0LL;853v1.S64[1] = 0xFEDCBA0987654321LL;854v2.S64[0] = 0x123456789ABCDEF0LL; // Same as v1[0]855v2.S64[1] = 0x1111111111111111LL; // Different from v1[1]856857auto eq64_result = v1.eq64(v2);858EXPECT_EQ(eq64_result.S64[0], -1); // Equal859EXPECT_EQ(eq64_result.S64[1], 0); // Not equal860}861862TEST(GSVector4iTest, InsertExtract64Bit)863{864GSVector4i v1(0x12345678, 0x9ABCDEF0, 0x11111111, 0x22222222);865866// Test insert64867auto v_insert64 = v1.insert64<0>(static_cast<s64>(0x9999888877776666ULL));868EXPECT_EQ(v_insert64.extract64<0>(), static_cast<s64>(0x9999888877776666ULL));869EXPECT_EQ(v_insert64.extract64<1>(), v1.extract64<1>());870871// Test extract64872EXPECT_EQ(v1.extract64<0>(), static_cast<s64>(0x9ABCDEF012345678ULL)); // Little endian combination873EXPECT_EQ(v1.extract64<1>(), static_cast<s64>(0x2222222211111111ULL));874}875876TEST(GSVector4iTest, LoadStoreSpecialOperations)877{878// Test loadnt (non-temporal load)879alignas(VECTOR_ALIGNMENT) static constexpr const s32 data[4] = {0x11111111, 0x22222222, 0x33333333, 0x44444444};880auto loaded_nt = GSVector4i::loadnt(data);881for (int i = 0; i < 4; i++)882{883EXPECT_EQ(loaded_nt.S32[i], data[i]);884}885886// Test storent (non-temporal store)887alignas(VECTOR_ALIGNMENT) s32 output_nt[4];888GSVector4i::storent(output_nt, loaded_nt);889for (int i = 0; i < 4; i++)890{891EXPECT_EQ(output_nt[i], data[i]);892}893894// Test zext32895auto zext_result = GSVector4i::zext32(0x12345678);896EXPECT_EQ(zext_result.x, 0x12345678);897EXPECT_EQ(zext_result.y, 0);898EXPECT_EQ(zext_result.z, 0);899EXPECT_EQ(zext_result.w, 0);900}901902TEST(GSVector4iTest, LoadStoreHalfOperations)903{904// Test loadl and loadh905u64 data[2] = {0x123456789ABCDEF0ULL, 0xFEDCBA0987654321ULL};906907auto loaded_low = GSVector4i::loadl<true>(data);908EXPECT_EQ(loaded_low.U64[0], data[0]);909EXPECT_EQ(loaded_low.U64[1], 0u);910911auto loaded_high = GSVector4i::loadh<true>(data);912EXPECT_EQ(loaded_high.U64[0], 0u);913EXPECT_EQ(loaded_high.U64[1], data[0]);914915// Test storel and storeh916GSVector4i test_vec;917test_vec.U64[0] = 0xAAAABBBBCCCCDDDDULL;918test_vec.U64[1] = 0xEEEEFFFF00001111ULL;919920s32 output_low[2];921GSVector4i::storel<true>(output_low, test_vec);922EXPECT_EQ(reinterpret_cast<u64*>(output_low)[0], test_vec.U64[0]);923924s32 output_high[2];925GSVector4i::storeh<true>(output_high, test_vec);926EXPECT_EQ(reinterpret_cast<u64*>(output_high)[0], test_vec.U64[1]);927}928929TEST(GSVector4iTest, BroadcastOperations)930{931GSVector4i v1(10, 20, 30, 40);932933auto broadcast_result = GSVector4i::broadcast128(v1);934// In no-SIMD implementation, this just returns the same vector935EXPECT_EQ(broadcast_result.x, v1.x);936EXPECT_EQ(broadcast_result.y, v1.y);937EXPECT_EQ(broadcast_result.z, v1.z);938EXPECT_EQ(broadcast_result.w, v1.w);939}940941TEST(GSVector4iTest, StaticHelperFunctions)942{943GSVector2i xy(10, 20);944GSVector2i zw(30, 40);945946auto xyxy_result1 = GSVector4i::xyxy(xy, zw);947EXPECT_EQ(xyxy_result1.x, 10);948EXPECT_EQ(xyxy_result1.y, 20);949EXPECT_EQ(xyxy_result1.z, 30);950EXPECT_EQ(xyxy_result1.w, 40);951952auto xyxy_result2 = GSVector4i::xyxy(xy);953EXPECT_EQ(xyxy_result2.x, 10);954EXPECT_EQ(xyxy_result2.y, 20);955EXPECT_EQ(xyxy_result2.z, 10);956EXPECT_EQ(xyxy_result2.w, 20);957}958959// GSVector4 Tests960TEST(GSVector4Test, DoubleOperations)961{962// Test all 64-bit double operations963GSVector4 v1 = GSVector4::f64(3.14159, 2.71828);964GSVector4 v2 = GSVector4::f64(1.41421, 1.73205);965966auto add64_result = v1.add64(v2);967EXPECT_DOUBLE_EQ(add64_result.F64[0], 3.14159 + 1.41421);968EXPECT_DOUBLE_EQ(add64_result.F64[1], 2.71828 + 1.73205);969970auto sub64_result = v1.sub64(v2);971EXPECT_DOUBLE_EQ(sub64_result.F64[0], 3.14159 - 1.41421);972EXPECT_DOUBLE_EQ(sub64_result.F64[1], 2.71828 - 1.73205);973974auto mul64_result = v1.mul64(v2);975EXPECT_DOUBLE_EQ(mul64_result.F64[0], 3.14159 * 1.41421);976EXPECT_DOUBLE_EQ(mul64_result.F64[1], 2.71828 * 1.73205);977978auto div64_result = v1.div64(v2);979EXPECT_DOUBLE_EQ(div64_result.F64[0], 3.14159 / 1.41421);980EXPECT_DOUBLE_EQ(div64_result.F64[1], 2.71828 / 1.73205);981}982983TEST(GSVector4Test, BasicOps)984{985GSVector4 v(1.0f, -2.0f, 3.5f, -4.5f);986987EXPECT_FLOAT_EQ(v.addv(), (1.0f - 2.0f + 3.5f - 4.5f));988EXPECT_FLOAT_EQ(v.minv(), -4.5f);989EXPECT_FLOAT_EQ(v.maxv(), 3.5f);990991auto av = v.abs();992EXPECT_FLOAT_EQ(av.x, 1.0f);993EXPECT_FLOAT_EQ(av.y, 2.0f);994EXPECT_FLOAT_EQ(av.z, 3.5f);995EXPECT_FLOAT_EQ(av.w, 4.5f);996997auto nv = v.neg();998EXPECT_FLOAT_EQ(nv.x, -1.0f);999EXPECT_FLOAT_EQ(nv.y, 2.0f);1000EXPECT_FLOAT_EQ(nv.z, -3.5f);1001EXPECT_FLOAT_EQ(nv.w, 4.5f);10021003auto fl = GSVector4(1.9f, -1.2f, 3.01f, -3.99f).floor();1004EXPECT_FLOAT_EQ(fl.x, 1.0f);1005EXPECT_FLOAT_EQ(fl.y, -2.0f);1006EXPECT_FLOAT_EQ(fl.z, 3.0f);1007EXPECT_FLOAT_EQ(fl.w, -4.0f);10081009auto cl = GSVector4(1.1f, -1.2f, 3.01f, -3.99f).ceil();1010EXPECT_FLOAT_EQ(cl.x, 2.0f);1011EXPECT_FLOAT_EQ(cl.y, -1.0f);1012EXPECT_FLOAT_EQ(cl.z, 4.0f);1013EXPECT_FLOAT_EQ(cl.w, -3.0f);10141015// sat(scale)1016auto sat_scaled = GSVector4(-5.0f, 10.0f, 500.0f, 260.0f).sat(255.0f);1017EXPECT_FLOAT_EQ(sat_scaled.x, 0.0f);1018EXPECT_FLOAT_EQ(sat_scaled.y, 10.0f);1019EXPECT_FLOAT_EQ(sat_scaled.z, 255.0f);1020EXPECT_FLOAT_EQ(sat_scaled.w, 255.0f);10211022// sat(minmax vector) : x/z clamped to [min.x, min.z], y/w to [min.y, min.w]1023GSVector4 range(0.0f, -1.0f, 2.0f, 1.0f);1024auto sat_pair = v.sat(range);1025EXPECT_FLOAT_EQ(sat_pair.x, 1.0f); // within [0,2]1026EXPECT_FLOAT_EQ(sat_pair.y, -1.0f); // clamped to -11027EXPECT_FLOAT_EQ(sat_pair.z, 2.0f); // clamped to 21028EXPECT_FLOAT_EQ(sat_pair.w, -1.0f); // clamped to -11029}10301031TEST(GSVector4Test, BlendAndMask)1032{1033GSVector4 a(1, 2, 3, 4);1034GSVector4 b(5, 6, 7, 8);10351036// Template blend32<mask> (selects only lanes 0/1 from the 'v' argument per bit)1037auto tb = a.blend32<0b1010>(b);1038EXPECT_FLOAT_EQ(tb.x, 1.0f); // bit0 = 0 -> v[0]1039EXPECT_FLOAT_EQ(tb.y, 6.0f); // bit1 = 1 -> v[1]1040EXPECT_FLOAT_EQ(tb.z, 3.0f); // bit2 = 0 -> v[0]1041EXPECT_FLOAT_EQ(tb.w, 8.0f); // bit3 = 1 -> v[1]10421043// Masked blend: high bit set -> take from second vector argument (b); else from 'a'1044GSVector4 mask;1045mask.U32[0] = 0x00000000u;1046mask.U32[1] = 0x80000000u;1047mask.U32[2] = 0x00000000u;1048mask.U32[3] = 0x80000000u;1049auto mb = a.blend32(b, mask);1050EXPECT_FLOAT_EQ(mb.x, a.x);1051EXPECT_FLOAT_EQ(mb.y, b.y);1052EXPECT_FLOAT_EQ(mb.z, a.z);1053EXPECT_FLOAT_EQ(mb.w, b.w);10541055// mask() bit packing (bits 31,23,15,7)1056GSVector4 m;1057m.U32[0] = 0x80000000u; // sets bit 01058m.U32[1] = 0x40000000u; // sets bit 11059m.U32[2] = 0x20000000u; // sets bit 21060m.U32[3] = 0x10000000u; // sets bit 31061EXPECT_EQ(m.mask(), 0x1);1062}10631064TEST(GSVector4Test, HorizontalAndInterleave)1065{1066GSVector4 v(1, 2, 10, 20);1067auto hadd0 = v.hadd();1068EXPECT_FLOAT_EQ(hadd0.x, 3);1069EXPECT_FLOAT_EQ(hadd0.y, 30);1070EXPECT_FLOAT_EQ(hadd0.z, 3);1071EXPECT_FLOAT_EQ(hadd0.w, 30);10721073auto hsub0 = v.hsub();1074EXPECT_FLOAT_EQ(hsub0.x, -1);1075EXPECT_FLOAT_EQ(hsub0.y, -10);1076EXPECT_FLOAT_EQ(hsub0.z, -1);1077EXPECT_FLOAT_EQ(hsub0.w, -10);10781079GSVector4 v2(3, 4, 5, 6);1080auto hadd1 = v.hadd(v2);1081EXPECT_FLOAT_EQ(hadd1.x, 3);1082EXPECT_FLOAT_EQ(hadd1.y, 30);1083EXPECT_FLOAT_EQ(hadd1.z, 7);1084EXPECT_FLOAT_EQ(hadd1.w, 11);10851086auto hsub1 = v.hsub(v2);1087EXPECT_FLOAT_EQ(hsub1.x, -1);1088EXPECT_FLOAT_EQ(hsub1.y, -10);1089EXPECT_FLOAT_EQ(hsub1.z, -1);1090EXPECT_FLOAT_EQ(hsub1.w, -1);10911092// Interleave / low-high helpers1093GSVector4 a(1, 2, 3, 4);1094GSVector4 b(5, 6, 7, 8);1095auto upl = a.upl(b);1096EXPECT_FLOAT_EQ(upl.x, 1);1097EXPECT_FLOAT_EQ(upl.y, 5);1098EXPECT_FLOAT_EQ(upl.z, 2);1099EXPECT_FLOAT_EQ(upl.w, 6);1100auto uph = a.uph(b);1101EXPECT_FLOAT_EQ(uph.x, 3);1102EXPECT_FLOAT_EQ(uph.y, 7);1103EXPECT_FLOAT_EQ(uph.z, 4);1104EXPECT_FLOAT_EQ(uph.w, 8);1105auto l2h = a.l2h(b);1106EXPECT_FLOAT_EQ(l2h.x, 1);1107EXPECT_FLOAT_EQ(l2h.y, 2);1108EXPECT_FLOAT_EQ(l2h.z, 5);1109EXPECT_FLOAT_EQ(l2h.w, 6);1110auto h2l = a.h2l(b);1111EXPECT_FLOAT_EQ(h2l.x, 7);1112EXPECT_FLOAT_EQ(h2l.y, 8);1113EXPECT_FLOAT_EQ(h2l.z, 3);1114EXPECT_FLOAT_EQ(h2l.w, 4);1115}11161117TEST(GSVector4Test, BroadcastAndInsertExtract)1118{1119GSVector4 v(9, 2, 3, 4);1120auto bc_self = v.broadcast32();1121EXPECT_FLOAT_EQ(bc_self.x, 9);1122EXPECT_FLOAT_EQ(bc_self.y, 9);1123EXPECT_FLOAT_EQ(bc_self.z, 9);1124EXPECT_FLOAT_EQ(bc_self.w, 9);11251126auto bc_static = GSVector4::broadcast32(v);1127EXPECT_FLOAT_EQ(bc_static.z, 9);11281129GSVector4 a(1, 2, 3, 4);1130GSVector4 b(5, 6, 7, 8);1131auto ins_from_other = a.insert32<2, 0>(b); // copy b.z into a.x1132EXPECT_FLOAT_EQ(ins_from_other.x, 7);1133EXPECT_FLOAT_EQ(ins_from_other.y, 2);1134EXPECT_FLOAT_EQ(ins_from_other.z, 3);1135EXPECT_FLOAT_EQ(ins_from_other.w, 4);11361137auto ins_scalar = a.insert32<1>(42.0f);1138EXPECT_FLOAT_EQ(ins_scalar.x, 1);1139EXPECT_FLOAT_EQ(ins_scalar.y, 42.0f);1140EXPECT_FLOAT_EQ(ins_scalar.z, 3);1141EXPECT_FLOAT_EQ(ins_scalar.w, 4);11421143EXPECT_FLOAT_EQ(a.extract32<0>(), 1.0f);1144EXPECT_FLOAT_EQ(a.extract32<3>(), 4.0f);1145}11461147TEST(GSVector4Test, BitwiseAndAndNot)1148{1149GSVector4 a;1150a.U32[0] = 0xFFFFFFFFu;1151a.U32[1] = 0x00FF00FFu;1152a.U32[2] = 0x12345678u;1153a.U32[3] = 0xAAAAAAAAu;11541155GSVector4 b;1156b.U32[0] = 0x0F0F0F0Fu;1157b.U32[1] = 0xFF00FF00u;1158b.U32[2] = 0xFFFFFFFFu;1159b.U32[3] = 0x55555555u;11601161auto vand = a & b;1162EXPECT_EQ(vand.U32[0], 0x0F0F0F0Fu);1163EXPECT_EQ(vand.U32[1], 0x00000000u);1164EXPECT_EQ(vand.U32[2], 0x12345678u);1165EXPECT_EQ(vand.U32[3], 0x00000000u);11661167auto vor = a | b;1168EXPECT_EQ(vor.U32[0], 0xFFFFFFFFu);1169EXPECT_EQ(vor.U32[1], 0xFFFFFFFFu);1170EXPECT_EQ(vor.U32[2], 0xFFFFFFFFu);1171EXPECT_EQ(vor.U32[3], 0xFFFFFFFFu);11721173auto vxor = a ^ b;1174EXPECT_EQ(vxor.U32[0], 0xF0F0F0F0u);1175EXPECT_EQ(vxor.U32[1], 0xFFFFFFFFu);1176EXPECT_EQ(vxor.U32[2], 0xEDCBA987u);1177EXPECT_EQ(vxor.U32[3], 0xFFFFFFFFu);11781179auto an = a.andnot(b); // (~b) & a1180EXPECT_EQ(an.U32[0], (~b.U32[0]) & a.U32[0]);1181EXPECT_EQ(an.U32[1], (~b.U32[1]) & a.U32[1]);1182EXPECT_EQ(an.U32[2], (~b.U32[2]) & a.U32[2]);1183EXPECT_EQ(an.U32[3], (~b.U32[3]) & a.U32[3]);1184}11851186TEST(GSVector4Test, ReplaceNaN)1187{1188GSVector4 v(1.0f, std::numeric_limits<float>::quiet_NaN(), -5.0f, std::numeric_limits<float>::quiet_NaN());1189GSVector4 repl(10.0f, 20.0f, 30.0f, 40.0f);1190auto r = v.replace_nan(repl);1191EXPECT_FLOAT_EQ(r.x, 1.0f); // kept1192EXPECT_FLOAT_EQ(r.y, 20.0f); // replaced1193EXPECT_FLOAT_EQ(r.z, -5.0f); // kept1194EXPECT_FLOAT_EQ(r.w, 40.0f); // replaced1195}11961197TEST(GSVector4Test, DoubleExtendedOps)1198{1199GSVector4 d = GSVector4::f64(-4.0, 9.0);1200auto sq = d.sqr64();1201EXPECT_DOUBLE_EQ(sq.F64[0], 16.0);1202EXPECT_DOUBLE_EQ(sq.F64[1], 81.0);12031204auto rt = GSVector4::f64(4.0, 9.0).sqrt64();1205EXPECT_DOUBLE_EQ(rt.F64[0], 2.0);1206EXPECT_DOUBLE_EQ(rt.F64[1], 3.0);12071208auto ab = d.abs64();1209EXPECT_DOUBLE_EQ(ab.F64[0], 4.0);1210EXPECT_DOUBLE_EQ(ab.F64[1], 9.0);12111212auto ng = d.neg64();1213EXPECT_DOUBLE_EQ(ng.F64[0], 4.0);1214EXPECT_DOUBLE_EQ(ng.F64[1], -9.0);12151216GSVector4 d2 = GSVector4::f64(-2.0, 10.0);1217EXPECT_DOUBLE_EQ(d.min64(d2).F64[0], -4.0);1218EXPECT_DOUBLE_EQ(d.min64(d2).F64[1], 9.0);1219EXPECT_DOUBLE_EQ(d.max64(d2).F64[0], -2.0);1220EXPECT_DOUBLE_EQ(d.max64(d2).F64[1], 10.0);12211222auto gt = d.gt64(d2);1223EXPECT_EQ(gt.U64[0], 0ULL); // -4 > -2 ? no1224EXPECT_EQ(gt.U64[1], 0ULL); // 9 > 10 ? no1225auto lt = d.lt64(d2);1226EXPECT_NE(lt.U64[0], 0ULL); // -4 < -21227EXPECT_NE(lt.U64[1], 0ULL); // 9 < 101228auto ge = d.ge64(d2);1229EXPECT_EQ(ge.U64[0], 0ULL); // -4 >= -2 ? no1230EXPECT_EQ(ge.U64[1], 0ULL); // 9 >= 10 ? no1231auto le = d.le64(d2);1232EXPECT_NE(le.U64[0], 0ULL);1233EXPECT_NE(le.U64[1], 0ULL);1234auto eq = d.eq64(d);1235EXPECT_EQ(eq.U64[0], 0xFFFFFFFFFFFFFFFFULL);1236EXPECT_EQ(eq.U64[1], 0xFFFFFFFFFFFFFFFFULL);1237}12381239TEST(GSVector4Test, FloatToDoubleConversions)1240{1241GSVector4 vf(1.25f, 2.75f, 3.0f, 4.0f);1242auto fd = GSVector4::f32to64(vf);1243EXPECT_DOUBLE_EQ(fd.F64[0], 1.25);1244EXPECT_DOUBLE_EQ(fd.F64[1], 2.75);12451246GSVector4 vd = GSVector4::f64(5.9, -2.1);1247auto i32 = vd.f64toi32();1248EXPECT_EQ(i32.S32[0], 5);1249EXPECT_EQ(i32.S32[1], -2);1250}12511252// Cross-class conversion tests1253TEST(GSVectorTest, ConversionsGSVector2iGSVector2)1254{1255GSVector2i vi(42, 84);1256GSVector2 vf(vi);1257EXPECT_FLOAT_EQ(vf.x, 42.0f);1258EXPECT_FLOAT_EQ(vf.y, 84.0f);12591260GSVector2 vf2(3.14f, 2.71f);1261GSVector2i vi2(vf2);1262EXPECT_EQ(vi2.x, 3);1263EXPECT_EQ(vi2.y, 2);12641265// Test cast operations1266auto cast_result = GSVector2::cast(vi);1267// Cast preserves bit pattern, so we can't directly compare float values1268EXPECT_EQ(cast_result.I32[0], 42);1269EXPECT_EQ(cast_result.I32[1], 84);12701271auto cast_result2 = GSVector2i::cast(vf2);1272// Cast preserves bit pattern1273EXPECT_EQ(cast_result2.U32[0], vf2.U32[0]);1274EXPECT_EQ(cast_result2.U32[1], vf2.U32[1]);1275}127612771278