/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef __clang__ # ifdef __SSE2__ # include # define USE_SSE2 1 # endif # ifdef __ARM_NEON # include # define USE_NEON 1 # endif #endif namespace glsl { #ifdef __clang__ template using VectorType = T __attribute__((ext_vector_type(N))); # define CONVERT(vector, type) __builtin_convertvector(vector, type) # define SHUFFLE(a, b, ...) __builtin_shufflevector(a, b, __VA_ARGS__) template SI VectorType combine(VectorType a, VectorType b) { return __builtin_shufflevector(a, b, 0, 1, 2, 3); } template SI VectorType combine(VectorType a, VectorType b) { return __builtin_shufflevector(a, b, 0, 1, 2, 3, 4, 5, 6, 7); } template SI VectorType combine(VectorType a, VectorType b) { return __builtin_shufflevector(a, b, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); } template SI VectorType lowHalf(VectorType a) { return __builtin_shufflevector(a, a, 0, 1); } template SI VectorType highHalf(VectorType a) { return __builtin_shufflevector(a, a, 2, 3); } template SI VectorType lowHalf(VectorType a) { return __builtin_shufflevector(a, a, 0, 1, 2, 3); } template SI VectorType highHalf(VectorType a) { return __builtin_shufflevector(a, a, 4, 5, 6, 7); } template SI VectorType lowHalf(VectorType a) { return __builtin_shufflevector(a, a, 0, 1, 2, 3, 4, 5, 6, 7); } template SI VectorType highHalf(VectorType a) { return __builtin_shufflevector(a, a, 8, 9, 10, 11, 12, 13, 14, 15); } template SI VectorType expand(VectorType a) { return __builtin_shufflevector(a, a, 0, 1, 2, 3, -1, -1, -1, -1); } #else template struct VectorMask { typedef T type; }; template <> struct VectorMask { typedef int32_t type; }; template <> struct VectorMask { typedef int16_t type; }; template <> struct VectorMask { typedef int8_t type; }; template <> struct VectorMask { typedef int type; }; template struct VectorType { enum { SIZE = N }; typedef T data_type __attribute__((vector_size(sizeof(T) * N))); typedef typename VectorMask::type mask_index; typedef mask_index mask_type __attribute__((vector_size(sizeof(mask_index) * N))); typedef T half_type __attribute__((vector_size(sizeof(T) * (N / 2)))); union { data_type data; struct { T x, y, z, w; }; T elements[N]; struct { half_type low_half, high_half; }; }; VectorType() : data{0} {} constexpr VectorType(const VectorType& rhs) : data(rhs.data) {} // GCC vector extensions only support broadcasting scalars on arithmetic ops, // but not on initializers, hence the following... constexpr VectorType(T n) : data((data_type){0} + n) {} constexpr VectorType(T a, T b, T c, T d) : data{a, b, c, d} {} constexpr VectorType(T a, T b, T c, T d, T e, T f, T g, T h) : data{a, b, c, d, e, f, g, h} {} constexpr VectorType(T a, T b, T c, T d, T e, T f, T g, T h, T i, T j, T k, T l, T m, T n, T o, T p) : data{a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p} {} SI VectorType wrap(const data_type& data) { VectorType v; v.data = data; return v; } T& operator[](size_t i) { return elements[i]; } T operator[](size_t i) const { return elements[i]; } template operator VectorType() const { return VectorType::wrap( (typename VectorType::data_type){U(x), U(y)}); } template operator VectorType() const { return VectorType::wrap( (typename VectorType::data_type){U(x), U(y), U(z), U(w)}); } template operator VectorType() const { return VectorType::wrap((typename VectorType::data_type){ U(elements[0]), U(elements[1]), U(elements[2]), U(elements[3]), U(elements[4]), U(elements[5]), U(elements[6]), U(elements[7])}); } template operator VectorType() const { return VectorType::wrap((typename VectorType::data_type){ U(elements[0]), U(elements[1]), U(elements[2]), U(elements[3]), U(elements[4]), U(elements[5]), U(elements[6]), U(elements[7]), U(elements[8]), U(elements[9]), U(elements[10]), U(elements[11]), U(elements[12]), U(elements[13]), U(elements[14]), U(elements[15]), }); } VectorType operator-() const { return wrap(-data); } VectorType operator~() const { return wrap(~data); } VectorType operator&(VectorType x) const { return wrap(data & x.data); } VectorType operator&(T x) const { return wrap(data & x); } VectorType operator|(VectorType x) const { return wrap(data | x.data); } VectorType operator|(T x) const { return wrap(data | x); } VectorType operator^(VectorType x) const { return wrap(data ^ x.data); } VectorType operator^(T x) const { return wrap(data ^ x); } VectorType operator<<(int x) const { return wrap(data << x); } VectorType operator>>(int x) const { return wrap(data >> x); } VectorType operator+(VectorType x) const { return wrap(data + x.data); } VectorType operator+(T x) const { return wrap(data + x); } friend VectorType operator+(T x, VectorType y) { return wrap(x + y.data); } VectorType operator-(VectorType x) const { return wrap(data - x.data); } VectorType operator-(T x) const { return wrap(data - x); } friend VectorType operator-(T x, VectorType y) { return wrap(x - y.data); } VectorType operator*(VectorType x) const { return wrap(data * x.data); } VectorType operator*(T x) const { return wrap(data * x); } friend VectorType operator*(T x, VectorType y) { return wrap(x * y.data); } VectorType operator/(VectorType x) const { return wrap(data / x.data); } VectorType operator/(T x) const { return wrap(data / x); } friend VectorType operator/(T x, VectorType y) { return wrap(x / y.data); } VectorType operator%(int x) const { return wrap(data % x); } VectorType& operator&=(VectorType x) { data &= x.data; return *this; } VectorType& operator|=(VectorType x) { data |= x.data; return *this; } VectorType& operator^=(VectorType x) { data ^= x.data; return *this; } VectorType& operator<<=(int x) { data <<= x; return *this; } VectorType& operator>>=(int x) { data >>= x; return *this; } VectorType& operator+=(VectorType x) { data += x.data; return *this; } VectorType& operator-=(VectorType x) { data -= x.data; return *this; } VectorType& operator*=(VectorType x) { data *= x.data; return *this; } VectorType& operator/=(VectorType x) { data /= x.data; return *this; } VectorType& operator%=(int x) { data %= x; return *this; } VectorType operator==(VectorType x) const { return VectorType::wrap(data == x.data); } VectorType operator!=(VectorType x) const { return VectorType::wrap(data != x.data); } VectorType operator<(VectorType x) const { return VectorType::wrap(data < x.data); } VectorType operator>(VectorType x) const { return VectorType::wrap(data > x.data); } VectorType operator<=(VectorType x) const { return VectorType::wrap(data <= x.data); } VectorType operator>=(VectorType x) const { return VectorType::wrap(data >= x.data); } VectorType operator!() const { return wrap(!data); } VectorType operator&&(VectorType x) const { return wrap(data & x.data); } VectorType operator||(VectorType x) const { return wrap(data | x.data); } VectorType& operator=(VectorType x) { data = x.data; return *this; } VectorType shuffle(VectorType b, mask_index x, mask_index y, mask_index z, mask_index w) const { return VectorType::wrap(__builtin_shuffle( data, b.data, (typename VectorType::mask_type){x, y, z, w})); } VectorType shuffle(VectorType b, mask_index x, mask_index y, mask_index z, mask_index w, mask_index s, mask_index t, mask_index u, mask_index v) const { return VectorType::wrap(__builtin_shuffle( data, b.data, (typename VectorType::mask_type){x, y, z, w, s, t, u, v})); } VectorType shuffle(VectorType b, mask_index x, mask_index y, mask_index z, mask_index w, mask_index s, mask_index t, mask_index u, mask_index v, mask_index i, mask_index j, mask_index k, mask_index l, mask_index m, mask_index n, mask_index o, mask_index p) const { return VectorType::wrap( __builtin_shuffle(data, b.data, (typename VectorType::mask_type){ x, y, z, w, s, t, u, v, i, j, k, l, m, n, o, p})); } VectorType swizzle(mask_index x, mask_index y, mask_index z, mask_index w) const { return VectorType::wrap(__builtin_shuffle( data, (typename VectorType::mask_type){x, y, z, w})); } VectorType swizzle(mask_index x, mask_index y, mask_index z, mask_index w, mask_index s, mask_index t, mask_index u, mask_index v) const { return VectorType::wrap(__builtin_shuffle( data, (typename VectorType::mask_type){x, y, z, w, s, t, u, v})); } SI VectorType wrap(half_type low, half_type high) { VectorType v; v.low_half = low; v.high_half = high; return v; } VectorType combine(VectorType high) const { return VectorType::wrap(data, high.data); } # define xxxx swizzle(0, 0, 0, 0) # define yyyy swizzle(1, 1, 1, 1) # define zzzz swizzle(2, 2, 2, 2) # define wwww swizzle(3, 3, 3, 3) # define xxyy swizzle(0, 0, 1, 1) # define xxzz swizzle(0, 0, 2, 2) # define yyww swizzle(1, 1, 3, 3) # define zzww swizzle(2, 2, 3, 3) # define xyxy swizzle(0, 1, 0, 1) # define xzxz swizzle(0, 2, 0, 2) # define ywyw swizzle(1, 3, 1, 3) # define zwzw swizzle(2, 3, 2, 3) # define zwxy swizzle(2, 3, 0, 1) # define zyxw swizzle(2, 1, 0, 3) # define xxyz swizzle(0, 0, 1, 2) # define xyyz swizzle(0, 1, 1, 2) # define xyzz swizzle(0, 1, 2, 2) # define xzyw swizzle(0, 2, 1, 3) # define yzwx swizzle(1, 2, 3, 0) # define wxyz swizzle(3, 0, 1, 2) # define wzyx swizzle(3, 2, 1, 0) # define xxxxyyyy XXXXYYYY() VectorType XXXXYYYY() const { return swizzle(0, 0, 0, 0).combine(swizzle(1, 1, 1, 1)); } # define zzzzwwww ZZZZWWWW() VectorType ZZZZWWWW() const { return swizzle(2, 2, 2, 2).combine(swizzle(3, 3, 3, 3)); } # define xyzwxyzw XYZWXYZW() VectorType XYZWXYZW() const { return combine(*this); } # define xyxyxyxy XYXYXYXY() VectorType XYXYXYXY() const { return swizzle(0, 1, 0, 1).combine(swizzle(0, 1, 0, 1)); } # define zwzwzwzw ZWZWZWZW() VectorType ZWZWZWZW() const { return swizzle(2, 3, 2, 3).combine(swizzle(2, 3, 2, 3)); } # define xxyyzzww XXYYZZWW() VectorType XXYYZZWW() const { return swizzle(0, 0, 1, 1).combine(swizzle(2, 2, 3, 3)); } # define xxxxyyyyzzzzwwww XXXXYYYYZZZZWWWW() VectorType XXXXYYYYZZZZWWWW() { return XXXXYYYY().combine(ZZZZWWWW()); } }; template struct VectorType { typedef T data_type __attribute__((vector_size(sizeof(T) * 2))); union { data_type data; struct { T x, y; }; T elements[2]; }; SI VectorType wrap(const data_type& data) { VectorType v; v.data = data; return v; } VectorType operator&(VectorType x) const { return wrap(data & x.data); } VectorType operator&(T x) const { return wrap(data & x); } VectorType operator|(VectorType x) const { return wrap(data | x.data); } VectorType operator|(T x) const { return wrap(data | x); } }; # define CONVERT(vector, type) ((type)(vector)) # define SHUFFLE(a, b, ...) a.shuffle(b, __VA_ARGS__) template SI VectorType combine(VectorType a, VectorType b) { return VectorType::wrap(a.data, b.data); } template SI VectorType lowHalf(VectorType a) { return VectorType::wrap(a.low_half); } template SI VectorType highHalf(VectorType a) { return VectorType::wrap(a.high_half); } template SI VectorType expand(VectorType a) { return combine(a, a); } #endif template SI VectorType combine(VectorType a, VectorType b, VectorType c, VectorType d) { return combine(combine(a, b), combine(c, d)); } template SI VectorType combineLow(VectorType a, VectorType b) { return combine(lowHalf(a), lowHalf(b)); } template SI VectorType combineHigh(VectorType a, VectorType b) { return combine(highHalf(a), highHalf(b)); } template SI VectorType repeat2(VectorType a) { return combine(a, a); } template SI VectorType repeat4(VectorType a) { return combine(a, a, a, a); } template SI VectorType zipLow(VectorType a, VectorType b) { return SHUFFLE(a, b, 0, 4, 1, 5); } template SI VectorType zipHigh(VectorType a, VectorType b) { return SHUFFLE(a, b, 2, 6, 3, 7); } template SI VectorType zipLow(VectorType a, VectorType b) { return SHUFFLE(a, b, 0, 8, 1, 9, 2, 10, 3, 11); } template SI VectorType zipHigh(VectorType a, VectorType b) { return SHUFFLE(a, b, 4, 12, 5, 13, 6, 14, 7, 15); } template SI VectorType zipLow(VectorType a, VectorType b) { return SHUFFLE(a, b, 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23); } template SI VectorType zipHigh(VectorType a, VectorType b) { return SHUFFLE(a, b, 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31); } template SI VectorType zip2Low(VectorType a, VectorType b) { return SHUFFLE(a, b, 0, 1, 8, 9, 2, 3, 10, 11); } template SI VectorType zip2High(VectorType a, VectorType b) { return SHUFFLE(a, b, 4, 5, 12, 13, 6, 7, 14, 15); } #ifdef __clang__ template SI VectorType zip(VectorType a, VectorType b) { return SHUFFLE(a, b, 0, 4, 1, 5, 2, 6, 3, 7); } template SI VectorType zip(VectorType a, VectorType b) { return SHUFFLE(a, b, 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15); } #else template SI VectorType zip(VectorType a, VectorType b) { return combine(zipLow(a, b), zipHigh(a, b)); } #endif template struct Unaligned { template SI T load(const P* p) { T v; memcpy(&v, p, sizeof(v)); return v; } template SI void store(P* p, T v) { memcpy(p, &v, sizeof(v)); } }; #ifndef __clang__ template struct Unaligned> { template SI VectorType load(const P* p) { VectorType v; memcpy(v.elements, p, sizeof(v)); return v; } template SI void store(P* p, VectorType v) { memcpy(p, v.elements, sizeof(v)); } }; #endif template SI T unaligned_load(const P* p) { return Unaligned::load(p); } template SI void unaligned_store(P* p, T v) { Unaligned::store(p, v); } template SI D bit_cast(const S& src) { static_assert(sizeof(D) == sizeof(S), ""); return unaligned_load(&src); } template using V2 = VectorType; template using V4 = VectorType; using Float = V4; using I32 = V4; using I16 = V4; using U64 = V4; using U32 = V4; using U16 = V4; using U8 = V4; using Bool = V4; template using V8 = VectorType; template using V16 = VectorType; } // namespace glsl