xref: /aosp_15_r20/external/webp/src/dsp/common_sse2.h (revision b2055c353e87c8814eb2b6b1b11112a1562253bd)
1*b2055c35SXin Li // Copyright 2016 Google Inc. All Rights Reserved.
2*b2055c35SXin Li //
3*b2055c35SXin Li // Use of this source code is governed by a BSD-style license
4*b2055c35SXin Li // that can be found in the COPYING file in the root of the source
5*b2055c35SXin Li // tree. An additional intellectual property rights grant can be found
6*b2055c35SXin Li // in the file PATENTS. All contributing project authors may
7*b2055c35SXin Li // be found in the AUTHORS file in the root of the source tree.
8*b2055c35SXin Li // -----------------------------------------------------------------------------
9*b2055c35SXin Li //
10*b2055c35SXin Li // SSE2 code common to several files.
11*b2055c35SXin Li //
12*b2055c35SXin Li // Author: Vincent Rabaud ([email protected])
13*b2055c35SXin Li 
14*b2055c35SXin Li #ifndef WEBP_DSP_COMMON_SSE2_H_
15*b2055c35SXin Li #define WEBP_DSP_COMMON_SSE2_H_
16*b2055c35SXin Li 
17*b2055c35SXin Li #ifdef __cplusplus
18*b2055c35SXin Li extern "C" {
19*b2055c35SXin Li #endif
20*b2055c35SXin Li 
21*b2055c35SXin Li #if defined(WEBP_USE_SSE2)
22*b2055c35SXin Li 
23*b2055c35SXin Li #include <emmintrin.h>
24*b2055c35SXin Li 
25*b2055c35SXin Li //------------------------------------------------------------------------------
26*b2055c35SXin Li // Quite useful macro for debugging. Left here for convenience.
27*b2055c35SXin Li 
28*b2055c35SXin Li #if 0
29*b2055c35SXin Li #include <stdio.h>
30*b2055c35SXin Li static WEBP_INLINE void PrintReg(const __m128i r, const char* const name,
31*b2055c35SXin Li                                  int size) {
32*b2055c35SXin Li   int n;
33*b2055c35SXin Li   union {
34*b2055c35SXin Li     __m128i r;
35*b2055c35SXin Li     uint8_t i8[16];
36*b2055c35SXin Li     uint16_t i16[8];
37*b2055c35SXin Li     uint32_t i32[4];
38*b2055c35SXin Li     uint64_t i64[2];
39*b2055c35SXin Li   } tmp;
40*b2055c35SXin Li   tmp.r = r;
41*b2055c35SXin Li   fprintf(stderr, "%s\t: ", name);
42*b2055c35SXin Li   if (size == 8) {
43*b2055c35SXin Li     for (n = 0; n < 16; ++n) fprintf(stderr, "%.2x ", tmp.i8[n]);
44*b2055c35SXin Li   } else if (size == 16) {
45*b2055c35SXin Li     for (n = 0; n < 8; ++n) fprintf(stderr, "%.4x ", tmp.i16[n]);
46*b2055c35SXin Li   } else if (size == 32) {
47*b2055c35SXin Li     for (n = 0; n < 4; ++n) fprintf(stderr, "%.8x ", tmp.i32[n]);
48*b2055c35SXin Li   } else {
49*b2055c35SXin Li     for (n = 0; n < 2; ++n) fprintf(stderr, "%.16lx ", tmp.i64[n]);
50*b2055c35SXin Li   }
51*b2055c35SXin Li   fprintf(stderr, "\n");
52*b2055c35SXin Li }
53*b2055c35SXin Li #endif
54*b2055c35SXin Li 
55*b2055c35SXin Li //------------------------------------------------------------------------------
56*b2055c35SXin Li // Math functions.
57*b2055c35SXin Li 
58*b2055c35SXin Li // Return the sum of all the 8b in the register.
VP8HorizontalAdd8b(const __m128i * const a)59*b2055c35SXin Li static WEBP_INLINE int VP8HorizontalAdd8b(const __m128i* const a) {
60*b2055c35SXin Li   const __m128i zero = _mm_setzero_si128();
61*b2055c35SXin Li   const __m128i sad8x2 = _mm_sad_epu8(*a, zero);
62*b2055c35SXin Li   // sum the two sads: sad8x2[0:1] + sad8x2[8:9]
63*b2055c35SXin Li   const __m128i sum = _mm_add_epi32(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
64*b2055c35SXin Li   return _mm_cvtsi128_si32(sum);
65*b2055c35SXin Li }
66*b2055c35SXin Li 
67*b2055c35SXin Li // Transpose two 4x4 16b matrices horizontally stored in registers.
VP8Transpose_2_4x4_16b(const __m128i * const in0,const __m128i * const in1,const __m128i * const in2,const __m128i * const in3,__m128i * const out0,__m128i * const out1,__m128i * const out2,__m128i * const out3)68*b2055c35SXin Li static WEBP_INLINE void VP8Transpose_2_4x4_16b(
69*b2055c35SXin Li     const __m128i* const in0, const __m128i* const in1,
70*b2055c35SXin Li     const __m128i* const in2, const __m128i* const in3, __m128i* const out0,
71*b2055c35SXin Li     __m128i* const out1, __m128i* const out2, __m128i* const out3) {
72*b2055c35SXin Li   // Transpose the two 4x4.
73*b2055c35SXin Li   // a00 a01 a02 a03   b00 b01 b02 b03
74*b2055c35SXin Li   // a10 a11 a12 a13   b10 b11 b12 b13
75*b2055c35SXin Li   // a20 a21 a22 a23   b20 b21 b22 b23
76*b2055c35SXin Li   // a30 a31 a32 a33   b30 b31 b32 b33
77*b2055c35SXin Li   const __m128i transpose0_0 = _mm_unpacklo_epi16(*in0, *in1);
78*b2055c35SXin Li   const __m128i transpose0_1 = _mm_unpacklo_epi16(*in2, *in3);
79*b2055c35SXin Li   const __m128i transpose0_2 = _mm_unpackhi_epi16(*in0, *in1);
80*b2055c35SXin Li   const __m128i transpose0_3 = _mm_unpackhi_epi16(*in2, *in3);
81*b2055c35SXin Li   // a00 a10 a01 a11   a02 a12 a03 a13
82*b2055c35SXin Li   // a20 a30 a21 a31   a22 a32 a23 a33
83*b2055c35SXin Li   // b00 b10 b01 b11   b02 b12 b03 b13
84*b2055c35SXin Li   // b20 b30 b21 b31   b22 b32 b23 b33
85*b2055c35SXin Li   const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
86*b2055c35SXin Li   const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
87*b2055c35SXin Li   const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
88*b2055c35SXin Li   const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
89*b2055c35SXin Li   // a00 a10 a20 a30 a01 a11 a21 a31
90*b2055c35SXin Li   // b00 b10 b20 b30 b01 b11 b21 b31
91*b2055c35SXin Li   // a02 a12 a22 a32 a03 a13 a23 a33
92*b2055c35SXin Li   // b02 b12 a22 b32 b03 b13 b23 b33
93*b2055c35SXin Li   *out0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
94*b2055c35SXin Li   *out1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
95*b2055c35SXin Li   *out2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
96*b2055c35SXin Li   *out3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
97*b2055c35SXin Li   // a00 a10 a20 a30   b00 b10 b20 b30
98*b2055c35SXin Li   // a01 a11 a21 a31   b01 b11 b21 b31
99*b2055c35SXin Li   // a02 a12 a22 a32   b02 b12 b22 b32
100*b2055c35SXin Li   // a03 a13 a23 a33   b03 b13 b23 b33
101*b2055c35SXin Li }
102*b2055c35SXin Li 
103*b2055c35SXin Li //------------------------------------------------------------------------------
104*b2055c35SXin Li // Channel mixing.
105*b2055c35SXin Li 
106*b2055c35SXin Li // Function used several times in VP8PlanarTo24b.
107*b2055c35SXin Li // It samples the in buffer as follows: one every two unsigned char is stored
108*b2055c35SXin Li // at the beginning of the buffer, while the other half is stored at the end.
109*b2055c35SXin Li #define VP8PlanarTo24bHelper(IN, OUT)                            \
110*b2055c35SXin Li   do {                                                           \
111*b2055c35SXin Li     const __m128i v_mask = _mm_set1_epi16(0x00ff);               \
112*b2055c35SXin Li     /* Take one every two upper 8b values.*/                     \
113*b2055c35SXin Li     (OUT##0) = _mm_packus_epi16(_mm_and_si128((IN##0), v_mask),  \
114*b2055c35SXin Li                                 _mm_and_si128((IN##1), v_mask)); \
115*b2055c35SXin Li     (OUT##1) = _mm_packus_epi16(_mm_and_si128((IN##2), v_mask),  \
116*b2055c35SXin Li                                 _mm_and_si128((IN##3), v_mask)); \
117*b2055c35SXin Li     (OUT##2) = _mm_packus_epi16(_mm_and_si128((IN##4), v_mask),  \
118*b2055c35SXin Li                                 _mm_and_si128((IN##5), v_mask)); \
119*b2055c35SXin Li     /* Take one every two lower 8b values.*/                     \
120*b2055c35SXin Li     (OUT##3) = _mm_packus_epi16(_mm_srli_epi16((IN##0), 8),      \
121*b2055c35SXin Li                                 _mm_srli_epi16((IN##1), 8));     \
122*b2055c35SXin Li     (OUT##4) = _mm_packus_epi16(_mm_srli_epi16((IN##2), 8),      \
123*b2055c35SXin Li                                 _mm_srli_epi16((IN##3), 8));     \
124*b2055c35SXin Li     (OUT##5) = _mm_packus_epi16(_mm_srli_epi16((IN##4), 8),      \
125*b2055c35SXin Li                                 _mm_srli_epi16((IN##5), 8));     \
126*b2055c35SXin Li   } while (0)
127*b2055c35SXin Li 
128*b2055c35SXin Li // Pack the planar buffers
129*b2055c35SXin Li // rrrr... rrrr... gggg... gggg... bbbb... bbbb....
130*b2055c35SXin Li // triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
VP8PlanarTo24b_SSE2(__m128i * const in0,__m128i * const in1,__m128i * const in2,__m128i * const in3,__m128i * const in4,__m128i * const in5)131*b2055c35SXin Li static WEBP_INLINE void VP8PlanarTo24b_SSE2(
132*b2055c35SXin Li     __m128i* const in0, __m128i* const in1, __m128i* const in2,
133*b2055c35SXin Li     __m128i* const in3, __m128i* const in4, __m128i* const in5) {
134*b2055c35SXin Li   // The input is 6 registers of sixteen 8b but for the sake of explanation,
135*b2055c35SXin Li   // let's take 6 registers of four 8b values.
136*b2055c35SXin Li   // To pack, we will keep taking one every two 8b integer and move it
137*b2055c35SXin Li   // around as follows:
138*b2055c35SXin Li   // Input:
139*b2055c35SXin Li   //   r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7
140*b2055c35SXin Li   // Split the 6 registers in two sets of 3 registers: the first set as the even
141*b2055c35SXin Li   // 8b bytes, the second the odd ones:
142*b2055c35SXin Li   //   r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7
143*b2055c35SXin Li   // Repeat the same permutations twice more:
144*b2055c35SXin Li   //   r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
145*b2055c35SXin Li   //   r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
146*b2055c35SXin Li   __m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
147*b2055c35SXin Li   VP8PlanarTo24bHelper(*in, tmp);
148*b2055c35SXin Li   VP8PlanarTo24bHelper(tmp, *in);
149*b2055c35SXin Li   VP8PlanarTo24bHelper(*in, tmp);
150*b2055c35SXin Li   // We need to do it two more times than the example as we have sixteen bytes.
151*b2055c35SXin Li   {
152*b2055c35SXin Li     __m128i out0, out1, out2, out3, out4, out5;
153*b2055c35SXin Li     VP8PlanarTo24bHelper(tmp, out);
154*b2055c35SXin Li     VP8PlanarTo24bHelper(out, *in);
155*b2055c35SXin Li   }
156*b2055c35SXin Li }
157*b2055c35SXin Li 
158*b2055c35SXin Li #undef VP8PlanarTo24bHelper
159*b2055c35SXin Li 
160*b2055c35SXin Li // Convert four packed four-channel buffers like argbargbargbargb... into the
161*b2055c35SXin Li // split channels aaaaa ... rrrr ... gggg .... bbbbb ......
VP8L32bToPlanar_SSE2(__m128i * const in0,__m128i * const in1,__m128i * const in2,__m128i * const in3)162*b2055c35SXin Li static WEBP_INLINE void VP8L32bToPlanar_SSE2(__m128i* const in0,
163*b2055c35SXin Li                                              __m128i* const in1,
164*b2055c35SXin Li                                              __m128i* const in2,
165*b2055c35SXin Li                                              __m128i* const in3) {
166*b2055c35SXin Li   // Column-wise transpose.
167*b2055c35SXin Li   const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1);
168*b2055c35SXin Li   const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1);
169*b2055c35SXin Li   const __m128i A2 = _mm_unpacklo_epi8(*in2, *in3);
170*b2055c35SXin Li   const __m128i A3 = _mm_unpackhi_epi8(*in2, *in3);
171*b2055c35SXin Li   const __m128i B0 = _mm_unpacklo_epi8(A0, A1);
172*b2055c35SXin Li   const __m128i B1 = _mm_unpackhi_epi8(A0, A1);
173*b2055c35SXin Li   const __m128i B2 = _mm_unpacklo_epi8(A2, A3);
174*b2055c35SXin Li   const __m128i B3 = _mm_unpackhi_epi8(A2, A3);
175*b2055c35SXin Li   // C0 = g7 g6 ... g1 g0 | b7 b6 ... b1 b0
176*b2055c35SXin Li   // C1 = a7 a6 ... a1 a0 | r7 r6 ... r1 r0
177*b2055c35SXin Li   const __m128i C0 = _mm_unpacklo_epi8(B0, B1);
178*b2055c35SXin Li   const __m128i C1 = _mm_unpackhi_epi8(B0, B1);
179*b2055c35SXin Li   const __m128i C2 = _mm_unpacklo_epi8(B2, B3);
180*b2055c35SXin Li   const __m128i C3 = _mm_unpackhi_epi8(B2, B3);
181*b2055c35SXin Li   // Gather the channels.
182*b2055c35SXin Li   *in0 = _mm_unpackhi_epi64(C1, C3);
183*b2055c35SXin Li   *in1 = _mm_unpacklo_epi64(C1, C3);
184*b2055c35SXin Li   *in2 = _mm_unpackhi_epi64(C0, C2);
185*b2055c35SXin Li   *in3 = _mm_unpacklo_epi64(C0, C2);
186*b2055c35SXin Li }
187*b2055c35SXin Li 
188*b2055c35SXin Li #endif  // WEBP_USE_SSE2
189*b2055c35SXin Li 
190*b2055c35SXin Li #ifdef __cplusplus
191*b2055c35SXin Li }  // extern "C"
192*b2055c35SXin Li #endif
193*b2055c35SXin Li 
194*b2055c35SXin Li #endif  // WEBP_DSP_COMMON_SSE2_H_
195