Index: src/core/Sk4x.h |
diff --git a/src/core/Sk4x.h b/src/core/Sk4x.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c1933a14dfff1c19199d96c4bae82b0497ff9001 |
--- /dev/null |
+++ b/src/core/Sk4x.h |
@@ -0,0 +1,96 @@ |
+#ifndef Sk4x_DEFINED |
+#define Sk4x_DEFINED |
+ |
+// Sk4x.h brings the fun of GCC vector extensions* to platforms without them (MSVC). |
+// We also paper over some of the differences between GCC and Clang's flavors. |
+// |
+// * https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html |
+// http://clang.llvm.org/docs/LanguageExtensions.html#vectors-and-extended-vectors |
+ |
+// First code common to both Clang and GCC. |
+#if defined(__GNUC__) |
+ typedef float Sk4f __attribute__((vector_size(16))); |
+ typedef int Sk4i __attribute__((vector_size(16))); |
+#endif |
+ |
+// Now code specialized for Clang xor GCC. |
+#if defined(__clang__) |
+ #define Sk4Shuffle(x,y, m,a,s,k) __builtin_shufflevector(x,y, m,a,s,k) |
+ |
+ #if __has_builtin(__builtin_convertvector) |
+ template<typename D, typename S> |
+ D Sk4Convert(S src) { return __builtin_convertvector(src, D); } |
+ #else |
+ template<typename D, typename S> |
+ D Sk4Convert(S src) { |
+ D dst = { (D)src[0], (D)src[1], (D)src[2], (D)src[3] }; |
+ return dst; |
+ } |
+ #endif |
+ |
+#elif defined(__GNUC__) |
+ template <typename V> |
+ V Sk4Shuffle(V x, V y, int m, int a, int s, int k) { |
+ Sk4i mask = { m, a, s, k }; |
+ return __builtin_shuffle(x, y, mask); |
+ } |
+ |
+ template<typename D, typename S> |
+ D Sk4Convert(S src) { |
+ D dst = { (D)src[0], (D)src[1], (D)src[2], (D)src[3] }; |
+ return dst; |
+ } |
+ |
+#endif |
+ |
+#if !defined(__GNUC__) |
+ #error "Need to implement scalar versions." |
+#endif |
+ |
+ |
+// Finally code that will work no matter the implementation. |
+inline Sk4f SkLoad4f(float a, float b, float c, float d) { |
+ Sk4f v = { a, b, c, d }; |
+ return v; |
+} |
+ |
+inline Sk4i SkLoad4i(int a, int b, int c, int d) { |
+ Sk4i v = { a, b, c, d }; |
+ return v; |
+} |
+ |
+inline Sk4f SkLoad4f(const float fs[4]) { |
+ Sk4f v = { fs[0], fs[1], fs[2], fs[3] }; |
+ return v; |
+} |
+ |
+inline Sk4i SkLoad4i(const int is[4]) { |
+ Sk4i v = { is[0], is[1], is[2], is[3] }; |
+ return v; |
+} |
+ |
+inline void SkStore4(Sk4f v, float fs[4]) { |
+ *reinterpret_cast<Sk4f*>(fs) = v; |
+} |
+ |
+inline void SkStore4(Sk4i v, int is[4]) { |
+ *reinterpret_cast<Sk4i*>(is) = v; |
+} |
+ |
+inline bool Sk4All(Sk4i v) { |
reed1
2014/10/10 16:06:11
as we start to actually use these, we might discus
mtklein
2014/10/10 21:26:07
See what you think of the API at PS 20?
|
+ return v[0] & v[1] & v[2] & v[3]; |
+} |
+ |
+template <typename V> |
+V Sk4Min(V a, V b) { |
+ Sk4i less = a < b; |
+ return ((Sk4i)a & less) | ((Sk4i)b & ~less); |
+} |
+ |
+template <typename V> |
+V Sk4Max(V a, V b) { |
+ Sk4i less = a < b; |
+ return ((Sk4i)b & less) | ((Sk4i)a & ~less); |
+} |
+ |
+#endif//Sk4x_DEFINED |