From 32e1de9778c160c9aeb474fc55fc56465866d3d4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 01:29:34 +0000 Subject: [PATCH 1/9] Initial plan From 2d3d05b8c99a181c793b83c25ead0be12b56c638 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 01:34:29 +0000 Subject: [PATCH 2/9] Add SIMD support to math library with macro-controlled SSE/NEON paths - Add SKY_MATH_SIMD CMake option (ON by default) in cmake/options.cmake - Add SKY_MATH_SIMD compile definition in cmake/configuration.cmake - Create MathSimd.h with platform detection for SSE (x86) and NEON (ARM) - Add __m128/float32x4_t SIMD member to Vector4 union with alignas(16) - Optimize Vector4 operators (+=, -=, *=, /=, Dot, Normalize) with SIMD - Optimize Matrix4 multiply (mat*mat, mat*vec) with SIMD - Add comprehensive math unit tests for Vector4 and Matrix4 operations Co-authored-by: bluesky013 <35895395+bluesky013@users.noreply.github.com> --- cmake/configuration.cmake | 4 + cmake/options.cmake | 3 +- runtime/core/include/core/math/MathSimd.h | 31 ++++++ runtime/core/include/core/math/Matrix4.inl | 44 +++++++++ runtime/core/include/core/math/Vector4.h | 8 +- runtime/core/include/core/math/Vector4.inl | 68 +++++++++++++ test/core/MathTest.cpp | 105 +++++++++++++++++++++ 7 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 runtime/core/include/core/math/MathSimd.h diff --git a/cmake/configuration.cmake b/cmake/configuration.cmake index 99a6d582..c4f06e72 100644 --- a/cmake/configuration.cmake +++ b/cmake/configuration.cmake @@ -27,3 +27,7 @@ if (SKY_EDITOR OR SKY_BUILD_TOOL) endif () add_compile_definitions("$<$:_DEBUG;DEBUG>") + +if (SKY_MATH_SIMD) + add_compile_definitions(SKY_MATH_SIMD=1) +endif () diff --git a/cmake/options.cmake b/cmake/options.cmake index b64b2c7f..07ed35cd 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -13,4 +13,5 @@ option(SKY_USE_TRACY "use tracy profiler" OFF) # todo: controlled by project config json. option(SKY_BUILD_XR "xr plugin" OFF) -option(SKY_BUILD_PYTHON "python plugin" OFF) \ No newline at end of file +option(SKY_BUILD_PYTHON "python plugin" OFF) +option(SKY_MATH_SIMD "enable simd math" ON) \ No newline at end of file diff --git a/runtime/core/include/core/math/MathSimd.h b/runtime/core/include/core/math/MathSimd.h new file mode 100644 index 00000000..99814af2 --- /dev/null +++ b/runtime/core/include/core/math/MathSimd.h @@ -0,0 +1,31 @@ +// +// Created for SIMD math support. +// + +#pragma once + +// SIMD platform detection +#if defined(SKY_MATH_SIMD) && SKY_MATH_SIMD + + #if defined(__SSE__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1) + #define SKY_SIMD_SSE 1 + #include // SSE + #include // SSE2 + #endif + + #if defined(__ARM_NEON) || defined(__ARM_NEON__) + #define SKY_SIMD_NEON 1 + #include + #endif + +#endif + +#ifndef SKY_SIMD_SSE + #define SKY_SIMD_SSE 0 +#endif + +#ifndef SKY_SIMD_NEON + #define SKY_SIMD_NEON 0 +#endif + +#define SKY_SIMD_ENABLED (SKY_SIMD_SSE || SKY_SIMD_NEON) diff --git a/runtime/core/include/core/math/Matrix4.inl b/runtime/core/include/core/math/Matrix4.inl index 8d179025..4cf34bfa 100644 --- a/runtime/core/include/core/math/Matrix4.inl +++ b/runtime/core/include/core/math/Matrix4.inl @@ -32,6 +32,29 @@ namespace sky { inline Matrix4 Matrix4::operator*(const Matrix4& rhs) const { +#if SKY_SIMD_SSE + Matrix4 ret; + for (int i = 0; i < 4; ++i) { + __m128 e0 = _mm_set1_ps(rhs.m[i].v[0]); + __m128 e1 = _mm_set1_ps(rhs.m[i].v[1]); + __m128 e2 = _mm_set1_ps(rhs.m[i].v[2]); + __m128 e3 = _mm_set1_ps(rhs.m[i].v[3]); + ret.m[i].simd = _mm_add_ps( + _mm_add_ps(_mm_mul_ps(m[0].simd, e0), _mm_mul_ps(m[1].simd, e1)), + _mm_add_ps(_mm_mul_ps(m[2].simd, e2), _mm_mul_ps(m[3].simd, e3))); + } + return ret; +#elif SKY_SIMD_NEON + Matrix4 ret; + for (int i = 0; i < 4; ++i) { + float32x4_t r = vmulq_n_f32(m[0].simd, rhs.m[i].v[0]); + r = vmlaq_n_f32(r, m[1].simd, rhs.m[i].v[1]); + r = vmlaq_n_f32(r, m[2].simd, rhs.m[i].v[2]); + r = vmlaq_n_f32(r, m[3].simd, rhs.m[i].v[3]); + ret.m[i].simd = r; + } + return ret; +#else const auto& rw = rhs.m; Matrix4 ret; ret[0] = m[0] * rw[0][0] + m[1] * rw[0][1] + m[2] * rw[0][2] + m[3] * rw[0][3]; @@ -39,6 +62,7 @@ namespace sky { ret[2] = m[0] * rw[2][0] + m[1] * rw[2][1] + m[2] * rw[2][2] + m[3] * rw[2][3]; ret[3] = m[0] * rw[3][0] + m[1] * rw[3][1] + m[2] * rw[3][2] + m[3] * rw[3][3]; return ret; +#endif } inline Matrix4 Matrix4::operator*(float multiplier) const @@ -95,11 +119,31 @@ namespace sky { inline Vector4 Matrix4::operator*(const Vector4& rhs) const { +#if SKY_SIMD_SSE + __m128 e0 = _mm_set1_ps(rhs.v[0]); + __m128 e1 = _mm_set1_ps(rhs.v[1]); + __m128 e2 = _mm_set1_ps(rhs.v[2]); + __m128 e3 = _mm_set1_ps(rhs.v[3]); + Vector4 result; + result.simd = _mm_add_ps( + _mm_add_ps(_mm_mul_ps(m[0].simd, e0), _mm_mul_ps(m[1].simd, e1)), + _mm_add_ps(_mm_mul_ps(m[2].simd, e2), _mm_mul_ps(m[3].simd, e3))); + return result; +#elif SKY_SIMD_NEON + float32x4_t r = vmulq_n_f32(m[0].simd, rhs.v[0]); + r = vmlaq_n_f32(r, m[1].simd, rhs.v[1]); + r = vmlaq_n_f32(r, m[2].simd, rhs.v[2]); + r = vmlaq_n_f32(r, m[3].simd, rhs.v[3]); + Vector4 result; + result.simd = r; + return result; +#else Vector4 v0 = m[0] * rhs[0]; Vector4 v1 = m[1] * rhs[1]; Vector4 v2 = m[2] * rhs[2]; Vector4 v3 = m[3] * rhs[3]; return (v0 + v1) + (v2 + v3); +#endif } inline Vector4 &Matrix4::operator[](uint32_t i) diff --git a/runtime/core/include/core/math/Vector4.h b/runtime/core/include/core/math/Vector4.h index 0f9452ca..26713e1f 100644 --- a/runtime/core/include/core/math/Vector4.h +++ b/runtime/core/include/core/math/Vector4.h @@ -6,10 +6,11 @@ #pragma once #include "core/math/Math.h" +#include "core/math/MathSimd.h" namespace sky { - struct Vector4 { + struct alignas(16) Vector4 { union { float v[4]; struct { @@ -18,6 +19,11 @@ namespace sky { float z; float w; }; +#if SKY_SIMD_SSE + __m128 simd; +#elif SKY_SIMD_NEON + float32x4_t simd; +#endif }; inline constexpr Vector4(); diff --git a/runtime/core/include/core/math/Vector4.inl b/runtime/core/include/core/math/Vector4.inl index a770262a..5696f6bf 100644 --- a/runtime/core/include/core/math/Vector4.inl +++ b/runtime/core/include/core/math/Vector4.inl @@ -53,55 +53,92 @@ namespace sky { inline Vector4& Vector4::operator+=(const Vector4& rhs) { +#if SKY_SIMD_SSE + simd = _mm_add_ps(simd, rhs.simd); +#elif SKY_SIMD_NEON + simd = vaddq_f32(simd, rhs.simd); +#else x += rhs.x; y += rhs.y; z += rhs.z; w += rhs.w; +#endif return *this; } inline Vector4& Vector4::operator-=(const Vector4& rhs) { +#if SKY_SIMD_SSE + simd = _mm_sub_ps(simd, rhs.simd); +#elif SKY_SIMD_NEON + simd = vsubq_f32(simd, rhs.simd); +#else x -= rhs.x; y -= rhs.y; z -= rhs.z; w -= rhs.w; +#endif return *this; } inline Vector4& Vector4::operator*=(const Vector4& rhs) { +#if SKY_SIMD_SSE + simd = _mm_mul_ps(simd, rhs.simd); +#elif SKY_SIMD_NEON + simd = vmulq_f32(simd, rhs.simd); +#else x *= rhs.x; y *= rhs.y; z *= rhs.z; w *= rhs.w; +#endif return *this; } inline Vector4& Vector4::operator/=(const Vector4& rhs) { +#if SKY_SIMD_SSE + simd = _mm_div_ps(simd, rhs.simd); +#elif SKY_SIMD_NEON + simd = vdivq_f32(simd, rhs.simd); +#else x /= rhs.x; y /= rhs.y; z /= rhs.z; w /= rhs.w; +#endif return *this; } inline Vector4& Vector4::operator*=(float m) { +#if SKY_SIMD_SSE + simd = _mm_mul_ps(simd, _mm_set1_ps(m)); +#elif SKY_SIMD_NEON + simd = vmulq_n_f32(simd, m); +#else x *= m; y *= m; z *= m; w *= m; +#endif return *this; } inline Vector4& Vector4::operator/=(float d) { +#if SKY_SIMD_SSE + simd = _mm_div_ps(simd, _mm_set1_ps(d)); +#elif SKY_SIMD_NEON + float32x4_t dv = vdupq_n_f32(d); + simd = vdivq_f32(simd, dv); +#else x /= d; y /= d; z /= d; w /= d; +#endif return *this; } @@ -117,13 +154,44 @@ namespace sky { inline float Vector4::Dot(const Vector4 &rhs) const { +#if SKY_SIMD_SSE + __m128 mul = _mm_mul_ps(simd, rhs.simd); + __m128 shuf1 = _mm_shuffle_ps(mul, mul, _MM_SHUFFLE(2, 3, 0, 1)); + __m128 sums1 = _mm_add_ps(mul, shuf1); + __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); + __m128 sums2 = _mm_add_ps(sums1, shuf2); + return _mm_cvtss_f32(sums2); +#elif SKY_SIMD_NEON + float32x4_t mul = vmulq_f32(simd, rhs.simd); + float32x2_t sum = vadd_f32(vget_low_f32(mul), vget_high_f32(mul)); + sum = vpadd_f32(sum, sum); + return vget_lane_f32(sum, 0); +#else Vector4 ret = (*this) * rhs; return (ret.x + ret.y) + (ret.z + ret.w); +#endif } inline void Vector4::Normalize() { +#if SKY_SIMD_SSE + __m128 dot = _mm_mul_ps(simd, simd); + __m128 shuf1 = _mm_shuffle_ps(dot, dot, _MM_SHUFFLE(2, 3, 0, 1)); + __m128 sums1 = _mm_add_ps(dot, shuf1); + __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); + __m128 sums2 = _mm_add_ps(sums1, shuf2); + __m128 inv = _mm_rsqrt_ps(sums2); + simd = _mm_mul_ps(simd, inv); +#elif SKY_SIMD_NEON + float32x4_t mul = vmulq_f32(simd, simd); + float32x2_t sum = vadd_f32(vget_low_f32(mul), vget_high_f32(mul)); + sum = vpadd_f32(sum, sum); + float32x4_t dotVal = vdupq_lane_f32(sum, 0); + float32x4_t inv = vrsqrteq_f32(dotVal); + simd = vmulq_f32(simd, inv); +#else float inverseSqrt = 1 / sqrt(Dot(*this)); Vector4::operator*=(inverseSqrt); +#endif } } diff --git a/test/core/MathTest.cpp b/test/core/MathTest.cpp index 845fdb22..ef111c66 100644 --- a/test/core/MathTest.cpp +++ b/test/core/MathTest.cpp @@ -12,4 +12,109 @@ TEST(MathTest, MathUtilTest) for (uint32_t i = 0; i < 32; ++i) { ASSERT_EQ(CeilLog2(static_cast(pow(2, i))), i); } +} + +TEST(MathTest, Vector4Add) +{ + Vector4 a(1.0f, 2.0f, 3.0f, 4.0f); + Vector4 b(5.0f, 6.0f, 7.0f, 8.0f); + Vector4 c = a + b; + ASSERT_FLOAT_EQ(c.x, 6.0f); + ASSERT_FLOAT_EQ(c.y, 8.0f); + ASSERT_FLOAT_EQ(c.z, 10.0f); + ASSERT_FLOAT_EQ(c.w, 12.0f); +} + +TEST(MathTest, Vector4Sub) +{ + Vector4 a(5.0f, 6.0f, 7.0f, 8.0f); + Vector4 b(1.0f, 2.0f, 3.0f, 4.0f); + Vector4 c = a - b; + ASSERT_FLOAT_EQ(c.x, 4.0f); + ASSERT_FLOAT_EQ(c.y, 4.0f); + ASSERT_FLOAT_EQ(c.z, 4.0f); + ASSERT_FLOAT_EQ(c.w, 4.0f); +} + +TEST(MathTest, Vector4Mul) +{ + Vector4 a(1.0f, 2.0f, 3.0f, 4.0f); + Vector4 b(5.0f, 6.0f, 7.0f, 8.0f); + Vector4 c = a * b; + ASSERT_FLOAT_EQ(c.x, 5.0f); + ASSERT_FLOAT_EQ(c.y, 12.0f); + ASSERT_FLOAT_EQ(c.z, 21.0f); + ASSERT_FLOAT_EQ(c.w, 32.0f); +} + +TEST(MathTest, Vector4Div) +{ + Vector4 a(10.0f, 12.0f, 21.0f, 32.0f); + Vector4 b(5.0f, 6.0f, 7.0f, 8.0f); + Vector4 c = a / b; + ASSERT_FLOAT_EQ(c.x, 2.0f); + ASSERT_FLOAT_EQ(c.y, 2.0f); + ASSERT_FLOAT_EQ(c.z, 3.0f); + ASSERT_FLOAT_EQ(c.w, 4.0f); +} + +TEST(MathTest, Vector4ScalarMul) +{ + Vector4 a(1.0f, 2.0f, 3.0f, 4.0f); + Vector4 c = a * 3.0f; + ASSERT_FLOAT_EQ(c.x, 3.0f); + ASSERT_FLOAT_EQ(c.y, 6.0f); + ASSERT_FLOAT_EQ(c.z, 9.0f); + ASSERT_FLOAT_EQ(c.w, 12.0f); +} + +TEST(MathTest, Vector4ScalarDiv) +{ + Vector4 a(2.0f, 4.0f, 6.0f, 8.0f); + Vector4 c = a / 2.0f; + ASSERT_FLOAT_EQ(c.x, 1.0f); + ASSERT_FLOAT_EQ(c.y, 2.0f); + ASSERT_FLOAT_EQ(c.z, 3.0f); + ASSERT_FLOAT_EQ(c.w, 4.0f); +} + +TEST(MathTest, Vector4Dot) +{ + Vector4 a(1.0f, 2.0f, 3.0f, 4.0f); + Vector4 b(5.0f, 6.0f, 7.0f, 8.0f); + float dot = a.Dot(b); + ASSERT_FLOAT_EQ(dot, 70.0f); +} + +TEST(MathTest, Vector4Negate) +{ + Vector4 a(1.0f, 2.0f, 3.0f, 4.0f); + Vector4 c = -a; + ASSERT_FLOAT_EQ(c.x, -1.0f); + ASSERT_FLOAT_EQ(c.y, -2.0f); + ASSERT_FLOAT_EQ(c.z, -3.0f); + ASSERT_FLOAT_EQ(c.w, -4.0f); +} + +TEST(MathTest, Matrix4VecMul) +{ + Matrix4 id = Matrix4::Identity(); + Vector4 v(1.0f, 2.0f, 3.0f, 4.0f); + Vector4 r = id * v; + ASSERT_FLOAT_EQ(r.x, 1.0f); + ASSERT_FLOAT_EQ(r.y, 2.0f); + ASSERT_FLOAT_EQ(r.z, 3.0f); + ASSERT_FLOAT_EQ(r.w, 4.0f); +} + +TEST(MathTest, Matrix4MatMul) +{ + Matrix4 id = Matrix4::Identity(); + Matrix4 r = id * id; + ASSERT_FLOAT_EQ(r[0][0], 1.0f); + ASSERT_FLOAT_EQ(r[1][1], 1.0f); + ASSERT_FLOAT_EQ(r[2][2], 1.0f); + ASSERT_FLOAT_EQ(r[3][3], 1.0f); + ASSERT_FLOAT_EQ(r[0][1], 0.0f); + ASSERT_FLOAT_EQ(r[1][0], 0.0f); } \ No newline at end of file From 39d23cff58ef1059827edc62f160424587710582 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 01:35:19 +0000 Subject: [PATCH 3/9] Add Newton-Raphson refinement to SIMD normalize for improved precision Co-authored-by: bluesky013 <35895395+bluesky013@users.noreply.github.com> --- runtime/core/include/core/math/Vector4.inl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/runtime/core/include/core/math/Vector4.inl b/runtime/core/include/core/math/Vector4.inl index 5696f6bf..487987b8 100644 --- a/runtime/core/include/core/math/Vector4.inl +++ b/runtime/core/include/core/math/Vector4.inl @@ -181,6 +181,11 @@ namespace sky { __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); __m128 sums2 = _mm_add_ps(sums1, shuf2); __m128 inv = _mm_rsqrt_ps(sums2); + // Newton-Raphson refinement: inv = inv * (1.5 - 0.5 * sums2 * inv * inv) + __m128 half = _mm_set1_ps(0.5f); + __m128 three_half = _mm_set1_ps(1.5f); + __m128 muls = _mm_mul_ps(_mm_mul_ps(half, sums2), _mm_mul_ps(inv, inv)); + inv = _mm_mul_ps(inv, _mm_sub_ps(three_half, muls)); simd = _mm_mul_ps(simd, inv); #elif SKY_SIMD_NEON float32x4_t mul = vmulq_f32(simd, simd); @@ -188,6 +193,8 @@ namespace sky { sum = vpadd_f32(sum, sum); float32x4_t dotVal = vdupq_lane_f32(sum, 0); float32x4_t inv = vrsqrteq_f32(dotVal); + // Newton-Raphson refinement + inv = vmulq_f32(inv, vrsqrtsq_f32(vmulq_f32(dotVal, inv), inv)); simd = vmulq_f32(simd, inv); #else float inverseSqrt = 1 / sqrt(Dot(*this)); From 8a65857a09e8978017df82fa58add791be863f1b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 01:35:46 +0000 Subject: [PATCH 4/9] Final: SIMD math library support complete Co-authored-by: bluesky013 <35895395+bluesky013@users.noreply.github.com> --- _codeql_detected_source_root | 1 + 1 file changed, 1 insertion(+) create mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 00000000..945c9b46 --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file From 3d675e38589e4fc2904707984aec02bfe6c628bb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 01:36:03 +0000 Subject: [PATCH 5/9] Remove codeql artifact and add to .gitignore Co-authored-by: bluesky013 <35895395+bluesky013@users.noreply.github.com> --- .gitignore | 1 + _codeql_detected_source_root | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 120000 _codeql_detected_source_root diff --git a/.gitignore b/.gitignore index 9309668d..a38f0748 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ /active_project /test/assets/assets.db /test/products/ +_codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root deleted file mode 120000 index 945c9b46..00000000 --- a/_codeql_detected_source_root +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file From ea81ce41c4390dc62447e8af70fd15970572cb52 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 02:03:01 +0000 Subject: [PATCH 6/9] Split SIMD data types: extract SFloat4 abstraction from Vector4/Matrix4 - Create SFloat4.h: platform-agnostic SIMD float4 type wrapping __m128 (SSE), float32x4_t (NEON), or scalar fallback with Load/Store/Set/Splat, arithmetic operators, HorizontalSum, HorizontalSumSplat, InvSqrt - Refactor Vector4.h: remove inline __m128/float32x4_t from union, include SFloat4.h instead of MathSimd.h directly - Refactor Vector4.inl: replace #if SSE/#elif NEON branches with unified #if SKY_SIMD_ENABLED using SFloat4 operations - Refactor Matrix4.inl: replace #if SSE/#elif NEON branches with unified #if SKY_SIMD_ENABLED using SFloat4 operations Co-authored-by: bluesky013 <35895395+bluesky013@users.noreply.github.com> --- runtime/core/include/core/math/Matrix4.inl | 46 ++---- runtime/core/include/core/math/SFloat4.h | 161 +++++++++++++++++++++ runtime/core/include/core/math/Vector4.h | 7 +- runtime/core/include/core/math/Vector4.inl | 92 +++++------- 4 files changed, 207 insertions(+), 99 deletions(-) create mode 100644 runtime/core/include/core/math/SFloat4.h diff --git a/runtime/core/include/core/math/Matrix4.inl b/runtime/core/include/core/math/Matrix4.inl index 4cf34bfa..6536062d 100644 --- a/runtime/core/include/core/math/Matrix4.inl +++ b/runtime/core/include/core/math/Matrix4.inl @@ -32,26 +32,14 @@ namespace sky { inline Matrix4 Matrix4::operator*(const Matrix4& rhs) const { -#if SKY_SIMD_SSE +#if SKY_SIMD_ENABLED Matrix4 ret; for (int i = 0; i < 4; ++i) { - __m128 e0 = _mm_set1_ps(rhs.m[i].v[0]); - __m128 e1 = _mm_set1_ps(rhs.m[i].v[1]); - __m128 e2 = _mm_set1_ps(rhs.m[i].v[2]); - __m128 e3 = _mm_set1_ps(rhs.m[i].v[3]); - ret.m[i].simd = _mm_add_ps( - _mm_add_ps(_mm_mul_ps(m[0].simd, e0), _mm_mul_ps(m[1].simd, e1)), - _mm_add_ps(_mm_mul_ps(m[2].simd, e2), _mm_mul_ps(m[3].simd, e3))); - } - return ret; -#elif SKY_SIMD_NEON - Matrix4 ret; - for (int i = 0; i < 4; ++i) { - float32x4_t r = vmulq_n_f32(m[0].simd, rhs.m[i].v[0]); - r = vmlaq_n_f32(r, m[1].simd, rhs.m[i].v[1]); - r = vmlaq_n_f32(r, m[2].simd, rhs.m[i].v[2]); - r = vmlaq_n_f32(r, m[3].simd, rhs.m[i].v[3]); - ret.m[i].simd = r; + SFloat4 r = SFloat4::Load(m[0].v) * SFloat4::Splat(rhs.m[i].v[0]); + r += SFloat4::Load(m[1].v) * SFloat4::Splat(rhs.m[i].v[1]); + r += SFloat4::Load(m[2].v) * SFloat4::Splat(rhs.m[i].v[2]); + r += SFloat4::Load(m[3].v) * SFloat4::Splat(rhs.m[i].v[3]); + r.Store(ret.m[i].v); } return ret; #else @@ -119,23 +107,13 @@ namespace sky { inline Vector4 Matrix4::operator*(const Vector4& rhs) const { -#if SKY_SIMD_SSE - __m128 e0 = _mm_set1_ps(rhs.v[0]); - __m128 e1 = _mm_set1_ps(rhs.v[1]); - __m128 e2 = _mm_set1_ps(rhs.v[2]); - __m128 e3 = _mm_set1_ps(rhs.v[3]); - Vector4 result; - result.simd = _mm_add_ps( - _mm_add_ps(_mm_mul_ps(m[0].simd, e0), _mm_mul_ps(m[1].simd, e1)), - _mm_add_ps(_mm_mul_ps(m[2].simd, e2), _mm_mul_ps(m[3].simd, e3))); - return result; -#elif SKY_SIMD_NEON - float32x4_t r = vmulq_n_f32(m[0].simd, rhs.v[0]); - r = vmlaq_n_f32(r, m[1].simd, rhs.v[1]); - r = vmlaq_n_f32(r, m[2].simd, rhs.v[2]); - r = vmlaq_n_f32(r, m[3].simd, rhs.v[3]); +#if SKY_SIMD_ENABLED + SFloat4 r = SFloat4::Load(m[0].v) * SFloat4::Splat(rhs.v[0]); + r += SFloat4::Load(m[1].v) * SFloat4::Splat(rhs.v[1]); + r += SFloat4::Load(m[2].v) * SFloat4::Splat(rhs.v[2]); + r += SFloat4::Load(m[3].v) * SFloat4::Splat(rhs.v[3]); Vector4 result; - result.simd = r; + r.Store(result.v); return result; #else Vector4 v0 = m[0] * rhs[0]; diff --git a/runtime/core/include/core/math/SFloat4.h b/runtime/core/include/core/math/SFloat4.h new file mode 100644 index 00000000..054763ff --- /dev/null +++ b/runtime/core/include/core/math/SFloat4.h @@ -0,0 +1,161 @@ +// +// Created for SIMD math support. +// + +#pragma once + +#include "core/math/MathSimd.h" +#include + +namespace sky { + +#if SKY_SIMD_SSE + + struct SFloat4 { + __m128 value; + + SFloat4() = default; + explicit SFloat4(__m128 v) : value(v) {} + + static inline SFloat4 Load(const float *p) { return SFloat4(_mm_loadu_ps(p)); } + static inline SFloat4 Set(float x, float y, float z, float w) { return SFloat4(_mm_set_ps(w, z, y, x)); } + static inline SFloat4 Splat(float v) { return SFloat4(_mm_set1_ps(v)); } + + inline void Store(float *p) const { _mm_storeu_ps(p, value); } + + inline SFloat4 operator+(const SFloat4 &rhs) const { return SFloat4(_mm_add_ps(value, rhs.value)); } + inline SFloat4 operator-(const SFloat4 &rhs) const { return SFloat4(_mm_sub_ps(value, rhs.value)); } + inline SFloat4 operator*(const SFloat4 &rhs) const { return SFloat4(_mm_mul_ps(value, rhs.value)); } + inline SFloat4 operator/(const SFloat4 &rhs) const { return SFloat4(_mm_div_ps(value, rhs.value)); } + + inline SFloat4 &operator+=(const SFloat4 &rhs) { value = _mm_add_ps(value, rhs.value); return *this; } + inline SFloat4 &operator-=(const SFloat4 &rhs) { value = _mm_sub_ps(value, rhs.value); return *this; } + inline SFloat4 &operator*=(const SFloat4 &rhs) { value = _mm_mul_ps(value, rhs.value); return *this; } + inline SFloat4 &operator/=(const SFloat4 &rhs) { value = _mm_div_ps(value, rhs.value); return *this; } + + static inline float HorizontalSum(const SFloat4 &v) + { + __m128 shuf1 = _mm_shuffle_ps(v.value, v.value, _MM_SHUFFLE(2, 3, 0, 1)); + __m128 sums1 = _mm_add_ps(v.value, shuf1); + __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); + __m128 sums2 = _mm_add_ps(sums1, shuf2); + return _mm_cvtss_f32(sums2); + } + + static inline SFloat4 HorizontalSumSplat(const SFloat4 &v) + { + __m128 shuf1 = _mm_shuffle_ps(v.value, v.value, _MM_SHUFFLE(2, 3, 0, 1)); + __m128 sums1 = _mm_add_ps(v.value, shuf1); + __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); + return SFloat4(_mm_add_ps(sums1, shuf2)); + } + + static inline SFloat4 InvSqrt(const SFloat4 &v) + { + __m128 inv = _mm_rsqrt_ps(v.value); + // Newton-Raphson refinement: inv = inv * (1.5 - 0.5 * v * inv * inv) + __m128 half = _mm_set1_ps(0.5f); + __m128 three_half = _mm_set1_ps(1.5f); + __m128 muls = _mm_mul_ps(_mm_mul_ps(half, v.value), _mm_mul_ps(inv, inv)); + inv = _mm_mul_ps(inv, _mm_sub_ps(three_half, muls)); + return SFloat4(inv); + } + }; + +#elif SKY_SIMD_NEON + + struct SFloat4 { + float32x4_t value; + + SFloat4() = default; + explicit SFloat4(float32x4_t v) : value(v) {} + + static inline SFloat4 Load(const float *p) { return SFloat4(vld1q_f32(p)); } + static inline SFloat4 Set(float x, float y, float z, float w) + { + float data[4] = {x, y, z, w}; + return SFloat4(vld1q_f32(data)); + } + static inline SFloat4 Splat(float v) { return SFloat4(vdupq_n_f32(v)); } + + inline void Store(float *p) const { vst1q_f32(p, value); } + + inline SFloat4 operator+(const SFloat4 &rhs) const { return SFloat4(vaddq_f32(value, rhs.value)); } + inline SFloat4 operator-(const SFloat4 &rhs) const { return SFloat4(vsubq_f32(value, rhs.value)); } + inline SFloat4 operator*(const SFloat4 &rhs) const { return SFloat4(vmulq_f32(value, rhs.value)); } + inline SFloat4 operator/(const SFloat4 &rhs) const { return SFloat4(vdivq_f32(value, rhs.value)); } + + inline SFloat4 &operator+=(const SFloat4 &rhs) { value = vaddq_f32(value, rhs.value); return *this; } + inline SFloat4 &operator-=(const SFloat4 &rhs) { value = vsubq_f32(value, rhs.value); return *this; } + inline SFloat4 &operator*=(const SFloat4 &rhs) { value = vmulq_f32(value, rhs.value); return *this; } + inline SFloat4 &operator/=(const SFloat4 &rhs) { value = vdivq_f32(value, rhs.value); return *this; } + + static inline float HorizontalSum(const SFloat4 &v) + { + float32x2_t sum = vadd_f32(vget_low_f32(v.value), vget_high_f32(v.value)); + sum = vpadd_f32(sum, sum); + return vget_lane_f32(sum, 0); + } + + static inline SFloat4 HorizontalSumSplat(const SFloat4 &v) + { + float32x2_t sum = vadd_f32(vget_low_f32(v.value), vget_high_f32(v.value)); + sum = vpadd_f32(sum, sum); + return SFloat4(vdupq_lane_f32(sum, 0)); + } + + static inline SFloat4 InvSqrt(const SFloat4 &v) + { + float32x4_t inv = vrsqrteq_f32(v.value); + // Newton-Raphson refinement + inv = vmulq_f32(inv, vrsqrtsq_f32(vmulq_f32(v.value, inv), inv)); + return SFloat4(inv); + } + }; + +#else + + struct SFloat4 { + float value[4]; + + SFloat4() = default; + + static inline SFloat4 Load(const float *p) { SFloat4 r; r.value[0] = p[0]; r.value[1] = p[1]; r.value[2] = p[2]; r.value[3] = p[3]; return r; } + static inline SFloat4 Set(float x, float y, float z, float w) { SFloat4 r; r.value[0] = x; r.value[1] = y; r.value[2] = z; r.value[3] = w; return r; } + static inline SFloat4 Splat(float v) { SFloat4 r; r.value[0] = r.value[1] = r.value[2] = r.value[3] = v; return r; } + + inline void Store(float *p) const { p[0] = value[0]; p[1] = value[1]; p[2] = value[2]; p[3] = value[3]; } + + inline SFloat4 operator+(const SFloat4 &rhs) const { return SFloat4(*this) += rhs; } + inline SFloat4 operator-(const SFloat4 &rhs) const { return SFloat4(*this) -= rhs; } + inline SFloat4 operator*(const SFloat4 &rhs) const { return SFloat4(*this) *= rhs; } + inline SFloat4 operator/(const SFloat4 &rhs) const { return SFloat4(*this) /= rhs; } + + inline SFloat4 &operator+=(const SFloat4 &rhs) { for (int i = 0; i < 4; ++i) value[i] += rhs.value[i]; return *this; } + inline SFloat4 &operator-=(const SFloat4 &rhs) { for (int i = 0; i < 4; ++i) value[i] -= rhs.value[i]; return *this; } + inline SFloat4 &operator*=(const SFloat4 &rhs) { for (int i = 0; i < 4; ++i) value[i] *= rhs.value[i]; return *this; } + inline SFloat4 &operator/=(const SFloat4 &rhs) { for (int i = 0; i < 4; ++i) value[i] /= rhs.value[i]; return *this; } + + static inline float HorizontalSum(const SFloat4 &v) + { + return (v.value[0] + v.value[1]) + (v.value[2] + v.value[3]); + } + + static inline SFloat4 HorizontalSumSplat(const SFloat4 &v) + { + return Splat(HorizontalSum(v)); + } + + static inline SFloat4 InvSqrt(const SFloat4 &v) + { + SFloat4 r; + for (int i = 0; i < 4; ++i) { + r.value[i] = 1.0f / std::sqrt(v.value[i]); + } + return r; + } + }; + +#endif + +} // namespace sky diff --git a/runtime/core/include/core/math/Vector4.h b/runtime/core/include/core/math/Vector4.h index 26713e1f..fa35a1b6 100644 --- a/runtime/core/include/core/math/Vector4.h +++ b/runtime/core/include/core/math/Vector4.h @@ -6,7 +6,7 @@ #pragma once #include "core/math/Math.h" -#include "core/math/MathSimd.h" +#include "core/math/SFloat4.h" namespace sky { @@ -19,11 +19,6 @@ namespace sky { float z; float w; }; -#if SKY_SIMD_SSE - __m128 simd; -#elif SKY_SIMD_NEON - float32x4_t simd; -#endif }; inline constexpr Vector4(); diff --git a/runtime/core/include/core/math/Vector4.inl b/runtime/core/include/core/math/Vector4.inl index 487987b8..ba26f593 100644 --- a/runtime/core/include/core/math/Vector4.inl +++ b/runtime/core/include/core/math/Vector4.inl @@ -53,10 +53,10 @@ namespace sky { inline Vector4& Vector4::operator+=(const Vector4& rhs) { -#if SKY_SIMD_SSE - simd = _mm_add_ps(simd, rhs.simd); -#elif SKY_SIMD_NEON - simd = vaddq_f32(simd, rhs.simd); +#if SKY_SIMD_ENABLED + SFloat4 a = SFloat4::Load(v); + SFloat4 b = SFloat4::Load(rhs.v); + (a += b).Store(v); #else x += rhs.x; y += rhs.y; @@ -68,10 +68,10 @@ namespace sky { inline Vector4& Vector4::operator-=(const Vector4& rhs) { -#if SKY_SIMD_SSE - simd = _mm_sub_ps(simd, rhs.simd); -#elif SKY_SIMD_NEON - simd = vsubq_f32(simd, rhs.simd); +#if SKY_SIMD_ENABLED + SFloat4 a = SFloat4::Load(v); + SFloat4 b = SFloat4::Load(rhs.v); + (a -= b).Store(v); #else x -= rhs.x; y -= rhs.y; @@ -83,10 +83,10 @@ namespace sky { inline Vector4& Vector4::operator*=(const Vector4& rhs) { -#if SKY_SIMD_SSE - simd = _mm_mul_ps(simd, rhs.simd); -#elif SKY_SIMD_NEON - simd = vmulq_f32(simd, rhs.simd); +#if SKY_SIMD_ENABLED + SFloat4 a = SFloat4::Load(v); + SFloat4 b = SFloat4::Load(rhs.v); + (a *= b).Store(v); #else x *= rhs.x; y *= rhs.y; @@ -98,10 +98,10 @@ namespace sky { inline Vector4& Vector4::operator/=(const Vector4& rhs) { -#if SKY_SIMD_SSE - simd = _mm_div_ps(simd, rhs.simd); -#elif SKY_SIMD_NEON - simd = vdivq_f32(simd, rhs.simd); +#if SKY_SIMD_ENABLED + SFloat4 a = SFloat4::Load(v); + SFloat4 b = SFloat4::Load(rhs.v); + (a /= b).Store(v); #else x /= rhs.x; y /= rhs.y; @@ -113,10 +113,10 @@ namespace sky { inline Vector4& Vector4::operator*=(float m) { -#if SKY_SIMD_SSE - simd = _mm_mul_ps(simd, _mm_set1_ps(m)); -#elif SKY_SIMD_NEON - simd = vmulq_n_f32(simd, m); +#if SKY_SIMD_ENABLED + SFloat4 a = SFloat4::Load(v); + SFloat4 b = SFloat4::Splat(m); + (a *= b).Store(v); #else x *= m; y *= m; @@ -128,11 +128,10 @@ namespace sky { inline Vector4& Vector4::operator/=(float d) { -#if SKY_SIMD_SSE - simd = _mm_div_ps(simd, _mm_set1_ps(d)); -#elif SKY_SIMD_NEON - float32x4_t dv = vdupq_n_f32(d); - simd = vdivq_f32(simd, dv); +#if SKY_SIMD_ENABLED + SFloat4 a = SFloat4::Load(v); + SFloat4 b = SFloat4::Splat(d); + (a /= b).Store(v); #else x /= d; y /= d; @@ -154,18 +153,10 @@ namespace sky { inline float Vector4::Dot(const Vector4 &rhs) const { -#if SKY_SIMD_SSE - __m128 mul = _mm_mul_ps(simd, rhs.simd); - __m128 shuf1 = _mm_shuffle_ps(mul, mul, _MM_SHUFFLE(2, 3, 0, 1)); - __m128 sums1 = _mm_add_ps(mul, shuf1); - __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); - __m128 sums2 = _mm_add_ps(sums1, shuf2); - return _mm_cvtss_f32(sums2); -#elif SKY_SIMD_NEON - float32x4_t mul = vmulq_f32(simd, rhs.simd); - float32x2_t sum = vadd_f32(vget_low_f32(mul), vget_high_f32(mul)); - sum = vpadd_f32(sum, sum); - return vget_lane_f32(sum, 0); +#if SKY_SIMD_ENABLED + SFloat4 a = SFloat4::Load(v); + SFloat4 b = SFloat4::Load(rhs.v); + return SFloat4::HorizontalSum(a * b); #else Vector4 ret = (*this) * rhs; return (ret.x + ret.y) + (ret.z + ret.w); @@ -174,28 +165,11 @@ namespace sky { inline void Vector4::Normalize() { -#if SKY_SIMD_SSE - __m128 dot = _mm_mul_ps(simd, simd); - __m128 shuf1 = _mm_shuffle_ps(dot, dot, _MM_SHUFFLE(2, 3, 0, 1)); - __m128 sums1 = _mm_add_ps(dot, shuf1); - __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); - __m128 sums2 = _mm_add_ps(sums1, shuf2); - __m128 inv = _mm_rsqrt_ps(sums2); - // Newton-Raphson refinement: inv = inv * (1.5 - 0.5 * sums2 * inv * inv) - __m128 half = _mm_set1_ps(0.5f); - __m128 three_half = _mm_set1_ps(1.5f); - __m128 muls = _mm_mul_ps(_mm_mul_ps(half, sums2), _mm_mul_ps(inv, inv)); - inv = _mm_mul_ps(inv, _mm_sub_ps(three_half, muls)); - simd = _mm_mul_ps(simd, inv); -#elif SKY_SIMD_NEON - float32x4_t mul = vmulq_f32(simd, simd); - float32x2_t sum = vadd_f32(vget_low_f32(mul), vget_high_f32(mul)); - sum = vpadd_f32(sum, sum); - float32x4_t dotVal = vdupq_lane_f32(sum, 0); - float32x4_t inv = vrsqrteq_f32(dotVal); - // Newton-Raphson refinement - inv = vmulq_f32(inv, vrsqrtsq_f32(vmulq_f32(dotVal, inv), inv)); - simd = vmulq_f32(simd, inv); +#if SKY_SIMD_ENABLED + SFloat4 a = SFloat4::Load(v); + SFloat4 dotSplat = SFloat4::HorizontalSumSplat(a * a); + SFloat4 inv = SFloat4::InvSqrt(dotSplat); + (a * inv).Store(v); #else float inverseSqrt = 1 / sqrt(Dot(*this)); Vector4::operator*=(inverseSqrt); From 16599c6e44d2c052ea343f3d0b5c529a8480c927 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 02:03:53 +0000 Subject: [PATCH 7/9] Improve scalar fallback readability in SFloat4.h Co-authored-by: bluesky013 <35895395+bluesky013@users.noreply.github.com> --- runtime/core/include/core/math/SFloat4.h | 29 ++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/runtime/core/include/core/math/SFloat4.h b/runtime/core/include/core/math/SFloat4.h index 054763ff..0de8f299 100644 --- a/runtime/core/include/core/math/SFloat4.h +++ b/runtime/core/include/core/math/SFloat4.h @@ -120,11 +120,32 @@ namespace sky { SFloat4() = default; - static inline SFloat4 Load(const float *p) { SFloat4 r; r.value[0] = p[0]; r.value[1] = p[1]; r.value[2] = p[2]; r.value[3] = p[3]; return r; } - static inline SFloat4 Set(float x, float y, float z, float w) { SFloat4 r; r.value[0] = x; r.value[1] = y; r.value[2] = z; r.value[3] = w; return r; } - static inline SFloat4 Splat(float v) { SFloat4 r; r.value[0] = r.value[1] = r.value[2] = r.value[3] = v; return r; } + static inline SFloat4 Load(const float *p) + { + SFloat4 r; + r.value[0] = p[0]; r.value[1] = p[1]; + r.value[2] = p[2]; r.value[3] = p[3]; + return r; + } + static inline SFloat4 Set(float x, float y, float z, float w) + { + SFloat4 r; + r.value[0] = x; r.value[1] = y; + r.value[2] = z; r.value[3] = w; + return r; + } + static inline SFloat4 Splat(float v) + { + SFloat4 r; + r.value[0] = r.value[1] = r.value[2] = r.value[3] = v; + return r; + } - inline void Store(float *p) const { p[0] = value[0]; p[1] = value[1]; p[2] = value[2]; p[3] = value[3]; } + inline void Store(float *p) const + { + p[0] = value[0]; p[1] = value[1]; + p[2] = value[2]; p[3] = value[3]; + } inline SFloat4 operator+(const SFloat4 &rhs) const { return SFloat4(*this) += rhs; } inline SFloat4 operator-(const SFloat4 &rhs) const { return SFloat4(*this) -= rhs; } From 9bda0b7f4efc154d294e5bd14fd51bb56542a0ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 02:10:27 +0000 Subject: [PATCH 8/9] Restore __m128/float32x4_t as union member in Vector4 Restore the SIMD native type as a union member in Vector4 for direct access, avoiding unnecessary Load/Store memory round-trips. Vector4 operations now construct SFloat4 directly from the simd union member and write back via .value assignment. Co-authored-by: bluesky013 <35895395+bluesky013@users.noreply.github.com> --- runtime/core/include/core/math/Matrix4.inl | 20 +++++------ runtime/core/include/core/math/Vector4.h | 5 +++ runtime/core/include/core/math/Vector4.inl | 40 +++++++++++----------- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/runtime/core/include/core/math/Matrix4.inl b/runtime/core/include/core/math/Matrix4.inl index 6536062d..47b7cc99 100644 --- a/runtime/core/include/core/math/Matrix4.inl +++ b/runtime/core/include/core/math/Matrix4.inl @@ -35,11 +35,11 @@ namespace sky { #if SKY_SIMD_ENABLED Matrix4 ret; for (int i = 0; i < 4; ++i) { - SFloat4 r = SFloat4::Load(m[0].v) * SFloat4::Splat(rhs.m[i].v[0]); - r += SFloat4::Load(m[1].v) * SFloat4::Splat(rhs.m[i].v[1]); - r += SFloat4::Load(m[2].v) * SFloat4::Splat(rhs.m[i].v[2]); - r += SFloat4::Load(m[3].v) * SFloat4::Splat(rhs.m[i].v[3]); - r.Store(ret.m[i].v); + SFloat4 r = SFloat4(m[0].simd) * SFloat4::Splat(rhs.m[i].v[0]); + r += SFloat4(m[1].simd) * SFloat4::Splat(rhs.m[i].v[1]); + r += SFloat4(m[2].simd) * SFloat4::Splat(rhs.m[i].v[2]); + r += SFloat4(m[3].simd) * SFloat4::Splat(rhs.m[i].v[3]); + ret.m[i].simd = r.value; } return ret; #else @@ -108,12 +108,12 @@ namespace sky { inline Vector4 Matrix4::operator*(const Vector4& rhs) const { #if SKY_SIMD_ENABLED - SFloat4 r = SFloat4::Load(m[0].v) * SFloat4::Splat(rhs.v[0]); - r += SFloat4::Load(m[1].v) * SFloat4::Splat(rhs.v[1]); - r += SFloat4::Load(m[2].v) * SFloat4::Splat(rhs.v[2]); - r += SFloat4::Load(m[3].v) * SFloat4::Splat(rhs.v[3]); + SFloat4 r = SFloat4(m[0].simd) * SFloat4::Splat(rhs.v[0]); + r += SFloat4(m[1].simd) * SFloat4::Splat(rhs.v[1]); + r += SFloat4(m[2].simd) * SFloat4::Splat(rhs.v[2]); + r += SFloat4(m[3].simd) * SFloat4::Splat(rhs.v[3]); Vector4 result; - r.Store(result.v); + result.simd = r.value; return result; #else Vector4 v0 = m[0] * rhs[0]; diff --git a/runtime/core/include/core/math/Vector4.h b/runtime/core/include/core/math/Vector4.h index fa35a1b6..a2d96fe4 100644 --- a/runtime/core/include/core/math/Vector4.h +++ b/runtime/core/include/core/math/Vector4.h @@ -19,6 +19,11 @@ namespace sky { float z; float w; }; +#if SKY_SIMD_SSE + __m128 simd; +#elif SKY_SIMD_NEON + float32x4_t simd; +#endif }; inline constexpr Vector4(); diff --git a/runtime/core/include/core/math/Vector4.inl b/runtime/core/include/core/math/Vector4.inl index ba26f593..41f28d4d 100644 --- a/runtime/core/include/core/math/Vector4.inl +++ b/runtime/core/include/core/math/Vector4.inl @@ -54,9 +54,9 @@ namespace sky { inline Vector4& Vector4::operator+=(const Vector4& rhs) { #if SKY_SIMD_ENABLED - SFloat4 a = SFloat4::Load(v); - SFloat4 b = SFloat4::Load(rhs.v); - (a += b).Store(v); + SFloat4 a(simd); + SFloat4 b(rhs.simd); + simd = (a += b).value; #else x += rhs.x; y += rhs.y; @@ -69,9 +69,9 @@ namespace sky { inline Vector4& Vector4::operator-=(const Vector4& rhs) { #if SKY_SIMD_ENABLED - SFloat4 a = SFloat4::Load(v); - SFloat4 b = SFloat4::Load(rhs.v); - (a -= b).Store(v); + SFloat4 a(simd); + SFloat4 b(rhs.simd); + simd = (a -= b).value; #else x -= rhs.x; y -= rhs.y; @@ -84,9 +84,9 @@ namespace sky { inline Vector4& Vector4::operator*=(const Vector4& rhs) { #if SKY_SIMD_ENABLED - SFloat4 a = SFloat4::Load(v); - SFloat4 b = SFloat4::Load(rhs.v); - (a *= b).Store(v); + SFloat4 a(simd); + SFloat4 b(rhs.simd); + simd = (a *= b).value; #else x *= rhs.x; y *= rhs.y; @@ -99,9 +99,9 @@ namespace sky { inline Vector4& Vector4::operator/=(const Vector4& rhs) { #if SKY_SIMD_ENABLED - SFloat4 a = SFloat4::Load(v); - SFloat4 b = SFloat4::Load(rhs.v); - (a /= b).Store(v); + SFloat4 a(simd); + SFloat4 b(rhs.simd); + simd = (a /= b).value; #else x /= rhs.x; y /= rhs.y; @@ -114,9 +114,9 @@ namespace sky { inline Vector4& Vector4::operator*=(float m) { #if SKY_SIMD_ENABLED - SFloat4 a = SFloat4::Load(v); + SFloat4 a(simd); SFloat4 b = SFloat4::Splat(m); - (a *= b).Store(v); + simd = (a *= b).value; #else x *= m; y *= m; @@ -129,9 +129,9 @@ namespace sky { inline Vector4& Vector4::operator/=(float d) { #if SKY_SIMD_ENABLED - SFloat4 a = SFloat4::Load(v); + SFloat4 a(simd); SFloat4 b = SFloat4::Splat(d); - (a /= b).Store(v); + simd = (a /= b).value; #else x /= d; y /= d; @@ -154,8 +154,8 @@ namespace sky { inline float Vector4::Dot(const Vector4 &rhs) const { #if SKY_SIMD_ENABLED - SFloat4 a = SFloat4::Load(v); - SFloat4 b = SFloat4::Load(rhs.v); + SFloat4 a(simd); + SFloat4 b(rhs.simd); return SFloat4::HorizontalSum(a * b); #else Vector4 ret = (*this) * rhs; @@ -166,10 +166,10 @@ namespace sky { inline void Vector4::Normalize() { #if SKY_SIMD_ENABLED - SFloat4 a = SFloat4::Load(v); + SFloat4 a(simd); SFloat4 dotSplat = SFloat4::HorizontalSumSplat(a * a); SFloat4 inv = SFloat4::InvSqrt(dotSplat); - (a * inv).Store(v); + simd = (a * inv).value; #else float inverseSqrt = 1 / sqrt(Dot(*this)); Vector4::operator*=(inverseSqrt); From f9756384bbd92136bbcf3b83b5f7814d53ebe95e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 03:08:22 +0000 Subject: [PATCH 9/9] Delete SFloat4 abstraction layer, use raw SIMD intrinsics directly Remove SFloat4.h and replace all SFloat4 usage in Vector4.inl and Matrix4.inl with direct #if SSE / #elif NEON / #else SIMD intrinsics. Co-authored-by: bluesky013 <35895395+bluesky013@users.noreply.github.com> --- runtime/core/include/core/math/Matrix4.inl | 46 ++++-- runtime/core/include/core/math/SFloat4.h | 182 --------------------- runtime/core/include/core/math/Vector4.h | 2 +- runtime/core/include/core/math/Vector4.inl | 91 +++++++---- 4 files changed, 93 insertions(+), 228 deletions(-) delete mode 100644 runtime/core/include/core/math/SFloat4.h diff --git a/runtime/core/include/core/math/Matrix4.inl b/runtime/core/include/core/math/Matrix4.inl index 47b7cc99..4cf34bfa 100644 --- a/runtime/core/include/core/math/Matrix4.inl +++ b/runtime/core/include/core/math/Matrix4.inl @@ -32,14 +32,26 @@ namespace sky { inline Matrix4 Matrix4::operator*(const Matrix4& rhs) const { -#if SKY_SIMD_ENABLED +#if SKY_SIMD_SSE Matrix4 ret; for (int i = 0; i < 4; ++i) { - SFloat4 r = SFloat4(m[0].simd) * SFloat4::Splat(rhs.m[i].v[0]); - r += SFloat4(m[1].simd) * SFloat4::Splat(rhs.m[i].v[1]); - r += SFloat4(m[2].simd) * SFloat4::Splat(rhs.m[i].v[2]); - r += SFloat4(m[3].simd) * SFloat4::Splat(rhs.m[i].v[3]); - ret.m[i].simd = r.value; + __m128 e0 = _mm_set1_ps(rhs.m[i].v[0]); + __m128 e1 = _mm_set1_ps(rhs.m[i].v[1]); + __m128 e2 = _mm_set1_ps(rhs.m[i].v[2]); + __m128 e3 = _mm_set1_ps(rhs.m[i].v[3]); + ret.m[i].simd = _mm_add_ps( + _mm_add_ps(_mm_mul_ps(m[0].simd, e0), _mm_mul_ps(m[1].simd, e1)), + _mm_add_ps(_mm_mul_ps(m[2].simd, e2), _mm_mul_ps(m[3].simd, e3))); + } + return ret; +#elif SKY_SIMD_NEON + Matrix4 ret; + for (int i = 0; i < 4; ++i) { + float32x4_t r = vmulq_n_f32(m[0].simd, rhs.m[i].v[0]); + r = vmlaq_n_f32(r, m[1].simd, rhs.m[i].v[1]); + r = vmlaq_n_f32(r, m[2].simd, rhs.m[i].v[2]); + r = vmlaq_n_f32(r, m[3].simd, rhs.m[i].v[3]); + ret.m[i].simd = r; } return ret; #else @@ -107,13 +119,23 @@ namespace sky { inline Vector4 Matrix4::operator*(const Vector4& rhs) const { -#if SKY_SIMD_ENABLED - SFloat4 r = SFloat4(m[0].simd) * SFloat4::Splat(rhs.v[0]); - r += SFloat4(m[1].simd) * SFloat4::Splat(rhs.v[1]); - r += SFloat4(m[2].simd) * SFloat4::Splat(rhs.v[2]); - r += SFloat4(m[3].simd) * SFloat4::Splat(rhs.v[3]); +#if SKY_SIMD_SSE + __m128 e0 = _mm_set1_ps(rhs.v[0]); + __m128 e1 = _mm_set1_ps(rhs.v[1]); + __m128 e2 = _mm_set1_ps(rhs.v[2]); + __m128 e3 = _mm_set1_ps(rhs.v[3]); + Vector4 result; + result.simd = _mm_add_ps( + _mm_add_ps(_mm_mul_ps(m[0].simd, e0), _mm_mul_ps(m[1].simd, e1)), + _mm_add_ps(_mm_mul_ps(m[2].simd, e2), _mm_mul_ps(m[3].simd, e3))); + return result; +#elif SKY_SIMD_NEON + float32x4_t r = vmulq_n_f32(m[0].simd, rhs.v[0]); + r = vmlaq_n_f32(r, m[1].simd, rhs.v[1]); + r = vmlaq_n_f32(r, m[2].simd, rhs.v[2]); + r = vmlaq_n_f32(r, m[3].simd, rhs.v[3]); Vector4 result; - result.simd = r.value; + result.simd = r; return result; #else Vector4 v0 = m[0] * rhs[0]; diff --git a/runtime/core/include/core/math/SFloat4.h b/runtime/core/include/core/math/SFloat4.h deleted file mode 100644 index 0de8f299..00000000 --- a/runtime/core/include/core/math/SFloat4.h +++ /dev/null @@ -1,182 +0,0 @@ -// -// Created for SIMD math support. -// - -#pragma once - -#include "core/math/MathSimd.h" -#include - -namespace sky { - -#if SKY_SIMD_SSE - - struct SFloat4 { - __m128 value; - - SFloat4() = default; - explicit SFloat4(__m128 v) : value(v) {} - - static inline SFloat4 Load(const float *p) { return SFloat4(_mm_loadu_ps(p)); } - static inline SFloat4 Set(float x, float y, float z, float w) { return SFloat4(_mm_set_ps(w, z, y, x)); } - static inline SFloat4 Splat(float v) { return SFloat4(_mm_set1_ps(v)); } - - inline void Store(float *p) const { _mm_storeu_ps(p, value); } - - inline SFloat4 operator+(const SFloat4 &rhs) const { return SFloat4(_mm_add_ps(value, rhs.value)); } - inline SFloat4 operator-(const SFloat4 &rhs) const { return SFloat4(_mm_sub_ps(value, rhs.value)); } - inline SFloat4 operator*(const SFloat4 &rhs) const { return SFloat4(_mm_mul_ps(value, rhs.value)); } - inline SFloat4 operator/(const SFloat4 &rhs) const { return SFloat4(_mm_div_ps(value, rhs.value)); } - - inline SFloat4 &operator+=(const SFloat4 &rhs) { value = _mm_add_ps(value, rhs.value); return *this; } - inline SFloat4 &operator-=(const SFloat4 &rhs) { value = _mm_sub_ps(value, rhs.value); return *this; } - inline SFloat4 &operator*=(const SFloat4 &rhs) { value = _mm_mul_ps(value, rhs.value); return *this; } - inline SFloat4 &operator/=(const SFloat4 &rhs) { value = _mm_div_ps(value, rhs.value); return *this; } - - static inline float HorizontalSum(const SFloat4 &v) - { - __m128 shuf1 = _mm_shuffle_ps(v.value, v.value, _MM_SHUFFLE(2, 3, 0, 1)); - __m128 sums1 = _mm_add_ps(v.value, shuf1); - __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); - __m128 sums2 = _mm_add_ps(sums1, shuf2); - return _mm_cvtss_f32(sums2); - } - - static inline SFloat4 HorizontalSumSplat(const SFloat4 &v) - { - __m128 shuf1 = _mm_shuffle_ps(v.value, v.value, _MM_SHUFFLE(2, 3, 0, 1)); - __m128 sums1 = _mm_add_ps(v.value, shuf1); - __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); - return SFloat4(_mm_add_ps(sums1, shuf2)); - } - - static inline SFloat4 InvSqrt(const SFloat4 &v) - { - __m128 inv = _mm_rsqrt_ps(v.value); - // Newton-Raphson refinement: inv = inv * (1.5 - 0.5 * v * inv * inv) - __m128 half = _mm_set1_ps(0.5f); - __m128 three_half = _mm_set1_ps(1.5f); - __m128 muls = _mm_mul_ps(_mm_mul_ps(half, v.value), _mm_mul_ps(inv, inv)); - inv = _mm_mul_ps(inv, _mm_sub_ps(three_half, muls)); - return SFloat4(inv); - } - }; - -#elif SKY_SIMD_NEON - - struct SFloat4 { - float32x4_t value; - - SFloat4() = default; - explicit SFloat4(float32x4_t v) : value(v) {} - - static inline SFloat4 Load(const float *p) { return SFloat4(vld1q_f32(p)); } - static inline SFloat4 Set(float x, float y, float z, float w) - { - float data[4] = {x, y, z, w}; - return SFloat4(vld1q_f32(data)); - } - static inline SFloat4 Splat(float v) { return SFloat4(vdupq_n_f32(v)); } - - inline void Store(float *p) const { vst1q_f32(p, value); } - - inline SFloat4 operator+(const SFloat4 &rhs) const { return SFloat4(vaddq_f32(value, rhs.value)); } - inline SFloat4 operator-(const SFloat4 &rhs) const { return SFloat4(vsubq_f32(value, rhs.value)); } - inline SFloat4 operator*(const SFloat4 &rhs) const { return SFloat4(vmulq_f32(value, rhs.value)); } - inline SFloat4 operator/(const SFloat4 &rhs) const { return SFloat4(vdivq_f32(value, rhs.value)); } - - inline SFloat4 &operator+=(const SFloat4 &rhs) { value = vaddq_f32(value, rhs.value); return *this; } - inline SFloat4 &operator-=(const SFloat4 &rhs) { value = vsubq_f32(value, rhs.value); return *this; } - inline SFloat4 &operator*=(const SFloat4 &rhs) { value = vmulq_f32(value, rhs.value); return *this; } - inline SFloat4 &operator/=(const SFloat4 &rhs) { value = vdivq_f32(value, rhs.value); return *this; } - - static inline float HorizontalSum(const SFloat4 &v) - { - float32x2_t sum = vadd_f32(vget_low_f32(v.value), vget_high_f32(v.value)); - sum = vpadd_f32(sum, sum); - return vget_lane_f32(sum, 0); - } - - static inline SFloat4 HorizontalSumSplat(const SFloat4 &v) - { - float32x2_t sum = vadd_f32(vget_low_f32(v.value), vget_high_f32(v.value)); - sum = vpadd_f32(sum, sum); - return SFloat4(vdupq_lane_f32(sum, 0)); - } - - static inline SFloat4 InvSqrt(const SFloat4 &v) - { - float32x4_t inv = vrsqrteq_f32(v.value); - // Newton-Raphson refinement - inv = vmulq_f32(inv, vrsqrtsq_f32(vmulq_f32(v.value, inv), inv)); - return SFloat4(inv); - } - }; - -#else - - struct SFloat4 { - float value[4]; - - SFloat4() = default; - - static inline SFloat4 Load(const float *p) - { - SFloat4 r; - r.value[0] = p[0]; r.value[1] = p[1]; - r.value[2] = p[2]; r.value[3] = p[3]; - return r; - } - static inline SFloat4 Set(float x, float y, float z, float w) - { - SFloat4 r; - r.value[0] = x; r.value[1] = y; - r.value[2] = z; r.value[3] = w; - return r; - } - static inline SFloat4 Splat(float v) - { - SFloat4 r; - r.value[0] = r.value[1] = r.value[2] = r.value[3] = v; - return r; - } - - inline void Store(float *p) const - { - p[0] = value[0]; p[1] = value[1]; - p[2] = value[2]; p[3] = value[3]; - } - - inline SFloat4 operator+(const SFloat4 &rhs) const { return SFloat4(*this) += rhs; } - inline SFloat4 operator-(const SFloat4 &rhs) const { return SFloat4(*this) -= rhs; } - inline SFloat4 operator*(const SFloat4 &rhs) const { return SFloat4(*this) *= rhs; } - inline SFloat4 operator/(const SFloat4 &rhs) const { return SFloat4(*this) /= rhs; } - - inline SFloat4 &operator+=(const SFloat4 &rhs) { for (int i = 0; i < 4; ++i) value[i] += rhs.value[i]; return *this; } - inline SFloat4 &operator-=(const SFloat4 &rhs) { for (int i = 0; i < 4; ++i) value[i] -= rhs.value[i]; return *this; } - inline SFloat4 &operator*=(const SFloat4 &rhs) { for (int i = 0; i < 4; ++i) value[i] *= rhs.value[i]; return *this; } - inline SFloat4 &operator/=(const SFloat4 &rhs) { for (int i = 0; i < 4; ++i) value[i] /= rhs.value[i]; return *this; } - - static inline float HorizontalSum(const SFloat4 &v) - { - return (v.value[0] + v.value[1]) + (v.value[2] + v.value[3]); - } - - static inline SFloat4 HorizontalSumSplat(const SFloat4 &v) - { - return Splat(HorizontalSum(v)); - } - - static inline SFloat4 InvSqrt(const SFloat4 &v) - { - SFloat4 r; - for (int i = 0; i < 4; ++i) { - r.value[i] = 1.0f / std::sqrt(v.value[i]); - } - return r; - } - }; - -#endif - -} // namespace sky diff --git a/runtime/core/include/core/math/Vector4.h b/runtime/core/include/core/math/Vector4.h index a2d96fe4..26713e1f 100644 --- a/runtime/core/include/core/math/Vector4.h +++ b/runtime/core/include/core/math/Vector4.h @@ -6,7 +6,7 @@ #pragma once #include "core/math/Math.h" -#include "core/math/SFloat4.h" +#include "core/math/MathSimd.h" namespace sky { diff --git a/runtime/core/include/core/math/Vector4.inl b/runtime/core/include/core/math/Vector4.inl index 41f28d4d..30b87e4a 100644 --- a/runtime/core/include/core/math/Vector4.inl +++ b/runtime/core/include/core/math/Vector4.inl @@ -53,10 +53,10 @@ namespace sky { inline Vector4& Vector4::operator+=(const Vector4& rhs) { -#if SKY_SIMD_ENABLED - SFloat4 a(simd); - SFloat4 b(rhs.simd); - simd = (a += b).value; +#if SKY_SIMD_SSE + simd = _mm_add_ps(simd, rhs.simd); +#elif SKY_SIMD_NEON + simd = vaddq_f32(simd, rhs.simd); #else x += rhs.x; y += rhs.y; @@ -68,10 +68,10 @@ namespace sky { inline Vector4& Vector4::operator-=(const Vector4& rhs) { -#if SKY_SIMD_ENABLED - SFloat4 a(simd); - SFloat4 b(rhs.simd); - simd = (a -= b).value; +#if SKY_SIMD_SSE + simd = _mm_sub_ps(simd, rhs.simd); +#elif SKY_SIMD_NEON + simd = vsubq_f32(simd, rhs.simd); #else x -= rhs.x; y -= rhs.y; @@ -83,10 +83,10 @@ namespace sky { inline Vector4& Vector4::operator*=(const Vector4& rhs) { -#if SKY_SIMD_ENABLED - SFloat4 a(simd); - SFloat4 b(rhs.simd); - simd = (a *= b).value; +#if SKY_SIMD_SSE + simd = _mm_mul_ps(simd, rhs.simd); +#elif SKY_SIMD_NEON + simd = vmulq_f32(simd, rhs.simd); #else x *= rhs.x; y *= rhs.y; @@ -98,10 +98,10 @@ namespace sky { inline Vector4& Vector4::operator/=(const Vector4& rhs) { -#if SKY_SIMD_ENABLED - SFloat4 a(simd); - SFloat4 b(rhs.simd); - simd = (a /= b).value; +#if SKY_SIMD_SSE + simd = _mm_div_ps(simd, rhs.simd); +#elif SKY_SIMD_NEON + simd = vdivq_f32(simd, rhs.simd); #else x /= rhs.x; y /= rhs.y; @@ -113,10 +113,10 @@ namespace sky { inline Vector4& Vector4::operator*=(float m) { -#if SKY_SIMD_ENABLED - SFloat4 a(simd); - SFloat4 b = SFloat4::Splat(m); - simd = (a *= b).value; +#if SKY_SIMD_SSE + simd = _mm_mul_ps(simd, _mm_set1_ps(m)); +#elif SKY_SIMD_NEON + simd = vmulq_n_f32(simd, m); #else x *= m; y *= m; @@ -128,10 +128,10 @@ namespace sky { inline Vector4& Vector4::operator/=(float d) { -#if SKY_SIMD_ENABLED - SFloat4 a(simd); - SFloat4 b = SFloat4::Splat(d); - simd = (a /= b).value; +#if SKY_SIMD_SSE + simd = _mm_div_ps(simd, _mm_set1_ps(d)); +#elif SKY_SIMD_NEON + simd = vdivq_f32(simd, vdupq_n_f32(d)); #else x /= d; y /= d; @@ -153,10 +153,18 @@ namespace sky { inline float Vector4::Dot(const Vector4 &rhs) const { -#if SKY_SIMD_ENABLED - SFloat4 a(simd); - SFloat4 b(rhs.simd); - return SFloat4::HorizontalSum(a * b); +#if SKY_SIMD_SSE + __m128 mul = _mm_mul_ps(simd, rhs.simd); + __m128 shuf1 = _mm_shuffle_ps(mul, mul, _MM_SHUFFLE(2, 3, 0, 1)); + __m128 sums1 = _mm_add_ps(mul, shuf1); + __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); + __m128 sums2 = _mm_add_ps(sums1, shuf2); + return _mm_cvtss_f32(sums2); +#elif SKY_SIMD_NEON + float32x4_t mul = vmulq_f32(simd, rhs.simd); + float32x2_t sum = vadd_f32(vget_low_f32(mul), vget_high_f32(mul)); + sum = vpadd_f32(sum, sum); + return vget_lane_f32(sum, 0); #else Vector4 ret = (*this) * rhs; return (ret.x + ret.y) + (ret.z + ret.w); @@ -165,11 +173,28 @@ namespace sky { inline void Vector4::Normalize() { -#if SKY_SIMD_ENABLED - SFloat4 a(simd); - SFloat4 dotSplat = SFloat4::HorizontalSumSplat(a * a); - SFloat4 inv = SFloat4::InvSqrt(dotSplat); - simd = (a * inv).value; +#if SKY_SIMD_SSE + __m128 dot = _mm_mul_ps(simd, simd); + __m128 shuf1 = _mm_shuffle_ps(dot, dot, _MM_SHUFFLE(2, 3, 0, 1)); + __m128 sums1 = _mm_add_ps(dot, shuf1); + __m128 shuf2 = _mm_shuffle_ps(sums1, sums1, _MM_SHUFFLE(0, 1, 2, 3)); + __m128 sums2 = _mm_add_ps(sums1, shuf2); + __m128 inv = _mm_rsqrt_ps(sums2); + // Newton-Raphson refinement: inv = inv * (1.5 - 0.5 * sums2 * inv * inv) + __m128 half = _mm_set1_ps(0.5f); + __m128 three_half = _mm_set1_ps(1.5f); + __m128 muls = _mm_mul_ps(_mm_mul_ps(half, sums2), _mm_mul_ps(inv, inv)); + inv = _mm_mul_ps(inv, _mm_sub_ps(three_half, muls)); + simd = _mm_mul_ps(simd, inv); +#elif SKY_SIMD_NEON + float32x4_t mul = vmulq_f32(simd, simd); + float32x2_t sum = vadd_f32(vget_low_f32(mul), vget_high_f32(mul)); + sum = vpadd_f32(sum, sum); + float32x4_t dotVal = vdupq_lane_f32(sum, 0); + float32x4_t inv = vrsqrteq_f32(dotVal); + // Newton-Raphson refinement + inv = vmulq_f32(inv, vrsqrtsq_f32(vmulq_f32(dotVal, inv), inv)); + simd = vmulq_f32(simd, inv); #else float inverseSqrt = 1 / sqrt(Dot(*this)); Vector4::operator*=(inverseSqrt);