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