From 6f37b4a4757ea3eb00c76162cc37f8a56c3b8bdb Mon Sep 17 00:00:00 2001 From: mtklein Date: Mon, 14 Dec 2015 11:25:18 -0800 Subject: Unify some SkNx code - one base case and one N=1 case instead of two each (or three with doubles) - use SkNx_cast instead of FromBytes/toBytes - 4-at-a-time Sk4f::ToBytes becomes a special standalone Sk4f_ToBytes If I did everything right, this'll be perf- and pixel- neutral. https://gold.skia.org/search2?issue=1526523003&unt=true&query=source_type%3Dgm&master=false BUG=skia: CQ_EXTRA_TRYBOTS=client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot Review URL: https://codereview.chromium.org/1526523003 --- src/opts/SkNx_sse.h | 91 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 30 deletions(-) (limited to 'src/opts/SkNx_sse.h') diff --git a/src/opts/SkNx_sse.h b/src/opts/SkNx_sse.h index 9092f44480..f3952a9768 100644 --- a/src/opts/SkNx_sse.h +++ b/src/opts/SkNx_sse.h @@ -111,37 +111,9 @@ public: SkNx(float val) : fVec( _mm_set1_ps(val) ) {} static SkNx Load(const float vals[4]) { return _mm_loadu_ps(vals); } - static SkNx FromBytes(const uint8_t bytes[4]) { - __m128i fix8 = _mm_cvtsi32_si128(*(const int*)bytes); - #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 - const char _ = ~0; // Zero these bytes. - __m128i fix8_32 = _mm_shuffle_epi8(fix8, _mm_setr_epi8(0,_,_,_, 1,_,_,_, 2,_,_,_, 3,_,_,_)); - #else - __m128i fix8_16 = _mm_unpacklo_epi8 (fix8, _mm_setzero_si128()), - fix8_32 = _mm_unpacklo_epi16(fix8_16, _mm_setzero_si128()); - #endif - return SkNx(_mm_cvtepi32_ps(fix8_32)); - // TODO: use _mm_cvtepu8_epi32 w/SSE4.1? - } - SkNx(float a, float b, float c, float d) : fVec(_mm_setr_ps(a,b,c,d)) {} void store(float vals[4]) const { _mm_storeu_ps(vals, fVec); } - void toBytes(uint8_t bytes[4]) const { - __m128i fix8_32 = _mm_cvttps_epi32(fVec), - fix8_16 = _mm_packus_epi16(fix8_32, fix8_32), - fix8 = _mm_packus_epi16(fix8_16, fix8_16); - *(int*)bytes = _mm_cvtsi128_si32(fix8); - } - - static void ToBytes(uint8_t bytes[16], - const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { - _mm_storeu_si128((__m128i*)bytes, - _mm_packus_epi16(_mm_packus_epi16(_mm_cvttps_epi32(a.fVec), - _mm_cvttps_epi32(b.fVec)), - _mm_packus_epi16(_mm_cvttps_epi32(c.fVec), - _mm_cvttps_epi32(d.fVec)))); - } SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); } SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); } @@ -252,6 +224,34 @@ public: __m128i fVec; }; +template <> +class SkNx<4, uint8_t> { +public: + SkNx(const __m128i& vec) : fVec(vec) {} + + SkNx() {} + static SkNx Load(const uint8_t vals[4]) { return _mm_cvtsi32_si128(*(const int*)vals); } + void store(uint8_t vals[4]) const { *(int*)vals = _mm_cvtsi128_si32(fVec); } + + // TODO as needed + + __m128i fVec; +}; + +template <> +class SkNx<8, uint8_t> { +public: + SkNx(const __m128i& vec) : fVec(vec) {} + + SkNx() {} + static SkNx Load(const uint8_t vals[8]) { return _mm_loadl_epi64((const __m128i*)vals); } + void store(uint8_t vals[8]) const { _mm_storel_epi64((__m128i*)vals, fVec); } + + // TODO as needed + + __m128i fVec; +}; + template <> class SkNx<16, uint8_t> { public: @@ -296,11 +296,42 @@ public: }; -template<> -inline SkNx<4, int> SkNx_cast(const SkNx<4, float>& src) { +template<> inline Sk4i SkNx_cast(const Sk4f& src) { return _mm_cvttps_epi32(src.fVec); } +template<> inline Sk4b SkNx_cast(const Sk4f& src) { + auto _32 = _mm_cvttps_epi32(src.fVec); +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + const int _ = ~0; + return _mm_shuffle_epi8(_32, _mm_setr_epi8(0,4,8,12, _,_,_,_, _,_,_,_, _,_,_,_)); +#else + auto _16 = _mm_packus_epi16(_32, _32); + return _mm_packus_epi16(_16, _16); +#endif +} + +template<> inline Sk4f SkNx_cast(const Sk4b& src) { +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + const int _ = ~0; + auto _32 = _mm_shuffle_epi8(src.fVec, _mm_setr_epi8(0,_,_,_, 1,_,_,_, 2,_,_,_, 3,_,_,_)); +#else + auto _16 = _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()), + _32 = _mm_unpacklo_epi16(_16, _mm_setzero_si128()); +#endif + return _mm_cvtepi32_ps(_32); +} + +static inline void Sk4f_ToBytes(uint8_t bytes[16], + const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { + _mm_storeu_si128((__m128i*)bytes, + _mm_packus_epi16(_mm_packus_epi16(_mm_cvttps_epi32(a.fVec), + _mm_cvttps_epi32(b.fVec)), + _mm_packus_epi16(_mm_cvttps_epi32(c.fVec), + _mm_cvttps_epi32(d.fVec)))); +} + + } // namespace #endif//SkNx_sse_DEFINED -- cgit v1.2.3