diff --git a/.github/workflows/cmake-wasm.yml b/.github/workflows/cmake-wasm.yml new file mode 100644 index 0000000..5f7d7d0 --- /dev/null +++ b/.github/workflows/cmake-wasm.yml @@ -0,0 +1,97 @@ +name: CMake WebAssembly + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +env: + wasmtime_version: v7.0.0 + wasmer_version: v3.1.1 + +jobs: + build_wasi_sdk: + strategy: + matrix: + BUILD_TYPE: [Release, Debug, RelWithDebInfo, MinSizeRel] + C_FLAGS: ['', '-msimd128'] + wasi_sdk_version: [19, 20] + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Downloading wasi-sdk + run: | + cd ${{github.workspace}} + wget --no-verbose https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${{matrix.wasi_sdk_version}}/wasi-sdk-${{matrix.wasi_sdk_version}}.0-linux.tar.gz + tar xf wasi-sdk-${{matrix.wasi_sdk_version}}.0-linux.tar.gz + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.BUILD_TYPE}} -DCMAKE_C_FLAGS="${{matrix.C_FLAGS}}" -DCMAKE_TOOLCHAIN_FILE=${{github.workspace}}/wasi-sdk-${{matrix.wasi_sdk_version}}.0/share/cmake/wasi-sdk.cmake -DWASI_SDK_PREFIX=${{github.workspace}}/wasi-sdk-${{matrix.wasi_sdk_version}}.0 -DCGLM_USE_TEST=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{matrix.BUILD_TYPE}} + + - name: Test with wasmtime + run: | + cd ${{github.workspace}} + ls -lh ${{github.workspace}}/build/ + wget --no-verbose https://github.com/bytecodealliance/wasmtime/releases/download/${{env.wasmtime_version}}/wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz + tar xf wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz + ./wasmtime-${{env.wasmtime_version}}-x86_64-linux/wasmtime run --wasm-features simd ${{github.workspace}}/build/tests + + - name: Test with wasmer + run: | + cd ${{github.workspace}} + mkdir wasmer + cd wasmer + wget --no-verbose https://github.com/wasmerio/wasmer/releases/download/${{env.wasmer_version}}/wasmer-linux-amd64.tar.gz + tar xf wasmer-linux-amd64.tar.gz + ./bin/wasmer run --enable-simd ${{github.workspace}}/build/tests + + build_emsdk: + strategy: + matrix: + BUILD_TYPE: [Release, Debug, RelWithDebInfo, MinSizeRel] + C_FLAGS: ['', '-msimd128', '-msse -msse2 -msimd128', '-msse -msse2 -msse3 -msse4 -msimd128'] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup emsdk + uses: mymindstorm/setup-emsdk@v11 + + - name: Verify emsdk + run: emcc -v + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: emcmake cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.BUILD_TYPE}} -DCMAKE_C_FLAGS="${{matrix.C_FLAGS}}" -DCMAKE_EXE_LINKER_FLAGS="-s STANDALONE_WASM" -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{matrix.BUILD_TYPE}} + + - name: Test with wasmtime + run: | + cd ${{github.workspace}} + ls -lh ${{github.workspace}}/build/ + wget --no-verbose https://github.com/bytecodealliance/wasmtime/releases/download/${{env.wasmtime_version}}/wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz + tar xf wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz + ./wasmtime-${{env.wasmtime_version}}-x86_64-linux/wasmtime run --wasm-features simd ${{github.workspace}}/build/tests.wasm + - name: Test with wasmer + run: | + cd ${{github.workspace}} + mkdir wasmer + cd wasmer + wget --no-verbose https://github.com/wasmerio/wasmer/releases/download/${{env.wasmer_version}}/wasmer-linux-amd64.tar.gz + tar xf wasmer-linux-amd64.tar.gz + ./bin/wasmer run --enable-simd ${{github.workspace}}/build/tests.wasm diff --git a/CMakeLists.txt b/CMakeLists.txt index 7633d94..5594581 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,11 @@ option(CGLM_STATIC "Static build" OFF) option(CGLM_USE_C99 "" OFF) option(CGLM_USE_TEST "Enable Tests" OFF) +if(CMAKE_SYSTEM_NAME STREQUAL WASI) + set(CGLM_STATIC ON CACHE BOOL "Static option" FORCE) + set(CGLM_SHARED OFF CACHE BOOL "Shared option" FORCE) +endif() + if(NOT CGLM_STATIC AND CGLM_SHARED) set(CGLM_BUILD SHARED) else(CGLM_STATIC) diff --git a/include/cglm/affine-mat.h b/include/cglm/affine-mat.h index 75607e7..1cd4973 100644 --- a/include/cglm/affine-mat.h +++ b/include/cglm/affine-mat.h @@ -30,6 +30,10 @@ # include "simd/neon/affine.h" #endif +#ifdef CGLM_SIMD_WASM +# include "simd/wasm/affine.h" +#endif + /*! * @brief this is similar to glm_mat4_mul but specialized to affine transform * @@ -49,7 +53,9 @@ CGLM_INLINE void glm_mul(mat4 m1, mat4 m2, mat4 dest) { -#ifdef __AVX__ +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mul_wasm(m1, m2, dest); +#elif defined(__AVX__) glm_mul_avx(m1, m2, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mul_sse2(m1, m2, dest); @@ -107,7 +113,9 @@ glm_mul(mat4 m1, mat4 m2, mat4 dest) { CGLM_INLINE void glm_mul_rot(mat4 m1, mat4 m2, mat4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mul_rot_wasm(m1, m2, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mul_rot_sse2(m1, m2, dest); #elif defined(CGLM_NEON_FP) glm_mul_rot_neon(m1, m2, dest); @@ -156,7 +164,9 @@ glm_mul_rot(mat4 m1, mat4 m2, mat4 dest) { CGLM_INLINE void glm_inv_tr(mat4 mat) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_inv_tr_wasm(mat); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_inv_tr_sse2(mat); #elif defined(CGLM_NEON_FP) glm_inv_tr_neon(mat); diff --git a/include/cglm/io.h b/include/cglm/io.h index 12c3db0..2b8136f 100644 --- a/include/cglm/io.h +++ b/include/cglm/io.h @@ -68,7 +68,10 @@ CGLM_INLINE void glm_arch_print_name(FILE* __restrict ostream) { -#ifdef CGLM_SIMD_x86 +#if defined(CGLM_SIMD_WASM) + fprintf(ostream, CGLM_PRINT_COLOR "\ncglm arch: wasm SIMD128" + "\n\n" CGLM_PRINT_COLOR_RESET); +#elif defined(CGLM_SIMD_x86) fprintf(ostream, CGLM_PRINT_COLOR "\ncglm arch: x86 SSE*" #ifdef __AVX__ " AVX" diff --git a/include/cglm/mat2.h b/include/cglm/mat2.h index 871d6bd..918e965 100644 --- a/include/cglm/mat2.h +++ b/include/cglm/mat2.h @@ -44,6 +44,10 @@ # include "simd/neon/mat2.h" #endif +#ifdef CGLM_SIMD_WASM +# include "simd/wasm/mat2.h" +#endif + #define GLM_MAT2_IDENTITY_INIT {{1.0f, 0.0f}, {0.0f, 1.0f}} #define GLM_MAT2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}} @@ -132,7 +136,9 @@ glm_mat2_zero(mat2 mat) { CGLM_INLINE void glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat2_mul_wasm(m1, m2, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat2_mul_sse2(m1, m2, dest); #elif defined(CGLM_NEON_FP) glm_mat2_mul_neon(m1, m2, dest); @@ -160,7 +166,9 @@ glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) { CGLM_INLINE void glm_mat2_transpose_to(mat2 m, mat2 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat2_transp_wasm(m, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat2_transp_sse2(m, dest); #else dest[0][0] = m[0][0]; @@ -222,7 +230,10 @@ glm_mat2_trace(mat2 m) { CGLM_INLINE void glm_mat2_scale(mat2 m, float s) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(m[0], wasm_f32x4_mul(wasm_v128_load(m[0]), + wasm_f32x4_splat(s))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(m[0], _mm_mul_ps(_mm_loadu_ps(m[0]), _mm_set1_ps(s))); #elif defined(CGLM_NEON_FP) vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), vdupq_n_f32(s))); diff --git a/include/cglm/mat3.h b/include/cglm/mat3.h index 0b29f97..69f0454 100644 --- a/include/cglm/mat3.h +++ b/include/cglm/mat3.h @@ -42,6 +42,10 @@ # include "simd/sse2/mat3.h" #endif +#ifdef CGLM_SIMD_WASM +# include "simd/wasm/mat3.h" +#endif + #define GLM_MAT3_IDENTITY_INIT {{1.0f, 0.0f, 0.0f}, \ {0.0f, 1.0f, 0.0f}, \ {0.0f, 0.0f, 1.0f}} @@ -148,7 +152,9 @@ glm_mat3_zero(mat3 mat) { CGLM_INLINE void glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat3_mul_wasm(m1, m2, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat3_mul_sse2(m1, m2, dest); #else float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h index c7c8abd..932878d 100644 --- a/include/cglm/mat4.h +++ b/include/cglm/mat4.h @@ -64,6 +64,10 @@ # include "simd/neon/mat4.h" #endif +#ifdef CGLM_SIMD_WASM +# include "simd/wasm/mat4.h" +#endif + #ifdef DEBUG # include #endif @@ -121,7 +125,12 @@ glm_mat4_ucopy(mat4 mat, mat4 dest) { CGLM_INLINE void glm_mat4_copy(mat4 mat, mat4 dest) { -#ifdef __AVX__ +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest[0], glmm_load(mat[0])); + glmm_store(dest[1], glmm_load(mat[1])); + glmm_store(dest[2], glmm_load(mat[2])); + glmm_store(dest[3], glmm_load(mat[3])); +#elif defined(__AVX__) glmm_store256(dest[0], glmm_load256(mat[0])); glmm_store256(dest[2], glmm_load256(mat[2])); #elif defined( __SSE__ ) || defined( __SSE2__ ) @@ -187,7 +196,14 @@ glm_mat4_identity_array(mat4 * __restrict mat, size_t count) { CGLM_INLINE void glm_mat4_zero(mat4 mat) { -#ifdef __AVX__ +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_128 x0; + x0 = wasm_f32x4_const_splat(0.f); + glmm_store(mat[0], x0); + glmm_store(mat[1], x0); + glmm_store(mat[2], x0); + glmm_store(mat[3], x0); +#elif defined(__AVX__) __m256 y0; y0 = _mm256_setzero_ps(); glmm_store256(mat[0], y0); @@ -297,7 +313,9 @@ glm_mat4_ins3(mat3 mat, mat4 dest) { CGLM_INLINE void glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest) { -#ifdef __AVX__ +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat4_mul_wasm(m1, m2, dest); +#elif defined(__AVX__) glm_mat4_mul_avx(m1, m2, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_mul_sse2(m1, m2, dest); @@ -377,7 +395,9 @@ glm_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest) { CGLM_INLINE void glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat4_mulv_wasm(m, v, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_mulv_sse2(m, v, dest); #elif defined(CGLM_NEON_FP) glm_mat4_mulv_neon(m, v, dest); @@ -497,7 +517,9 @@ glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest) { CGLM_INLINE void glm_mat4_transpose_to(mat4 m, mat4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat4_transp_wasm(m, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_transp_sse2(m, dest); #elif defined(CGLM_NEON_FP) glm_mat4_transp_neon(m, dest); @@ -521,7 +543,9 @@ glm_mat4_transpose_to(mat4 m, mat4 dest) { CGLM_INLINE void glm_mat4_transpose(mat4 m) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat4_transp_wasm(m, m); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_transp_sse2(m, m); #elif defined(CGLM_NEON_FP) glm_mat4_transp_neon(m, m); @@ -560,7 +584,9 @@ glm_mat4_scale_p(mat4 m, float s) { CGLM_INLINE void glm_mat4_scale(mat4 m, float s) { -#ifdef __AVX__ +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat4_scale_wasm(m, s); +#elif defined(__AVX__) glm_mat4_scale_avx(m, s); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_scale_sse2(m, s); @@ -581,7 +607,9 @@ glm_mat4_scale(mat4 m, float s) { CGLM_INLINE float glm_mat4_det(mat4 mat) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + return glm_mat4_det_wasm(mat); +#elif defined( __SSE__ ) || defined( __SSE2__ ) return glm_mat4_det_sse2(mat); #elif defined(CGLM_NEON_FP) return glm_mat4_det_neon(mat); @@ -679,7 +707,9 @@ glm_mat4_inv(mat4 mat, mat4 dest) { CGLM_INLINE void glm_mat4_inv_fast(mat4 mat, mat4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_mat4_inv_fast_wasm(mat, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_inv_fast_sse2(mat, dest); #else glm_mat4_inv(mat, dest); diff --git a/include/cglm/quat.h b/include/cglm/quat.h index c76fa03..bc52a38 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -70,6 +70,10 @@ # include "simd/neon/quat.h" #endif +#ifdef CGLM_SIMD_WASM +# include "simd/wasm/quat.h" +#endif + CGLM_INLINE void glm_quat_normalize(versor q); /* @@ -238,7 +242,22 @@ glm_quat_norm(versor q) { CGLM_INLINE void glm_quat_normalize_to(versor q, versor dest) { -#if defined( __SSE2__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_128 xdot, x0; + float dot; + + x0 = glmm_load(q); + xdot = glmm_vdot(x0, x0); + /* dot = _mm_cvtss_f32(xdot); */ + dot = wasm_f32x4_extract_lane(xdot, 0); + + if (dot <= 0.0f) { + glm_quat_identity(dest); + return; + } + + glmm_store(dest, wasm_f32x4_div(x0, wasm_f32x4_sqrt(xdot))); +#elif defined( __SSE2__ ) || defined( __SSE2__ ) __m128 xdot, x0; float dot; @@ -438,7 +457,9 @@ glm_quat_mul(versor p, versor q, versor dest) { + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k a1 a2 − b1 b2 − c1 c2 − d1 d2 */ -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glm_quat_mul_wasm(p, q, dest); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glm_quat_mul_sse2(p, q, dest); #elif defined(CGLM_NEON_FP) glm_quat_mul_neon(p, q, dest); diff --git a/include/cglm/simd/intrin.h b/include/cglm/simd/intrin.h index bfdc94e..bf8d119 100644 --- a/include/cglm/simd/intrin.h +++ b/include/cglm/simd/intrin.h @@ -99,13 +99,21 @@ # endif #endif -#if defined(CGLM_SIMD_x86) || defined(CGLM_SIMD_ARM) + +/* WebAssembly */ +#if defined(__wasm__) && defined(__wasm_simd128__) +# ifndef CGLM_SIMD_WASM +# define CGLM_SIMD_WASM +# endif +#endif + +#if defined(CGLM_SIMD_x86) || defined(CGLM_SIMD_ARM) || defined(CGLM_SIMD_WASM) # ifndef CGLM_SIMD # define CGLM_SIMD # endif #endif -#if defined(CGLM_SIMD_x86) +#if defined(CGLM_SIMD_x86) && !defined(CGLM_SIMD_WASM) # include "x86.h" #endif @@ -113,4 +121,8 @@ # include "arm.h" #endif +#if defined(CGLM_SIMD_WASM) +# include "wasm.h" +#endif + #endif /* cglm_intrin_h */ diff --git a/include/cglm/simd/wasm.h b/include/cglm/simd/wasm.h new file mode 100644 index 0000000..648e1bb --- /dev/null +++ b/include/cglm/simd/wasm.h @@ -0,0 +1,188 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_simd_wasm_h +#define cglm_simd_wasm_h +#include "intrin.h" +#ifdef CGLM_SIMD_WASM +#include + +#define glmm_load(p) wasm_v128_load(p) +#define glmm_store(p, a) wasm_v128_store(p, (a)) + +#define glmm_set1(x) wasm_f32x4_splat(x) +#define glmm_128 v128_t + +#define glmm_shuff1(xmm, z, y, x, w) wasm_i32x4_shuffle(xmm, xmm, w, x, y, z) + +#define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane) + +#define glmm_splat_x(x) glmm_splat(x, 0) +#define glmm_splat_y(x) glmm_splat(x, 1) +#define glmm_splat_z(x) glmm_splat(x, 2) +#define glmm_splat_w(x) glmm_splat(x, 3) + +static inline +glmm_128 +glmm_abs(glmm_128 x) { + return wasm_f32x4_abs(x); +} + +static inline +glmm_128 +glmm_vhadd(glmm_128 v) { + glmm_128 x0; + x0 = wasm_f32x4_add(v, glmm_shuff1(v, 0, 1, 2, 3)); + x0 = wasm_f32x4_add(x0, glmm_shuff1(x0, 1, 0, 0, 1)); + return x0; +} + +static inline +glmm_128 +glmm_vhadds(glmm_128 v) { + glmm_128 shuf, sums; + shuf = glmm_shuff1(v, 2, 3, 0, 1); + sums = wasm_f32x4_add(v, shuf); + /* shuf = _mm_movehl_ps(shuf, sums); */ + shuf = wasm_i32x4_shuffle(shuf, sums, 6, 7, 2, 3); + sums = wasm_i32x4_shuffle(sums, wasm_f32x4_add(sums, shuf), 4, 1, 2, 3); + return sums; +} + +static inline +float +glmm_hadd(glmm_128 v) { + return wasm_f32x4_extract_lane(glmm_vhadds(v), 0); +} + +static inline +glmm_128 +glmm_vhmin(glmm_128 v) { + glmm_128 x0, x1, x2; + x0 = glmm_shuff1(v, 2, 3, 2, 3); /* [2, 3, 2, 3] */ + x1 = wasm_f32x4_pmin(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ + x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ + return wasm_f32x4_pmin(x1, x2); +} + +static inline +float +glmm_hmin(glmm_128 v) { + return wasm_f32x4_extract_lane(glmm_vhmin(v), 0); +} + +static inline +glmm_128 +glmm_vhmax(glmm_128 v) { + glmm_128 x0, x1, x2; + x0 = glmm_shuff1(v, 2, 3, 2, 3); /* [2, 3, 2, 3] */ + x1 = wasm_f32x4_pmax(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ + x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ + /* _mm_max_ss */ + return wasm_i32x4_shuffle(x1, wasm_f32x4_pmax(x1, x2), 4, 1, 2, 3); +} + +static inline +float +glmm_hmax(glmm_128 v) { + return wasm_f32x4_extract_lane(glmm_vhmax(v), 0); +} + +static inline +glmm_128 +glmm_vdots(glmm_128 a, glmm_128 b) { + return glmm_vhadds(wasm_f32x4_mul(a, b)); +} + +static inline +glmm_128 +glmm_vdot(glmm_128 a, glmm_128 b) { + glmm_128 x0; + x0 = wasm_f32x4_mul(a, b); + x0 = wasm_f32x4_add(x0, glmm_shuff1(x0, 1, 0, 3, 2)); + return wasm_f32x4_add(x0, glmm_shuff1(x0, 0, 1, 0, 1)); +} + +static inline +float +glmm_dot(glmm_128 a, glmm_128 b) { + return wasm_f32x4_extract_lane(glmm_vdots(a, b), 0); +} + +static inline +float +glmm_norm(glmm_128 a) { + glmm_128 x0; + x0 = glmm_vhadds(wasm_f32x4_mul(a, a)); + return wasm_f32x4_extract_lane( + wasm_i32x4_shuffle(x0, wasm_f32x4_sqrt(x0),4, 1, 2, 3), 0); +} + +static inline +float +glmm_norm2(glmm_128 a) { + return wasm_f32x4_extract_lane(glmm_vhadds(wasm_f32x4_mul(a, a)), 0); +} + +static inline +float +glmm_norm_one(glmm_128 a) { + return wasm_f32x4_extract_lane(glmm_vhadds(glmm_abs(a)), 0); +} + +static inline +float +glmm_norm_inf(glmm_128 a) { + return wasm_f32x4_extract_lane(glmm_vhmax(glmm_abs(a)), 0); +} + +static inline +glmm_128 +glmm_load3(float v[3]) { + glmm_128 xy = wasm_v128_load64_zero(v); + return wasm_f32x4_replace_lane(xy, 2, v[2]); +} + +static inline +void +glmm_store3(float v[3], glmm_128 vx) { + wasm_v128_store64_lane(v, vx, 0); + wasm_v128_store32_lane(&v[2], vx, 2); +} + +static inline +glmm_128 +glmm_div(glmm_128 a, glmm_128 b) { + return wasm_f32x4_div(a, b); +} + +static inline +glmm_128 +glmm_fmadd(glmm_128 a, glmm_128 b, glmm_128 c) { + return wasm_f32x4_add(c, wasm_f32x4_mul(a, b)); +} + +static inline +glmm_128 +glmm_fnmadd(glmm_128 a, glmm_128 b, glmm_128 c) { + return wasm_f32x4_sub(c, wasm_f32x4_mul(a, b)); +} + +static inline +glmm_128 +glmm_fmsub(glmm_128 a, glmm_128 b, glmm_128 c) { + return wasm_f32x4_sub(wasm_f32x4_mul(a, b), c); +} + +static inline +glmm_128 +glmm_fnmsub(glmm_128 a, glmm_128 b, glmm_128 c) { + return wasm_f32x4_neg(wasm_f32x4_add(wasm_f32x4_mul(a, b), c)); +} + +#endif +#endif /* cglm_simd_wasm_h */ diff --git a/include/cglm/simd/wasm/affine.h b/include/cglm/simd/wasm/affine.h new file mode 100644 index 0000000..80b98fb --- /dev/null +++ b/include/cglm/simd/wasm/affine.h @@ -0,0 +1,127 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_affine_mat_wasm_h +#define cglm_affine_mat_wasm_h +#if defined(__wasm__) && defined(__wasm_simd128__) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mul_wasm(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + r3 = glmm_load(m2[3]); + + v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); + v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); + v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); + v3 = wasm_f32x4_mul(glmm_splat_x(r3), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); + + l = glmm_load(m1[3]); + v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], v3); +} + +CGLM_INLINE +void +glm_mul_rot_wasm(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + glmm_128 l, r0, r1, r2, v0, v1, v2; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + + v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); + v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); + v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], glmm_load(m1[3])); +} + +CGLM_INLINE +void +glm_inv_tr_wasm(mat4 mat) { + glmm_128 r0, r1, r2, r3, x0, x1, x2, x3, x4, x5; + + r0 = glmm_load(mat[0]); + r1 = glmm_load(mat[1]); + r2 = glmm_load(mat[2]); + r3 = glmm_load(mat[3]); + x1 = wasm_f32x4_const(0.0f, 0.0f, 0.0f, 1.0f); + + /* _MM_TRANSPOSE4_PS(r0, r1, r2, x1); */ + x2 = wasm_i32x4_shuffle(r0, r1, 0, 4, 1, 5); + x3 = wasm_i32x4_shuffle(r0, r1, 2, 6, 3, 7); + x4 = wasm_i32x4_shuffle(r2, x1, 0, 4, 1, 5); + x5 = wasm_i32x4_shuffle(r2, x1, 2, 6, 3, 7); + /* r0 = _mm_movelh_ps(x2, x4); */ + r0 = wasm_i32x4_shuffle(x2, x4, 0, 1, 4, 5); + /* r1 = _mm_movehl_ps(x4, x2); */ + r1 = wasm_i32x4_shuffle(x4, x2, 6, 7, 2, 3); + /* r2 = _mm_movelh_ps(x3, x5); */ + r2 = wasm_i32x4_shuffle(x3, x5, 0, 1, 4, 5); + /* x1 = _mm_movehl_ps(x5, x3); */ + x1 = wasm_i32x4_shuffle(x5, x3, 6, 7, 2, 3); + + x2 = glmm_shuff1(r3, 0, 0, 0, 0); + x3 = glmm_shuff1(r3, 1, 1, 1, 1); + x4 = glmm_shuff1(r3, 2, 2, 2, 2); + + x0 = glmm_fmadd(r0, x2, + glmm_fmadd(r1, x3, wasm_f32x4_mul(r2, x4))); + x0 = wasm_f32x4_neg(x0); + + x0 = wasm_f32x4_add(x0, x1); + + glmm_store(mat[0], r0); + glmm_store(mat[1], r1); + glmm_store(mat[2], r2); + glmm_store(mat[3], x0); +} + +#endif +#endif /* cglm_affine_mat_wasm_h */ diff --git a/include/cglm/simd/wasm/mat2.h b/include/cglm/simd/wasm/mat2.h new file mode 100644 index 0000000..80ce0fb --- /dev/null +++ b/include/cglm/simd/wasm/mat2.h @@ -0,0 +1,50 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat2_wasm_h +#define cglm_mat2_wasm_h +#if defined(__wasm__) && defined(__wasm_simd128__) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mat2_mul_wasm(mat2 m1, mat2 m2, mat2 dest) { + glmm_128 x0, x1, x2, x3, x4; + + x1 = glmm_load(m1[0]); /* d c b a */ + x2 = glmm_load(m2[0]); /* h g f e */ + + x3 = glmm_shuff1(x2, 2, 2, 0, 0); + x4 = glmm_shuff1(x2, 3, 3, 1, 1); + /* x0 = _mm_movelh_ps(x1, x1); */ + x0 = wasm_i32x4_shuffle(x1, x1, 0, 1, 4, 5); + /* x2 = _mm_movehl_ps(x1, x1); */ + x2 = wasm_i32x4_shuffle(x1, x1, 6, 7, 2, 3); + + /* + dest[0][0] = a * e + c * f; + dest[0][1] = b * e + d * f; + dest[1][0] = a * g + c * h; + dest[1][1] = b * g + d * h; + */ + x0 = glmm_fmadd(x0, x3, wasm_f32x4_mul(x2, x4)); + + glmm_store(dest[0], x0); +} + +CGLM_INLINE +void +glm_mat2_transp_wasm(mat2 m, mat2 dest) { + /* d c b a */ + /* d b c a */ + glmm_store(dest[0], glmm_shuff1(glmm_load(m[0]), 3, 1, 2, 0)); +} + +#endif +#endif /* cglm_mat2_wasm_h */ diff --git a/include/cglm/simd/wasm/mat3.h b/include/cglm/simd/wasm/mat3.h new file mode 100644 index 0000000..dfe192d --- /dev/null +++ b/include/cglm/simd/wasm/mat3.h @@ -0,0 +1,85 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat3_wasm_h +#define cglm_mat3_wasm_h +#if defined(__wasm__) && defined(__wasm_simd128__) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_mat3_mul_wasm(mat3 m1, mat3 m2, mat3 dest) { + glmm_128 l0, l1, l2, r0, r1, r2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; + + l0 = wasm_v128_load(m1[0]); + l1 = wasm_v128_load(&m1[1][1]); + + r0 = wasm_v128_load(m2[0]); + r1 = wasm_v128_load(&m2[1][1]); + + x8 = glmm_shuff1(l0, 0, 2, 1, 0); /* a00 a02 a01 a00 */ + x1 = glmm_shuff1(r0, 3, 0, 0, 0); /* b10 b00 b00 b00 */ + x2 = wasm_i32x4_shuffle(l0, l1, 3, 3, 4, 5); /* a12 a11 a10 a10 */ + x3 = wasm_i32x4_shuffle(r0, r1, 1, 3, 4, 6); /* b20 b11 b10 b01 */ + x0 = wasm_f32x4_mul(x8, x1); + + x6 = glmm_shuff1(l0, 1, 0, 2, 1); /* a01 a00 a02 a01 */ + x7 = glmm_shuff1(x3, 3, 3, 1, 1); /* b20 b20 b10 b10 */ + l2 = wasm_v128_load32_zero(&m1[2][2]); + r2 = wasm_v128_load32_zero(&m2[2][2]); + x1 = wasm_f32x4_mul(x6, x7); + l2 = glmm_shuff1(l2, 0, 0, 1, 0); /* a22 a22 0.f a22 */ + r2 = glmm_shuff1(r2, 0, 0, 1, 0); /* b22 b22 0.f b22 */ + + x4 = glmm_shuff1(x2, 0, 3, 2, 0); /* a10 a12 a11 a10 */ + x5 = glmm_shuff1(x2, 2, 0, 3, 2); /* a11 a10 a12 a11 */ + x6 = glmm_shuff1(x3, 2, 0, 0, 0); /* b11 b01 b01 b01 */ + x2 = glmm_shuff1(r1, 3, 3, 0, 0); /* b21 b21 b11 b11 */ + + /* x8 = _mm_unpackhi_ps(x8, x4); */ + /* x9 = _mm_unpackhi_ps(x7, x2); */ + x8 = wasm_i32x4_shuffle(x8, x4, 2, 6, 3, 7); /* a10 a00 a12 a02 */ + x9 = wasm_i32x4_shuffle(x7, x2, 2, 6, 3, 7); /* b21 b20 b21 b20 */ + + x0 = glmm_fmadd(x4, x6, x0); + x1 = glmm_fmadd(x5, x2, x1); + + /* x2 = _mm_movehl_ps(l2, l1); */ + x2 = wasm_i32x4_shuffle(l2, l1, 6, 7, 2, 3); /* a22 a22 a21 a20 */ + x3 = glmm_shuff1(x2, 0, 2, 1, 0); /* a20 a22 a21 a20 */ + x2 = glmm_shuff1(x2, 1, 0, 2, 1); /* a21 a20 a22 a21 */ + x4 = wasm_i32x4_shuffle(r0, r1, 2, 2, 5, 5); /* b12 b12 b02 b02 */ + + x5 = glmm_shuff1(x4, 3, 0, 0, 0); /* b12 b02 b02 b02 */ + /* x4 = _mm_movehl_ps(r2, x4); */ + x4 = wasm_i32x4_shuffle(r2, x4, 6, 7, 2, 3); /* b22 b22 b12 b12 */ + x0 = glmm_fmadd(x3, x5, x0); + x1 = glmm_fmadd(x2, x4, x1); + + /* + Dot Product : dest[2][2] = a02 * b20 + + a12 * b21 + + a22 * b22 + + 0 * 00 */ + /* x2 = _mm_movelh_ps(x8, l2); */ + /* x3 = _mm_movelh_ps(x9, r2); */ + x2 = wasm_i32x4_shuffle(x8, l2, 0, 1, 4, 5); /* 0.f a22 a12 a02 */ + x3 = wasm_i32x4_shuffle(x9, r2, 0, 1, 4, 5); /* 0.f b22 b21 b20 */ + x2 = glmm_vdots(x2, x3); + + /* _mm_storeu_ps(&dest[0][0], x0); */ + wasm_v128_store(&dest[0][0], x0); + /* _mm_storeu_ps(&dest[1][1], x1); */ + wasm_v128_store(&dest[1][1], x1); + /* _mm_store_ss (&dest[2][2], x2); */ + wasm_v128_store32_lane(&dest[2][2], x2, 0); +} + +#endif +#endif /* cglm_mat3_wasm_h */ diff --git a/include/cglm/simd/wasm/mat4.h b/include/cglm/simd/wasm/mat4.h new file mode 100644 index 0000000..3711843 --- /dev/null +++ b/include/cglm/simd/wasm/mat4.h @@ -0,0 +1,452 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_mat_wasm_h +#define cglm_mat_wasm_h +#if defined(__wasm__) && defined(__wasm_simd128__) + +#include "../../common.h" +#include "../intrin.h" + +#define glm_mat4_inv_precise_wasm(mat, dest) glm_mat4_inv_wasm(mat, dest) + +CGLM_INLINE +void +glm_mat4_scale_wasm(mat4 m, float s) { + glmm_128 x0; + x0 = wasm_f32x4_splat(s); + + glmm_store(m[0], wasm_f32x4_mul(glmm_load(m[0]), x0)); + glmm_store(m[1], wasm_f32x4_mul(glmm_load(m[1]), x0)); + glmm_store(m[2], wasm_f32x4_mul(glmm_load(m[2]), x0)); + glmm_store(m[3], wasm_f32x4_mul(glmm_load(m[3]), x0)); +} + +CGLM_INLINE +void +glm_mat4_transp_wasm(mat4 m, mat4 dest) { + glmm_128 r0, r1, r2, r3, tmp0, tmp1, tmp2, tmp3; + + r0 = glmm_load(m[0]); + r1 = glmm_load(m[1]); + r2 = glmm_load(m[2]); + r3 = glmm_load(m[3]); + + /* _MM_TRANSPOSE4_PS(r0, r1, r2, r3); */ + tmp0 = wasm_i32x4_shuffle(r0, r1, 0, 4, 1, 5); + tmp1 = wasm_i32x4_shuffle(r0, r1, 2, 6, 3, 7); + tmp2 = wasm_i32x4_shuffle(r2, r3, 0, 4, 1, 5); + tmp3 = wasm_i32x4_shuffle(r2, r3, 2, 6, 3, 7); + /* r0 = _mm_movelh_ps(tmp0, tmp2); */ + r0 = wasm_i32x4_shuffle(tmp0, tmp2, 0, 1, 4, 5); + /* r1 = _mm_movehl_ps(tmp2, tmp0); */ + r1 = wasm_i32x4_shuffle(tmp2, tmp0, 6, 7, 2, 3); + /* r2 = _mm_movelh_ps(tmp1, tmp3); */ + r2 = wasm_i32x4_shuffle(tmp1, tmp3, 0, 1, 4, 5); + /* r3 = _mm_movehl_ps(tmp3, tmp1); */ + r3 = wasm_i32x4_shuffle(tmp3, tmp1, 6, 7, 2, 3); + + glmm_store(dest[0], r0); + glmm_store(dest[1], r1); + glmm_store(dest[2], r2); + glmm_store(dest[3], r3); +} + +CGLM_INLINE +void +glm_mat4_mul_wasm(mat4 m1, mat4 m2, mat4 dest) { + /* D = R * L (Column-Major) */ + + glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; + + l = glmm_load(m1[0]); + r0 = glmm_load(m2[0]); + r1 = glmm_load(m2[1]); + r2 = glmm_load(m2[2]); + r3 = glmm_load(m2[3]); + + v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); + v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); + v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); + v3 = wasm_f32x4_mul(glmm_splat_x(r3), l); + + l = glmm_load(m1[1]); + v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); + + l = glmm_load(m1[2]); + v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); + + l = glmm_load(m1[3]); + v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); + v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); + v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); + v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); + + glmm_store(dest[0], v0); + glmm_store(dest[1], v1); + glmm_store(dest[2], v2); + glmm_store(dest[3], v3); +} + +CGLM_INLINE +void +glm_mat4_mulv_wasm(mat4 m, vec4 v, vec4 dest) { + glmm_128 x0, x1, m0, m1, m2, m3, v0, v1, v2, v3; + + m0 = glmm_load(m[0]); + m1 = glmm_load(m[1]); + m2 = glmm_load(m[2]); + m3 = glmm_load(m[3]); + + x0 = glmm_load(v); + v0 = glmm_splat_x(x0); + v1 = glmm_splat_y(x0); + v2 = glmm_splat_z(x0); + v3 = glmm_splat_w(x0); + + x1 = wasm_f32x4_mul(m3, v3); + x1 = glmm_fmadd(m2, v2, x1); + x1 = glmm_fmadd(m1, v1, x1); + x1 = glmm_fmadd(m0, v0, x1); + + glmm_store(dest, x1); +} + +CGLM_INLINE +float +glm_mat4_det_wasm(mat4 mat) { + glmm_128 r0, r1, r2, r3, x0, x1, x2; + + /* 127 <- 0, [square] det(A) = det(At) */ + r0 = glmm_load(mat[0]); /* d c b a */ + r1 = glmm_load(mat[1]); /* h g f e */ + r2 = glmm_load(mat[2]); /* l k j i */ + r3 = glmm_load(mat[3]); /* p o n m */ + + /* + t[1] = j * p - n * l; + t[2] = j * o - n * k; + t[3] = i * p - m * l; + t[4] = i * o - m * k; + */ + x0 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 1, 1), glmm_shuff1(r2, 2, 3, 2, 3), + wasm_f32x4_mul(glmm_shuff1(r2, 0, 0, 1, 1), + glmm_shuff1(r3, 2, 3, 2, 3))); + /* + t[0] = k * p - o * l; + t[0] = k * p - o * l; + t[5] = i * n - m * j; + t[5] = i * n - m * j; + */ + x1 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 2, 2), glmm_shuff1(r2, 1, 1, 3, 3), + wasm_f32x4_mul(glmm_shuff1(r2, 0, 0, 2, 2), + glmm_shuff1(r3, 1, 1, 3, 3))); + + /* + a * (f * t[0] - g * t[1] + h * t[2]) + - b * (e * t[0] - g * t[3] + h * t[4]) + + c * (e * t[1] - f * t[3] + h * t[5]) + - d * (e * t[2] - f * t[4] + g * t[5]) + */ + x2 = glmm_fnmadd(glmm_shuff1(r1, 1, 1, 2, 2), glmm_shuff1(x0, 3, 2, 2, 0), + wasm_f32x4_mul(glmm_shuff1(r1, 0, 0, 0, 1), + wasm_i32x4_shuffle(x1, x0, 0, 0, 4, 5))); + x2 = glmm_fmadd(glmm_shuff1(r1, 2, 3, 3, 3), + wasm_i32x4_shuffle(x0, x1, 1, 3, 6, 6), + x2); + + x2 = wasm_v128_xor(x2, wasm_f32x4_const(0.f, -0.f, 0.f, -0.f)); + + return glmm_hadd(wasm_f32x4_mul(x2, r0)); +} + +CGLM_INLINE +void +glm_mat4_inv_fast_wasm(mat4 mat, mat4 dest) { + glmm_128 r0, r1, r2, r3, + v0, v1, v2, v3, + t0, t1, t2, t3, t4, t5, + x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; + + x8 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); + x9 = glmm_shuff1(x8, 2, 1, 2, 1); + + /* 127 <- 0 */ + r0 = glmm_load(mat[0]); /* d c b a */ + r1 = glmm_load(mat[1]); /* h g f e */ + r2 = glmm_load(mat[2]); /* l k j i */ + r3 = glmm_load(mat[3]); /* p o n m */ + /* x0 = _mm_movehl_ps(r3, r2); */ + x0 = wasm_i32x4_shuffle(r3, r2, 6, 7, 2, 3); /* p o l k */ + /* x3 = _mm_movelh_ps(r2, r3); */ + x3 = wasm_i32x4_shuffle(r2, r3, 0, 1, 4, 5); /* n m j i */ + x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ + x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ + x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ + x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ + + x6 = wasm_i32x4_shuffle(r2, r1, 0, 0, 4, 4); /* e e i i */ + x5 = wasm_i32x4_shuffle(r2, r1, 1, 1, 5, 5); /* f f j j */ + x3 = wasm_i32x4_shuffle(r2, r1, 2, 2, 6, 6); /* g g k k */ + x0 = wasm_i32x4_shuffle(r2, r1, 3, 3, 7, 7); /* h h l l */ + + t0 = wasm_f32x4_mul(x3, x1); + t1 = wasm_f32x4_mul(x5, x1); + t2 = wasm_f32x4_mul(x5, x2); + t3 = wasm_f32x4_mul(x6, x1); + t4 = wasm_f32x4_mul(x6, x2); + t5 = wasm_f32x4_mul(x6, x4); + + /* t1[0] = k * p - o * l; + t1[0] = k * p - o * l; + t2[0] = g * p - o * h; + t3[0] = g * l - k * h; */ + t0 = glmm_fnmadd(x2, x0, t0); + + /* t1[1] = j * p - n * l; + t1[1] = j * p - n * l; + t2[1] = f * p - n * h; + t3[1] = f * l - j * h; */ + t1 = glmm_fnmadd(x4, x0, t1); + + /* t1[2] = j * o - n * k + t1[2] = j * o - n * k; + t2[2] = f * o - n * g; + t3[2] = f * k - j * g; */ + t2 = glmm_fnmadd(x4, x3, t2); + + /* t1[3] = i * p - m * l; + t1[3] = i * p - m * l; + t2[3] = e * p - m * h; + t3[3] = e * l - i * h; */ + t3 = glmm_fnmadd(x7, x0, t3); + + /* t1[4] = i * o - m * k; + t1[4] = i * o - m * k; + t2[4] = e * o - m * g; + t3[4] = e * k - i * g; */ + t4 = glmm_fnmadd(x7, x3, t4); + + /* t1[5] = i * n - m * j; + t1[5] = i * n - m * j; + t2[5] = e * n - m * f; + t3[5] = e * j - i * f; */ + t5 = glmm_fnmadd(x7, x5, t5); + /* x4 = _mm_movelh_ps(r0, r1); */ + x4 = wasm_i32x4_shuffle(r0, r1, 0, 1, 4, 5); /* f e b a */ + /* x5 = _mm_movehl_ps(r1, r0); */ + x5 = wasm_i32x4_shuffle(r1, r0, 6, 7, 2, 3); /* h g d c */ + + x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ + x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ + x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ + x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ + + v2 = wasm_f32x4_mul(x0, t1); + v1 = wasm_f32x4_mul(x0, t0); + v3 = wasm_f32x4_mul(x0, t2); + v0 = wasm_f32x4_mul(x1, t0); + + v2 = glmm_fnmadd(x1, t3, v2); + v3 = glmm_fnmadd(x1, t4, v3); + v0 = glmm_fnmadd(x2, t1, v0); + v1 = glmm_fnmadd(x2, t3, v1); + + v3 = glmm_fmadd(x2, t5, v3); + v0 = glmm_fmadd(x3, t2, v0); + v2 = glmm_fmadd(x3, t5, v2); + v1 = glmm_fmadd(x3, t4, v1); + + /* + dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; + dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); + dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; + dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ + v0 = wasm_v128_xor(v0, x8); + + /* + dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; + dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); + dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; + dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ + v2 = wasm_v128_xor(v2, x8); + + /* + dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); + dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; + dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); + dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ + v1 = wasm_v128_xor(v1, x9); + + /* + dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); + dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; + dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); + dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ + v3 = wasm_v128_xor(v3, x9); + + /* determinant */ + x0 = wasm_i32x4_shuffle(v0, v1, 0, 0, 4, 4); + x1 = wasm_i32x4_shuffle(v2, v3, 0, 0, 4, 4); + x0 = wasm_i32x4_shuffle(x0, x1, 0, 2, 4, 6); + + /* x0 = _mm_rcp_ps(glmm_vhadd(wasm_f32x4_mul(x0, r0))); */ + x0 = wasm_f32x4_div(wasm_f32x4_const_splat(1.0f), + glmm_vhadd(wasm_f32x4_mul(x0, r0))); + + glmm_store(dest[0], wasm_f32x4_mul(v0, x0)); + glmm_store(dest[1], wasm_f32x4_mul(v1, x0)); + glmm_store(dest[2], wasm_f32x4_mul(v2, x0)); + glmm_store(dest[3], wasm_f32x4_mul(v3, x0)); +} + +CGLM_INLINE +void +glm_mat4_inv_wasm(mat4 mat, mat4 dest) { + glmm_128 r0, r1, r2, r3, + v0, v1, v2, v3, + t0, t1, t2, t3, t4, t5, + x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; + + x8 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); + x9 = glmm_shuff1(x8, 2, 1, 2, 1); + + /* 127 <- 0 */ + r0 = glmm_load(mat[0]); /* d c b a */ + r1 = glmm_load(mat[1]); /* h g f e */ + r2 = glmm_load(mat[2]); /* l k j i */ + r3 = glmm_load(mat[3]); /* p o n m */ + /* x0 = _mm_movehl_ps(r3, r2); */ + x0 = wasm_i32x4_shuffle(r3, r2, 6, 7, 2, 3); /* p o l k */ + /* x3 = _mm_movelh_ps(r2, r3); */ + x3 = wasm_i32x4_shuffle(r2, r3, 0, 1, 4, 5); /* n m j i */ + x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ + x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ + x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ + x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ + + x6 = wasm_i32x4_shuffle(r2, r1, 0, 0, 4, 4); /* e e i i */ + x5 = wasm_i32x4_shuffle(r2, r1, 1, 1, 5, 5); /* f f j j */ + x3 = wasm_i32x4_shuffle(r2, r1, 2, 2, 6, 6); /* g g k k */ + x0 = wasm_i32x4_shuffle(r2, r1, 3, 3, 7, 7); /* h h l l */ + + t0 = wasm_f32x4_mul(x3, x1); + t1 = wasm_f32x4_mul(x5, x1); + t2 = wasm_f32x4_mul(x5, x2); + t3 = wasm_f32x4_mul(x6, x1); + t4 = wasm_f32x4_mul(x6, x2); + t5 = wasm_f32x4_mul(x6, x4); + + /* t1[0] = k * p - o * l; + t1[0] = k * p - o * l; + t2[0] = g * p - o * h; + t3[0] = g * l - k * h; */ + t0 = glmm_fnmadd(x2, x0, t0); + + /* t1[1] = j * p - n * l; + t1[1] = j * p - n * l; + t2[1] = f * p - n * h; + t3[1] = f * l - j * h; */ + t1 = glmm_fnmadd(x4, x0, t1); + + /* t1[2] = j * o - n * k + t1[2] = j * o - n * k; + t2[2] = f * o - n * g; + t3[2] = f * k - j * g; */ + t2 = glmm_fnmadd(x4, x3, t2); + + /* t1[3] = i * p - m * l; + t1[3] = i * p - m * l; + t2[3] = e * p - m * h; + t3[3] = e * l - i * h; */ + t3 = glmm_fnmadd(x7, x0, t3); + + /* t1[4] = i * o - m * k; + t1[4] = i * o - m * k; + t2[4] = e * o - m * g; + t3[4] = e * k - i * g; */ + t4 = glmm_fnmadd(x7, x3, t4); + + /* t1[5] = i * n - m * j; + t1[5] = i * n - m * j; + t2[5] = e * n - m * f; + t3[5] = e * j - i * f; */ + t5 = glmm_fnmadd(x7, x5, t5); + /* x4 = _mm_movelh_ps(r0, r1); */ + x4 = wasm_i32x4_shuffle(r0, r1, 0, 1, 4, 5); /* f e b a */ + /* x5 = _mm_movehl_ps(r1, r0); */ + x5 = wasm_i32x4_shuffle(r1, r0, 6, 7, 2, 3); /* h g d c */ + + x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ + x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ + x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ + x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ + + v2 = wasm_f32x4_mul(x0, t1); + v1 = wasm_f32x4_mul(x0, t0); + v3 = wasm_f32x4_mul(x0, t2); + v0 = wasm_f32x4_mul(x1, t0); + + v2 = glmm_fnmadd(x1, t3, v2); + v3 = glmm_fnmadd(x1, t4, v3); + v0 = glmm_fnmadd(x2, t1, v0); + v1 = glmm_fnmadd(x2, t3, v1); + + v3 = glmm_fmadd(x2, t5, v3); + v0 = glmm_fmadd(x3, t2, v0); + v2 = glmm_fmadd(x3, t5, v2); + v1 = glmm_fmadd(x3, t4, v1); + + /* + dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; + dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); + dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; + dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ + v0 = wasm_v128_xor(v0, x8); + + /* + dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; + dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); + dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; + dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ + v2 = wasm_v128_xor(v2, x8); + + /* + dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); + dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; + dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); + dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ + v1 = wasm_v128_xor(v1, x9); + + /* + dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); + dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; + dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); + dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ + v3 = wasm_v128_xor(v3, x9); + + /* determinant */ + x0 = wasm_i32x4_shuffle(v0, v1, 0, 0, 4, 4); + x1 = wasm_i32x4_shuffle(v2, v3, 0, 0, 4, 4); + x0 = wasm_i32x4_shuffle(x0, x1, 0, 2, 4, 6); + + x0 = wasm_f32x4_div(wasm_f32x4_splat(1.0f), glmm_vhadd(wasm_f32x4_mul(x0, r0))); + + glmm_store(dest[0], wasm_f32x4_mul(v0, x0)); + glmm_store(dest[1], wasm_f32x4_mul(v1, x0)); + glmm_store(dest[2], wasm_f32x4_mul(v2, x0)); + glmm_store(dest[3], wasm_f32x4_mul(v3, x0)); +} + +#endif +#endif /* cglm_mat_wasm_h */ diff --git a/include/cglm/simd/wasm/quat.h b/include/cglm/simd/wasm/quat.h new file mode 100644 index 0000000..927ea21 --- /dev/null +++ b/include/cglm/simd/wasm/quat.h @@ -0,0 +1,54 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_quat_wasm_h +#define cglm_quat_wasm_h +#if defined(__wasm__) && defined(__wasm_simd128__) + +#include "../../common.h" +#include "../intrin.h" + +CGLM_INLINE +void +glm_quat_mul_wasm(versor p, versor q, versor dest) { + /* + + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k + a1 a2 − b1 b2 − c1 c2 − d1 d2 + */ + + glmm_128 xp, xq, x1, x2, x3, r, x, y, z; + + xp = glmm_load(p); /* 3 2 1 0 */ + xq = glmm_load(q); + x1 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); /* TODO: _mm_set1_ss() + shuff ? */ + r = wasm_f32x4_mul(glmm_splat_w(xp), xq); + /* x2 = _mm_unpackhi_ps(x1, x1); */ + x2 = wasm_i32x4_shuffle(x1, x1, 2, 6, 3, 7); + x3 = glmm_shuff1(x1, 3, 2, 0, 1); + x = glmm_splat_x(xp); + y = glmm_splat_y(xp); + z = glmm_splat_z(xp); + + x = wasm_v128_xor(x, x1); + y = wasm_v128_xor(y, x2); + z = wasm_v128_xor(z, x3); + + x1 = glmm_shuff1(xq, 0, 1, 2, 3); + x2 = glmm_shuff1(xq, 1, 0, 3, 2); + x3 = glmm_shuff1(xq, 2, 3, 0, 1); + + r = glmm_fmadd(x, x1, r); + r = glmm_fmadd(y, x2, r); + r = glmm_fmadd(z, x3, r); + + glmm_store(dest, r); +} + +#endif +#endif /* cglm_quat_wasm_h */ diff --git a/include/cglm/vec4-ext.h b/include/cglm/vec4-ext.h index e4e20cb..cccbb72 100644 --- a/include/cglm/vec4-ext.h +++ b/include/cglm/vec4-ext.h @@ -45,7 +45,9 @@ CGLM_INLINE void glm_vec4_broadcast(float val, vec4 d) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(d, wasm_f32x4_splat(val)); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(d, _mm_set1_ps(val)); #else d[0] = d[1] = d[2] = d[3] = val; @@ -61,7 +63,9 @@ glm_vec4_broadcast(float val, vec4 d) { CGLM_INLINE void glm_vec4_fill(vec4 v, float val) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(v, wasm_f32x4_splat(val)); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(v, _mm_set1_ps(val)); #else v[0] = v[1] = v[2] = v[3] = val; @@ -247,7 +251,9 @@ glm_vec4_sign(vec4 v, vec4 dest) { CGLM_INLINE void glm_vec4_abs(vec4 v, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, glmm_abs(glmm_load(v))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, glmm_abs(glmm_load(v))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vabsq_f32(vld1q_f32(v))); @@ -284,7 +290,9 @@ glm_vec4_fract(vec4 v, vec4 dest) { CGLM_INLINE float glm_vec4_hadd(vec4 v) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + return glmm_hadd(glmm_load(v)); +#elif defined( __SSE__ ) || defined( __SSE2__ ) return glmm_hadd(glmm_load(v)); #else return v[0] + v[1] + v[2] + v[3]; @@ -300,7 +308,9 @@ glm_vec4_hadd(vec4 v) { CGLM_INLINE void glm_vec4_sqrt(vec4 v, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_sqrt(glmm_load(v))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sqrt_ps(glmm_load(v))); #else dest[0] = sqrtf(v[0]); diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h index 8e95ec5..de29941 100644 --- a/include/cglm/vec4.h +++ b/include/cglm/vec4.h @@ -137,7 +137,9 @@ glm_vec4_copy3(vec4 a, vec3 dest) { CGLM_INLINE void glm_vec4_copy(vec4 v, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, glmm_load(v)); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, glmm_load(v)); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vld1q_f32(v)); @@ -160,10 +162,15 @@ glm_vec4_copy(vec4 v, vec4 dest) { CGLM_INLINE void glm_vec4_ucopy(vec4 v, vec4 dest) { +#if defined(__wasm__) && defined(__wasm_simd128__) + /* note here wasm v128.load/v128.store support unaligned loads and stores */ + wasm_v128_store(dest, wasm_v128_load(v)); +#else dest[0] = v[0]; dest[1] = v[1]; dest[2] = v[2]; dest[3] = v[3]; +#endif } /*! @@ -174,7 +181,9 @@ glm_vec4_ucopy(vec4 v, vec4 dest) { CGLM_INLINE void glm_vec4_zero(vec4 v) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(v, wasm_f32x4_const_splat(0.f)); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(v, _mm_setzero_ps()); #elif defined(CGLM_NEON_FP) vst1q_f32(v, vdupq_n_f32(0.0f)); @@ -194,7 +203,9 @@ glm_vec4_zero(vec4 v) { CGLM_INLINE void glm_vec4_one(vec4 v) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(v, wasm_f32x4_const_splat(1.0f)); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(v, _mm_set1_ps(1.0f)); #elif defined(CGLM_NEON_FP) vst1q_f32(v, vdupq_n_f32(1.0f)); @@ -320,7 +331,9 @@ glm_vec4_norm_inf(vec4 v) { CGLM_INLINE void glm_vec4_add(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_add(glmm_load(a), glmm_load(b))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vaddq_f32(vld1q_f32(a), vld1q_f32(b))); @@ -342,7 +355,9 @@ glm_vec4_add(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_adds(vec4 v, float s, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_add(glmm_load(v), wasm_f32x4_splat(s))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(v), _mm_set1_ps(s))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vaddq_f32(vld1q_f32(v), vdupq_n_f32(s))); @@ -364,7 +379,9 @@ glm_vec4_adds(vec4 v, float s, vec4 dest) { CGLM_INLINE void glm_vec4_sub(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_sub(glmm_load(a), glmm_load(b))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sub_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vsubq_f32(vld1q_f32(a), vld1q_f32(b))); @@ -386,7 +403,9 @@ glm_vec4_sub(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_subs(vec4 v, float s, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_sub(glmm_load(v), wasm_f32x4_splat(s))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sub_ps(glmm_load(v), _mm_set1_ps(s))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vsubq_f32(vld1q_f32(v), vdupq_n_f32(s))); @@ -408,7 +427,9 @@ glm_vec4_subs(vec4 v, float s, vec4 dest) { CGLM_INLINE void glm_vec4_mul(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_mul(glmm_load(a), glmm_load(b))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_mul_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vmulq_f32(vld1q_f32(a), vld1q_f32(b))); @@ -430,7 +451,9 @@ glm_vec4_mul(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_scale(vec4 v, float s, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_mul(glmm_load(v), wasm_f32x4_splat(s))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_mul_ps(glmm_load(v), _mm_set1_ps(s))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vmulq_f32(vld1q_f32(v), vdupq_n_f32(s))); @@ -493,7 +516,9 @@ glm_vec4_div(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_divs(vec4 v, float s, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_div(glmm_load(v), wasm_f32x4_splat(s))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_div_ps(glmm_load(v), _mm_set1_ps(s))); #else glm_vec4_scale(v, 1.0f / s, dest); @@ -512,7 +537,11 @@ glm_vec4_divs(vec4 v, float s, vec4 dest) { CGLM_INLINE void glm_vec4_addadd(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_add( + glmm_load(dest), + wasm_f32x4_add(glmm_load(a), glmm_load(b)))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(dest), _mm_add_ps(glmm_load(a), glmm_load(b)))); @@ -540,7 +569,11 @@ glm_vec4_addadd(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_subadd(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_add( + glmm_load(dest), + wasm_f32x4_sub(glmm_load(a), glmm_load(b)))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(dest), _mm_sub_ps(glmm_load(a), glmm_load(b)))); @@ -612,7 +645,11 @@ glm_vec4_muladds(vec4 a, float s, vec4 dest) { CGLM_INLINE void glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_add( + glmm_load(dest), + wasm_f32x4_max(glmm_load(a), glmm_load(b)))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(dest), _mm_max_ps(glmm_load(a), glmm_load(b)))); @@ -640,7 +677,11 @@ glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_minadd(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_add( + glmm_load(dest), + wasm_f32x4_min(glmm_load(a), glmm_load(b)))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(dest), _mm_min_ps(glmm_load(a), glmm_load(b)))); @@ -665,7 +706,9 @@ glm_vec4_minadd(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_negate_to(vec4 v, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_neg(glmm_load(v))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_xor_ps(glmm_load(v), _mm_set1_ps(-0.0f))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vnegq_f32(vld1q_f32(v))); @@ -697,7 +740,22 @@ glm_vec4_negate(vec4 v) { CGLM_INLINE void glm_vec4_normalize_to(vec4 v, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_128 xdot, x0; + float dot; + + x0 = glmm_load(v); + xdot = glmm_vdot(x0, x0); + /* dot = _mm_cvtss_f32(xdot); */ + dot = wasm_f32x4_extract_lane(xdot, 0); + + if (dot == 0.0f) { + glmm_store(dest, wasm_f32x4_const_splat(0.f)); + return; + } + + glmm_store(dest, wasm_f32x4_div(x0, wasm_f32x4_sqrt(xdot))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) __m128 xdot, x0; float dot; @@ -746,7 +804,9 @@ glm_vec4_normalize(vec4 v) { CGLM_INLINE float glm_vec4_distance(vec4 a, vec4 b) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + return glmm_norm(wasm_f32x4_sub(glmm_load(a), glmm_load(b))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) return glmm_norm(_mm_sub_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) return glmm_norm(vsubq_f32(glmm_load(a), glmm_load(b))); @@ -768,7 +828,9 @@ glm_vec4_distance(vec4 a, vec4 b) { CGLM_INLINE float glm_vec4_distance2(vec4 a, vec4 b) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + return glmm_norm2(wasm_f32x4_sub(glmm_load(a), glmm_load(b))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) return glmm_norm2(_mm_sub_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) return glmm_norm2(vsubq_f32(glmm_load(a), glmm_load(b))); @@ -790,7 +852,9 @@ glm_vec4_distance2(vec4 a, vec4 b) { CGLM_INLINE void glm_vec4_maxv(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_max(glmm_load(a), glmm_load(b))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_max_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vmaxq_f32(vld1q_f32(a), vld1q_f32(b))); @@ -812,7 +876,9 @@ glm_vec4_maxv(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_minv(vec4 a, vec4 b, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(dest, wasm_f32x4_min(glmm_load(a), glmm_load(b))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_min_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vminq_f32(vld1q_f32(a), vld1q_f32(b))); @@ -834,7 +900,11 @@ glm_vec4_minv(vec4 a, vec4 b, vec4 dest) { CGLM_INLINE void glm_vec4_clamp(vec4 v, float minVal, float maxVal) { -#if defined( __SSE__ ) || defined( __SSE2__ ) +#if defined(__wasm__) && defined(__wasm_simd128__) + glmm_store(v, wasm_f32x4_min( + wasm_f32x4_max(glmm_load(v), wasm_f32x4_splat(minVal)), + wasm_f32x4_splat(maxVal))); +#elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(v, _mm_min_ps(_mm_max_ps(glmm_load(v), _mm_set1_ps(minVal)), _mm_set1_ps(maxVal))); #elif defined(CGLM_NEON_FP) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 26fef9c..0c76203 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,6 +22,11 @@ set(TEST_RUNNER_PARAMS "") add_executable(${TEST_MAIN} ${TESTFILES}) target_compile_definitions(${TEST_MAIN} PRIVATE CGLM_DEFINE_PRINTS=1) +if(CMAKE_SYSTEM_NAME STREQUAL WASI) + target_compile_definitions(${TEST_MAIN} PRIVATE _WASI_EMULATED_PROCESS_CLOCKS=1) + target_link_options(${TEST_MAIN} PRIVATE "-lwasi-emulated-process-clocks") +endif() + if(NOT MSVC) target_link_libraries(${TEST_MAIN} PRIVATE m) endif()