1// Copyright 2011 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 version of speed-critical encoding functions.
11//
12// Author: Christian Duvivier (cduvivier@google.com)
13
14#include "src/dsp/dsp.h"
15
16#if defined(WEBP_USE_SSE2)
17#include <assert.h>
18#include <stdlib.h> // for abs()
19#include <emmintrin.h>
20
21#include "src/dsp/common_sse2.h"
22#include "src/enc/cost_enc.h"
23#include "src/enc/vp8i_enc.h"
24
25//------------------------------------------------------------------------------
26// Transforms (Paragraph 14.4)
27
28// Does one inverse transform.
29static void ITransform_One_SSE2(const uint8_t* ref, const int16_t* in,
30 uint8_t* dst) {
31 // This implementation makes use of 16-bit fixed point versions of two
32 // multiply constants:
33 // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
34 // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16
35 //
36 // To be able to use signed 16-bit integers, we use the following trick to
37 // have constants within range:
38 // - Associated constants are obtained by subtracting the 16-bit fixed point
39 // version of one:
40 // k = K - (1 << 16) => K = k + (1 << 16)
41 // K1 = 85267 => k1 = 20091
42 // K2 = 35468 => k2 = -30068
43 // - The multiplication of a variable by a constant become the sum of the
44 // variable and the multiplication of that variable by the associated
45 // constant:
46 // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x
47 const __m128i k1k2 = _mm_set_epi16(w7: -30068, w6: -30068, w5: -30068, w4: -30068,
48 w3: 20091, w2: 20091, w1: 20091, w0: 20091);
49 const __m128i k2k1 = _mm_set_epi16(w7: 20091, w6: 20091, w5: 20091, w4: 20091,
50 w3: -30068, w2: -30068, w1: -30068, w0: -30068);
51 const __m128i zero = _mm_setzero_si128();
52 const __m128i zero_four = _mm_set_epi16(w7: 0, w6: 0, w5: 0, w4: 0, w3: 4, w2: 4, w1: 4, w0: 4);
53 __m128i T01, T23;
54
55 // Load and concatenate the transform coefficients.
56 const __m128i in01 = _mm_loadu_si128(p: (const __m128i*)&in[0]);
57 const __m128i in23 = _mm_loadu_si128(p: (const __m128i*)&in[8]);
58 // a00 a10 a20 a30 a01 a11 a21 a31
59 // a02 a12 a22 a32 a03 a13 a23 a33
60
61 // Vertical pass and subsequent transpose.
62 {
63 const __m128i in1 = _mm_unpackhi_epi64(a: in01, b: in01);
64 const __m128i in3 = _mm_unpackhi_epi64(a: in23, b: in23);
65
66 // First pass, c and d calculations are longer because of the "trick"
67 // multiplications.
68 // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3
69 // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3
70 const __m128i a_d3 = _mm_add_epi16(a: in01, b: in23);
71 const __m128i b_c3 = _mm_sub_epi16(a: in01, b: in23);
72 const __m128i c1d1 = _mm_mulhi_epi16(a: in1, b: k2k1);
73 const __m128i c2d2 = _mm_mulhi_epi16(a: in3, b: k1k2);
74 const __m128i c3 = _mm_unpackhi_epi64(a: b_c3, b: b_c3);
75 const __m128i c4 = _mm_sub_epi16(a: c1d1, b: c2d2);
76 const __m128i c = _mm_add_epi16(a: c3, b: c4);
77 const __m128i d4u = _mm_add_epi16(a: c1d1, b: c2d2);
78 const __m128i du = _mm_add_epi16(a: a_d3, b: d4u);
79 const __m128i d = _mm_unpackhi_epi64(a: du, b: du);
80
81 // Second pass.
82 const __m128i comb_ab = _mm_unpacklo_epi64(a: a_d3, b: b_c3);
83 const __m128i comb_dc = _mm_unpacklo_epi64(a: d, b: c);
84
85 const __m128i tmp01 = _mm_add_epi16(a: comb_ab, b: comb_dc);
86 const __m128i tmp32 = _mm_sub_epi16(a: comb_ab, b: comb_dc);
87 const __m128i tmp23 = _mm_shuffle_epi32(tmp32, _MM_SHUFFLE(1, 0, 3, 2));
88
89 const __m128i transpose_0 = _mm_unpacklo_epi16(a: tmp01, b: tmp23);
90 const __m128i transpose_1 = _mm_unpackhi_epi16(a: tmp01, b: tmp23);
91 // a00 a20 a01 a21 a02 a22 a03 a23
92 // a10 a30 a11 a31 a12 a32 a13 a33
93
94 T01 = _mm_unpacklo_epi16(a: transpose_0, b: transpose_1);
95 T23 = _mm_unpackhi_epi16(a: transpose_0, b: transpose_1);
96 // a00 a10 a20 a30 a01 a11 a21 a31
97 // a02 a12 a22 a32 a03 a13 a23 a33
98 }
99
100 // Horizontal pass and subsequent transpose.
101 {
102 const __m128i T1 = _mm_unpackhi_epi64(a: T01, b: T01);
103 const __m128i T3 = _mm_unpackhi_epi64(a: T23, b: T23);
104
105 // First pass, c and d calculations are longer because of the "trick"
106 // multiplications.
107 const __m128i dc = _mm_add_epi16(a: T01, b: zero_four);
108
109 // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3
110 // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3
111 const __m128i a_d3 = _mm_add_epi16(a: dc, b: T23);
112 const __m128i b_c3 = _mm_sub_epi16(a: dc, b: T23);
113 const __m128i c1d1 = _mm_mulhi_epi16(a: T1, b: k2k1);
114 const __m128i c2d2 = _mm_mulhi_epi16(a: T3, b: k1k2);
115 const __m128i c3 = _mm_unpackhi_epi64(a: b_c3, b: b_c3);
116 const __m128i c4 = _mm_sub_epi16(a: c1d1, b: c2d2);
117 const __m128i c = _mm_add_epi16(a: c3, b: c4);
118 const __m128i d4u = _mm_add_epi16(a: c1d1, b: c2d2);
119 const __m128i du = _mm_add_epi16(a: a_d3, b: d4u);
120 const __m128i d = _mm_unpackhi_epi64(a: du, b: du);
121
122 // Second pass.
123 const __m128i comb_ab = _mm_unpacklo_epi64(a: a_d3, b: b_c3);
124 const __m128i comb_dc = _mm_unpacklo_epi64(a: d, b: c);
125
126 const __m128i tmp01 = _mm_add_epi16(a: comb_ab, b: comb_dc);
127 const __m128i tmp32 = _mm_sub_epi16(a: comb_ab, b: comb_dc);
128 const __m128i tmp23 = _mm_shuffle_epi32(tmp32, _MM_SHUFFLE(1, 0, 3, 2));
129
130 const __m128i shifted01 = _mm_srai_epi16(a: tmp01, count: 3);
131 const __m128i shifted23 = _mm_srai_epi16(a: tmp23, count: 3);
132 // a00 a01 a02 a03 a10 a11 a12 a13
133 // a20 a21 a22 a23 a30 a31 a32 a33
134
135 const __m128i transpose_0 = _mm_unpacklo_epi16(a: shifted01, b: shifted23);
136 const __m128i transpose_1 = _mm_unpackhi_epi16(a: shifted01, b: shifted23);
137 // a00 a20 a01 a21 a02 a22 a03 a23
138 // a10 a30 a11 a31 a12 a32 a13 a33
139
140 T01 = _mm_unpacklo_epi16(a: transpose_0, b: transpose_1);
141 T23 = _mm_unpackhi_epi16(a: transpose_0, b: transpose_1);
142 // a00 a10 a20 a30 a01 a11 a21 a31
143 // a02 a12 a22 a32 a03 a13 a23 a33
144 }
145
146 // Add inverse transform to 'ref' and store.
147 {
148 // Load the reference(s).
149 __m128i ref01, ref23, ref0123;
150 int32_t buf[4];
151
152 // Load four bytes/pixels per line.
153 const __m128i ref0 = _mm_cvtsi32_si128(a: WebPMemToInt32(ptr: &ref[0 * BPS]));
154 const __m128i ref1 = _mm_cvtsi32_si128(a: WebPMemToInt32(ptr: &ref[1 * BPS]));
155 const __m128i ref2 = _mm_cvtsi32_si128(a: WebPMemToInt32(ptr: &ref[2 * BPS]));
156 const __m128i ref3 = _mm_cvtsi32_si128(a: WebPMemToInt32(ptr: &ref[3 * BPS]));
157 ref01 = _mm_unpacklo_epi32(a: ref0, b: ref1);
158 ref23 = _mm_unpacklo_epi32(a: ref2, b: ref3);
159
160 // Convert to 16b.
161 ref01 = _mm_unpacklo_epi8(a: ref01, b: zero);
162 ref23 = _mm_unpacklo_epi8(a: ref23, b: zero);
163 // Add the inverse transform(s).
164 ref01 = _mm_add_epi16(a: ref01, b: T01);
165 ref23 = _mm_add_epi16(a: ref23, b: T23);
166 // Unsigned saturate to 8b.
167 ref0123 = _mm_packus_epi16(a: ref01, b: ref23);
168
169 _mm_storeu_si128(p: (__m128i *)buf, b: ref0123);
170
171 // Store four bytes/pixels per line.
172 WebPInt32ToMem(ptr: &dst[0 * BPS], val: buf[0]);
173 WebPInt32ToMem(ptr: &dst[1 * BPS], val: buf[1]);
174 WebPInt32ToMem(ptr: &dst[2 * BPS], val: buf[2]);
175 WebPInt32ToMem(ptr: &dst[3 * BPS], val: buf[3]);
176 }
177}
178
179// Does two inverse transforms.
180static void ITransform_Two_SSE2(const uint8_t* ref, const int16_t* in,
181 uint8_t* dst) {
182 // This implementation makes use of 16-bit fixed point versions of two
183 // multiply constants:
184 // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
185 // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16
186 //
187 // To be able to use signed 16-bit integers, we use the following trick to
188 // have constants within range:
189 // - Associated constants are obtained by subtracting the 16-bit fixed point
190 // version of one:
191 // k = K - (1 << 16) => K = k + (1 << 16)
192 // K1 = 85267 => k1 = 20091
193 // K2 = 35468 => k2 = -30068
194 // - The multiplication of a variable by a constant become the sum of the
195 // variable and the multiplication of that variable by the associated
196 // constant:
197 // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x
198 const __m128i k1 = _mm_set1_epi16(w: 20091);
199 const __m128i k2 = _mm_set1_epi16(w: -30068);
200 __m128i T0, T1, T2, T3;
201
202 // Load and concatenate the transform coefficients (we'll do two inverse
203 // transforms in parallel).
204 __m128i in0, in1, in2, in3;
205 {
206 const __m128i tmp0 = _mm_loadu_si128(p: (const __m128i*)&in[0]);
207 const __m128i tmp1 = _mm_loadu_si128(p: (const __m128i*)&in[8]);
208 const __m128i tmp2 = _mm_loadu_si128(p: (const __m128i*)&in[16]);
209 const __m128i tmp3 = _mm_loadu_si128(p: (const __m128i*)&in[24]);
210 in0 = _mm_unpacklo_epi64(a: tmp0, b: tmp2);
211 in1 = _mm_unpackhi_epi64(a: tmp0, b: tmp2);
212 in2 = _mm_unpacklo_epi64(a: tmp1, b: tmp3);
213 in3 = _mm_unpackhi_epi64(a: tmp1, b: tmp3);
214 // a00 a10 a20 a30 b00 b10 b20 b30
215 // a01 a11 a21 a31 b01 b11 b21 b31
216 // a02 a12 a22 a32 b02 b12 b22 b32
217 // a03 a13 a23 a33 b03 b13 b23 b33
218 }
219
220 // Vertical pass and subsequent transpose.
221 {
222 // First pass, c and d calculations are longer because of the "trick"
223 // multiplications.
224 const __m128i a = _mm_add_epi16(a: in0, b: in2);
225 const __m128i b = _mm_sub_epi16(a: in0, b: in2);
226 // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3
227 const __m128i c1 = _mm_mulhi_epi16(a: in1, b: k2);
228 const __m128i c2 = _mm_mulhi_epi16(a: in3, b: k1);
229 const __m128i c3 = _mm_sub_epi16(a: in1, b: in3);
230 const __m128i c4 = _mm_sub_epi16(a: c1, b: c2);
231 const __m128i c = _mm_add_epi16(a: c3, b: c4);
232 // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3
233 const __m128i d1 = _mm_mulhi_epi16(a: in1, b: k1);
234 const __m128i d2 = _mm_mulhi_epi16(a: in3, b: k2);
235 const __m128i d3 = _mm_add_epi16(a: in1, b: in3);
236 const __m128i d4 = _mm_add_epi16(a: d1, b: d2);
237 const __m128i d = _mm_add_epi16(a: d3, b: d4);
238
239 // Second pass.
240 const __m128i tmp0 = _mm_add_epi16(a: a, b: d);
241 const __m128i tmp1 = _mm_add_epi16(a: b, b: c);
242 const __m128i tmp2 = _mm_sub_epi16(a: b, b: c);
243 const __m128i tmp3 = _mm_sub_epi16(a: a, b: d);
244
245 // Transpose the two 4x4.
246 VP8Transpose_2_4x4_16b(in0: &tmp0, in1: &tmp1, in2: &tmp2, in3: &tmp3, out0: &T0, out1: &T1, out2: &T2, out3: &T3);
247 }
248
249 // Horizontal pass and subsequent transpose.
250 {
251 // First pass, c and d calculations are longer because of the "trick"
252 // multiplications.
253 const __m128i four = _mm_set1_epi16(w: 4);
254 const __m128i dc = _mm_add_epi16(a: T0, b: four);
255 const __m128i a = _mm_add_epi16(a: dc, b: T2);
256 const __m128i b = _mm_sub_epi16(a: dc, b: T2);
257 // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3
258 const __m128i c1 = _mm_mulhi_epi16(a: T1, b: k2);
259 const __m128i c2 = _mm_mulhi_epi16(a: T3, b: k1);
260 const __m128i c3 = _mm_sub_epi16(a: T1, b: T3);
261 const __m128i c4 = _mm_sub_epi16(a: c1, b: c2);
262 const __m128i c = _mm_add_epi16(a: c3, b: c4);
263 // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3
264 const __m128i d1 = _mm_mulhi_epi16(a: T1, b: k1);
265 const __m128i d2 = _mm_mulhi_epi16(a: T3, b: k2);
266 const __m128i d3 = _mm_add_epi16(a: T1, b: T3);
267 const __m128i d4 = _mm_add_epi16(a: d1, b: d2);
268 const __m128i d = _mm_add_epi16(a: d3, b: d4);
269
270 // Second pass.
271 const __m128i tmp0 = _mm_add_epi16(a: a, b: d);
272 const __m128i tmp1 = _mm_add_epi16(a: b, b: c);
273 const __m128i tmp2 = _mm_sub_epi16(a: b, b: c);
274 const __m128i tmp3 = _mm_sub_epi16(a: a, b: d);
275 const __m128i shifted0 = _mm_srai_epi16(a: tmp0, count: 3);
276 const __m128i shifted1 = _mm_srai_epi16(a: tmp1, count: 3);
277 const __m128i shifted2 = _mm_srai_epi16(a: tmp2, count: 3);
278 const __m128i shifted3 = _mm_srai_epi16(a: tmp3, count: 3);
279
280 // Transpose the two 4x4.
281 VP8Transpose_2_4x4_16b(in0: &shifted0, in1: &shifted1, in2: &shifted2, in3: &shifted3, out0: &T0, out1: &T1,
282 out2: &T2, out3: &T3);
283 }
284
285 // Add inverse transform to 'ref' and store.
286 {
287 const __m128i zero = _mm_setzero_si128();
288 // Load the reference(s).
289 __m128i ref0, ref1, ref2, ref3;
290 // Load eight bytes/pixels per line.
291 ref0 = _mm_loadl_epi64(p: (const __m128i*)&ref[0 * BPS]);
292 ref1 = _mm_loadl_epi64(p: (const __m128i*)&ref[1 * BPS]);
293 ref2 = _mm_loadl_epi64(p: (const __m128i*)&ref[2 * BPS]);
294 ref3 = _mm_loadl_epi64(p: (const __m128i*)&ref[3 * BPS]);
295 // Convert to 16b.
296 ref0 = _mm_unpacklo_epi8(a: ref0, b: zero);
297 ref1 = _mm_unpacklo_epi8(a: ref1, b: zero);
298 ref2 = _mm_unpacklo_epi8(a: ref2, b: zero);
299 ref3 = _mm_unpacklo_epi8(a: ref3, b: zero);
300 // Add the inverse transform(s).
301 ref0 = _mm_add_epi16(a: ref0, b: T0);
302 ref1 = _mm_add_epi16(a: ref1, b: T1);
303 ref2 = _mm_add_epi16(a: ref2, b: T2);
304 ref3 = _mm_add_epi16(a: ref3, b: T3);
305 // Unsigned saturate to 8b.
306 ref0 = _mm_packus_epi16(a: ref0, b: ref0);
307 ref1 = _mm_packus_epi16(a: ref1, b: ref1);
308 ref2 = _mm_packus_epi16(a: ref2, b: ref2);
309 ref3 = _mm_packus_epi16(a: ref3, b: ref3);
310 // Store eight bytes/pixels per line.
311 _mm_storel_epi64(p: (__m128i*)&dst[0 * BPS], a: ref0);
312 _mm_storel_epi64(p: (__m128i*)&dst[1 * BPS], a: ref1);
313 _mm_storel_epi64(p: (__m128i*)&dst[2 * BPS], a: ref2);
314 _mm_storel_epi64(p: (__m128i*)&dst[3 * BPS], a: ref3);
315 }
316}
317
318// Does one or two inverse transforms.
319static void ITransform_SSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
320 int do_two) {
321 if (do_two) {
322 ITransform_Two_SSE2(ref, in, dst);
323 } else {
324 ITransform_One_SSE2(ref, in, dst);
325 }
326}
327
328static void FTransformPass1_SSE2(const __m128i* const in01,
329 const __m128i* const in23,
330 __m128i* const out01,
331 __m128i* const out32) {
332 const __m128i k937 = _mm_set1_epi32(i: 937);
333 const __m128i k1812 = _mm_set1_epi32(i: 1812);
334
335 const __m128i k88p = _mm_set_epi16(w7: 8, w6: 8, w5: 8, w4: 8, w3: 8, w2: 8, w1: 8, w0: 8);
336 const __m128i k88m = _mm_set_epi16(w7: -8, w6: 8, w5: -8, w4: 8, w3: -8, w2: 8, w1: -8, w0: 8);
337 const __m128i k5352_2217p = _mm_set_epi16(w7: 2217, w6: 5352, w5: 2217, w4: 5352,
338 w3: 2217, w2: 5352, w1: 2217, w0: 5352);
339 const __m128i k5352_2217m = _mm_set_epi16(w7: -5352, w6: 2217, w5: -5352, w4: 2217,
340 w3: -5352, w2: 2217, w1: -5352, w0: 2217);
341
342 // *in01 = 00 01 10 11 02 03 12 13
343 // *in23 = 20 21 30 31 22 23 32 33
344 const __m128i shuf01_p = _mm_shufflehi_epi16(*in01, _MM_SHUFFLE(2, 3, 0, 1));
345 const __m128i shuf23_p = _mm_shufflehi_epi16(*in23, _MM_SHUFFLE(2, 3, 0, 1));
346 // 00 01 10 11 03 02 13 12
347 // 20 21 30 31 23 22 33 32
348 const __m128i s01 = _mm_unpacklo_epi64(a: shuf01_p, b: shuf23_p);
349 const __m128i s32 = _mm_unpackhi_epi64(a: shuf01_p, b: shuf23_p);
350 // 00 01 10 11 20 21 30 31
351 // 03 02 13 12 23 22 33 32
352 const __m128i a01 = _mm_add_epi16(a: s01, b: s32);
353 const __m128i a32 = _mm_sub_epi16(a: s01, b: s32);
354 // [d0 + d3 | d1 + d2 | ...] = [a0 a1 | a0' a1' | ... ]
355 // [d0 - d3 | d1 - d2 | ...] = [a3 a2 | a3' a2' | ... ]
356
357 const __m128i tmp0 = _mm_madd_epi16(a: a01, b: k88p); // [ (a0 + a1) << 3, ... ]
358 const __m128i tmp2 = _mm_madd_epi16(a: a01, b: k88m); // [ (a0 - a1) << 3, ... ]
359 const __m128i tmp1_1 = _mm_madd_epi16(a: a32, b: k5352_2217p);
360 const __m128i tmp3_1 = _mm_madd_epi16(a: a32, b: k5352_2217m);
361 const __m128i tmp1_2 = _mm_add_epi32(a: tmp1_1, b: k1812);
362 const __m128i tmp3_2 = _mm_add_epi32(a: tmp3_1, b: k937);
363 const __m128i tmp1 = _mm_srai_epi32(a: tmp1_2, count: 9);
364 const __m128i tmp3 = _mm_srai_epi32(a: tmp3_2, count: 9);
365 const __m128i s03 = _mm_packs_epi32(a: tmp0, b: tmp2);
366 const __m128i s12 = _mm_packs_epi32(a: tmp1, b: tmp3);
367 const __m128i s_lo = _mm_unpacklo_epi16(a: s03, b: s12); // 0 1 0 1 0 1...
368 const __m128i s_hi = _mm_unpackhi_epi16(a: s03, b: s12); // 2 3 2 3 2 3
369 const __m128i v23 = _mm_unpackhi_epi32(a: s_lo, b: s_hi);
370 *out01 = _mm_unpacklo_epi32(a: s_lo, b: s_hi);
371 *out32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2)); // 3 2 3 2 3 2..
372}
373
374static void FTransformPass2_SSE2(const __m128i* const v01,
375 const __m128i* const v32,
376 int16_t* out) {
377 const __m128i zero = _mm_setzero_si128();
378 const __m128i seven = _mm_set1_epi16(w: 7);
379 const __m128i k5352_2217 = _mm_set_epi16(w7: 5352, w6: 2217, w5: 5352, w4: 2217,
380 w3: 5352, w2: 2217, w1: 5352, w0: 2217);
381 const __m128i k2217_5352 = _mm_set_epi16(w7: 2217, w6: -5352, w5: 2217, w4: -5352,
382 w3: 2217, w2: -5352, w1: 2217, w0: -5352);
383 const __m128i k12000_plus_one = _mm_set1_epi32(i: 12000 + (1 << 16));
384 const __m128i k51000 = _mm_set1_epi32(i: 51000);
385
386 // Same operations are done on the (0,3) and (1,2) pairs.
387 // a3 = v0 - v3
388 // a2 = v1 - v2
389 const __m128i a32 = _mm_sub_epi16(a: *v01, b: *v32);
390 const __m128i a22 = _mm_unpackhi_epi64(a: a32, b: a32);
391
392 const __m128i b23 = _mm_unpacklo_epi16(a: a22, b: a32);
393 const __m128i c1 = _mm_madd_epi16(a: b23, b: k5352_2217);
394 const __m128i c3 = _mm_madd_epi16(a: b23, b: k2217_5352);
395 const __m128i d1 = _mm_add_epi32(a: c1, b: k12000_plus_one);
396 const __m128i d3 = _mm_add_epi32(a: c3, b: k51000);
397 const __m128i e1 = _mm_srai_epi32(a: d1, count: 16);
398 const __m128i e3 = _mm_srai_epi32(a: d3, count: 16);
399 // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16)
400 // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16)
401 const __m128i f1 = _mm_packs_epi32(a: e1, b: e1);
402 const __m128i f3 = _mm_packs_epi32(a: e3, b: e3);
403 // g1 = f1 + (a3 != 0);
404 // The compare will return (0xffff, 0) for (==0, !=0). To turn that into the
405 // desired (0, 1), we add one earlier through k12000_plus_one.
406 // -> g1 = f1 + 1 - (a3 == 0)
407 const __m128i g1 = _mm_add_epi16(a: f1, b: _mm_cmpeq_epi16(a: a32, b: zero));
408
409 // a0 = v0 + v3
410 // a1 = v1 + v2
411 const __m128i a01 = _mm_add_epi16(a: *v01, b: *v32);
412 const __m128i a01_plus_7 = _mm_add_epi16(a: a01, b: seven);
413 const __m128i a11 = _mm_unpackhi_epi64(a: a01, b: a01);
414 const __m128i c0 = _mm_add_epi16(a: a01_plus_7, b: a11);
415 const __m128i c2 = _mm_sub_epi16(a: a01_plus_7, b: a11);
416 // d0 = (a0 + a1 + 7) >> 4;
417 // d2 = (a0 - a1 + 7) >> 4;
418 const __m128i d0 = _mm_srai_epi16(a: c0, count: 4);
419 const __m128i d2 = _mm_srai_epi16(a: c2, count: 4);
420
421 const __m128i d0_g1 = _mm_unpacklo_epi64(a: d0, b: g1);
422 const __m128i d2_f3 = _mm_unpacklo_epi64(a: d2, b: f3);
423 _mm_storeu_si128(p: (__m128i*)&out[0], b: d0_g1);
424 _mm_storeu_si128(p: (__m128i*)&out[8], b: d2_f3);
425}
426
427static void FTransform_SSE2(const uint8_t* src, const uint8_t* ref,
428 int16_t* out) {
429 const __m128i zero = _mm_setzero_si128();
430 // Load src.
431 const __m128i src0 = _mm_loadl_epi64(p: (const __m128i*)&src[0 * BPS]);
432 const __m128i src1 = _mm_loadl_epi64(p: (const __m128i*)&src[1 * BPS]);
433 const __m128i src2 = _mm_loadl_epi64(p: (const __m128i*)&src[2 * BPS]);
434 const __m128i src3 = _mm_loadl_epi64(p: (const __m128i*)&src[3 * BPS]);
435 // 00 01 02 03 *
436 // 10 11 12 13 *
437 // 20 21 22 23 *
438 // 30 31 32 33 *
439 // Shuffle.
440 const __m128i src_0 = _mm_unpacklo_epi16(a: src0, b: src1);
441 const __m128i src_1 = _mm_unpacklo_epi16(a: src2, b: src3);
442 // 00 01 10 11 02 03 12 13 * * ...
443 // 20 21 30 31 22 22 32 33 * * ...
444
445 // Load ref.
446 const __m128i ref0 = _mm_loadl_epi64(p: (const __m128i*)&ref[0 * BPS]);
447 const __m128i ref1 = _mm_loadl_epi64(p: (const __m128i*)&ref[1 * BPS]);
448 const __m128i ref2 = _mm_loadl_epi64(p: (const __m128i*)&ref[2 * BPS]);
449 const __m128i ref3 = _mm_loadl_epi64(p: (const __m128i*)&ref[3 * BPS]);
450 const __m128i ref_0 = _mm_unpacklo_epi16(a: ref0, b: ref1);
451 const __m128i ref_1 = _mm_unpacklo_epi16(a: ref2, b: ref3);
452
453 // Convert both to 16 bit.
454 const __m128i src_0_16b = _mm_unpacklo_epi8(a: src_0, b: zero);
455 const __m128i src_1_16b = _mm_unpacklo_epi8(a: src_1, b: zero);
456 const __m128i ref_0_16b = _mm_unpacklo_epi8(a: ref_0, b: zero);
457 const __m128i ref_1_16b = _mm_unpacklo_epi8(a: ref_1, b: zero);
458
459 // Compute the difference.
460 const __m128i row01 = _mm_sub_epi16(a: src_0_16b, b: ref_0_16b);
461 const __m128i row23 = _mm_sub_epi16(a: src_1_16b, b: ref_1_16b);
462 __m128i v01, v32;
463
464 // First pass
465 FTransformPass1_SSE2(in01: &row01, in23: &row23, out01: &v01, out32: &v32);
466
467 // Second pass
468 FTransformPass2_SSE2(v01: &v01, v32: &v32, out);
469}
470
471static void FTransform2_SSE2(const uint8_t* src, const uint8_t* ref,
472 int16_t* out) {
473 const __m128i zero = _mm_setzero_si128();
474
475 // Load src and convert to 16b.
476 const __m128i src0 = _mm_loadl_epi64(p: (const __m128i*)&src[0 * BPS]);
477 const __m128i src1 = _mm_loadl_epi64(p: (const __m128i*)&src[1 * BPS]);
478 const __m128i src2 = _mm_loadl_epi64(p: (const __m128i*)&src[2 * BPS]);
479 const __m128i src3 = _mm_loadl_epi64(p: (const __m128i*)&src[3 * BPS]);
480 const __m128i src_0 = _mm_unpacklo_epi8(a: src0, b: zero);
481 const __m128i src_1 = _mm_unpacklo_epi8(a: src1, b: zero);
482 const __m128i src_2 = _mm_unpacklo_epi8(a: src2, b: zero);
483 const __m128i src_3 = _mm_unpacklo_epi8(a: src3, b: zero);
484 // Load ref and convert to 16b.
485 const __m128i ref0 = _mm_loadl_epi64(p: (const __m128i*)&ref[0 * BPS]);
486 const __m128i ref1 = _mm_loadl_epi64(p: (const __m128i*)&ref[1 * BPS]);
487 const __m128i ref2 = _mm_loadl_epi64(p: (const __m128i*)&ref[2 * BPS]);
488 const __m128i ref3 = _mm_loadl_epi64(p: (const __m128i*)&ref[3 * BPS]);
489 const __m128i ref_0 = _mm_unpacklo_epi8(a: ref0, b: zero);
490 const __m128i ref_1 = _mm_unpacklo_epi8(a: ref1, b: zero);
491 const __m128i ref_2 = _mm_unpacklo_epi8(a: ref2, b: zero);
492 const __m128i ref_3 = _mm_unpacklo_epi8(a: ref3, b: zero);
493 // Compute difference. -> 00 01 02 03 00' 01' 02' 03'
494 const __m128i diff0 = _mm_sub_epi16(a: src_0, b: ref_0);
495 const __m128i diff1 = _mm_sub_epi16(a: src_1, b: ref_1);
496 const __m128i diff2 = _mm_sub_epi16(a: src_2, b: ref_2);
497 const __m128i diff3 = _mm_sub_epi16(a: src_3, b: ref_3);
498
499 // Unpack and shuffle
500 // 00 01 02 03 0 0 0 0
501 // 10 11 12 13 0 0 0 0
502 // 20 21 22 23 0 0 0 0
503 // 30 31 32 33 0 0 0 0
504 const __m128i shuf01l = _mm_unpacklo_epi32(a: diff0, b: diff1);
505 const __m128i shuf23l = _mm_unpacklo_epi32(a: diff2, b: diff3);
506 const __m128i shuf01h = _mm_unpackhi_epi32(a: diff0, b: diff1);
507 const __m128i shuf23h = _mm_unpackhi_epi32(a: diff2, b: diff3);
508 __m128i v01l, v32l;
509 __m128i v01h, v32h;
510
511 // First pass
512 FTransformPass1_SSE2(in01: &shuf01l, in23: &shuf23l, out01: &v01l, out32: &v32l);
513 FTransformPass1_SSE2(in01: &shuf01h, in23: &shuf23h, out01: &v01h, out32: &v32h);
514
515 // Second pass
516 FTransformPass2_SSE2(v01: &v01l, v32: &v32l, out: out + 0);
517 FTransformPass2_SSE2(v01: &v01h, v32: &v32h, out: out + 16);
518}
519
520static void FTransformWHTRow_SSE2(const int16_t* const in, __m128i* const out) {
521 const __m128i kMult = _mm_set_epi16(w7: -1, w6: 1, w5: -1, w4: 1, w3: 1, w2: 1, w1: 1, w0: 1);
522 const __m128i src0 = _mm_loadl_epi64(p: (__m128i*)&in[0 * 16]);
523 const __m128i src1 = _mm_loadl_epi64(p: (__m128i*)&in[1 * 16]);
524 const __m128i src2 = _mm_loadl_epi64(p: (__m128i*)&in[2 * 16]);
525 const __m128i src3 = _mm_loadl_epi64(p: (__m128i*)&in[3 * 16]);
526 const __m128i A01 = _mm_unpacklo_epi16(a: src0, b: src1); // A0 A1 | ...
527 const __m128i A23 = _mm_unpacklo_epi16(a: src2, b: src3); // A2 A3 | ...
528 const __m128i B0 = _mm_adds_epi16(a: A01, b: A23); // a0 | a1 | ...
529 const __m128i B1 = _mm_subs_epi16(a: A01, b: A23); // a3 | a2 | ...
530 const __m128i C0 = _mm_unpacklo_epi32(a: B0, b: B1); // a0 | a1 | a3 | a2 | ...
531 const __m128i C1 = _mm_unpacklo_epi32(a: B1, b: B0); // a3 | a2 | a0 | a1 | ...
532 const __m128i D = _mm_unpacklo_epi64(a: C0, b: C1); // a0 a1 a3 a2 a3 a2 a0 a1
533 *out = _mm_madd_epi16(a: D, b: kMult);
534}
535
536static void FTransformWHT_SSE2(const int16_t* in, int16_t* out) {
537 // Input is 12b signed.
538 __m128i row0, row1, row2, row3;
539 // Rows are 14b signed.
540 FTransformWHTRow_SSE2(in: in + 0 * 64, out: &row0);
541 FTransformWHTRow_SSE2(in: in + 1 * 64, out: &row1);
542 FTransformWHTRow_SSE2(in: in + 2 * 64, out: &row2);
543 FTransformWHTRow_SSE2(in: in + 3 * 64, out: &row3);
544
545 {
546 // The a* are 15b signed.
547 const __m128i a0 = _mm_add_epi32(a: row0, b: row2);
548 const __m128i a1 = _mm_add_epi32(a: row1, b: row3);
549 const __m128i a2 = _mm_sub_epi32(a: row1, b: row3);
550 const __m128i a3 = _mm_sub_epi32(a: row0, b: row2);
551 const __m128i a0a3 = _mm_packs_epi32(a: a0, b: a3);
552 const __m128i a1a2 = _mm_packs_epi32(a: a1, b: a2);
553
554 // The b* are 16b signed.
555 const __m128i b0b1 = _mm_add_epi16(a: a0a3, b: a1a2);
556 const __m128i b3b2 = _mm_sub_epi16(a: a0a3, b: a1a2);
557 const __m128i tmp_b2b3 = _mm_unpackhi_epi64(a: b3b2, b: b3b2);
558 const __m128i b2b3 = _mm_unpacklo_epi64(a: tmp_b2b3, b: b3b2);
559
560 _mm_storeu_si128(p: (__m128i*)&out[0], b: _mm_srai_epi16(a: b0b1, count: 1));
561 _mm_storeu_si128(p: (__m128i*)&out[8], b: _mm_srai_epi16(a: b2b3, count: 1));
562 }
563}
564
565//------------------------------------------------------------------------------
566// Compute susceptibility based on DCT-coeff histograms:
567// the higher, the "easier" the macroblock is to compress.
568
569static void CollectHistogram_SSE2(const uint8_t* ref, const uint8_t* pred,
570 int start_block, int end_block,
571 VP8Histogram* const histo) {
572 const __m128i zero = _mm_setzero_si128();
573 const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH);
574 int j;
575 int distribution[MAX_COEFF_THRESH + 1] = { 0 };
576 for (j = start_block; j < end_block; ++j) {
577 int16_t out[16];
578 int k;
579
580 FTransform_SSE2(src: ref + VP8DspScan[j], ref: pred + VP8DspScan[j], out);
581
582 // Convert coefficients to bin (within out[]).
583 {
584 // Load.
585 const __m128i out0 = _mm_loadu_si128(p: (__m128i*)&out[0]);
586 const __m128i out1 = _mm_loadu_si128(p: (__m128i*)&out[8]);
587 const __m128i d0 = _mm_sub_epi16(a: zero, b: out0);
588 const __m128i d1 = _mm_sub_epi16(a: zero, b: out1);
589 const __m128i abs0 = _mm_max_epi16(a: out0, b: d0); // abs(v), 16b
590 const __m128i abs1 = _mm_max_epi16(a: out1, b: d1);
591 // v = abs(out) >> 3
592 const __m128i v0 = _mm_srai_epi16(a: abs0, count: 3);
593 const __m128i v1 = _mm_srai_epi16(a: abs1, count: 3);
594 // bin = min(v, MAX_COEFF_THRESH)
595 const __m128i bin0 = _mm_min_epi16(a: v0, b: max_coeff_thresh);
596 const __m128i bin1 = _mm_min_epi16(a: v1, b: max_coeff_thresh);
597 // Store.
598 _mm_storeu_si128(p: (__m128i*)&out[0], b: bin0);
599 _mm_storeu_si128(p: (__m128i*)&out[8], b: bin1);
600 }
601
602 // Convert coefficients to bin.
603 for (k = 0; k < 16; ++k) {
604 ++distribution[out[k]];
605 }
606 }
607 VP8SetHistogramData(distribution, histo);
608}
609
610//------------------------------------------------------------------------------
611// Intra predictions
612
613// helper for chroma-DC predictions
614static WEBP_INLINE void Put8x8uv_SSE2(uint8_t v, uint8_t* dst) {
615 int j;
616 const __m128i values = _mm_set1_epi8(b: (char)v);
617 for (j = 0; j < 8; ++j) {
618 _mm_storel_epi64(p: (__m128i*)(dst + j * BPS), a: values);
619 }
620}
621
622static WEBP_INLINE void Put16_SSE2(uint8_t v, uint8_t* dst) {
623 int j;
624 const __m128i values = _mm_set1_epi8(b: (char)v);
625 for (j = 0; j < 16; ++j) {
626 _mm_store_si128(p: (__m128i*)(dst + j * BPS), b: values);
627 }
628}
629
630static WEBP_INLINE void Fill_SSE2(uint8_t* dst, int value, int size) {
631 if (size == 4) {
632 int j;
633 for (j = 0; j < 4; ++j) {
634 memset(s: dst + j * BPS, c: value, n: 4);
635 }
636 } else if (size == 8) {
637 Put8x8uv_SSE2(v: value, dst);
638 } else {
639 Put16_SSE2(v: value, dst);
640 }
641}
642
643static WEBP_INLINE void VE8uv_SSE2(uint8_t* dst, const uint8_t* top) {
644 int j;
645 const __m128i top_values = _mm_loadl_epi64(p: (const __m128i*)top);
646 for (j = 0; j < 8; ++j) {
647 _mm_storel_epi64(p: (__m128i*)(dst + j * BPS), a: top_values);
648 }
649}
650
651static WEBP_INLINE void VE16_SSE2(uint8_t* dst, const uint8_t* top) {
652 const __m128i top_values = _mm_load_si128(p: (const __m128i*)top);
653 int j;
654 for (j = 0; j < 16; ++j) {
655 _mm_store_si128(p: (__m128i*)(dst + j * BPS), b: top_values);
656 }
657}
658
659static WEBP_INLINE void VerticalPred_SSE2(uint8_t* dst,
660 const uint8_t* top, int size) {
661 if (top != NULL) {
662 if (size == 8) {
663 VE8uv_SSE2(dst, top);
664 } else {
665 VE16_SSE2(dst, top);
666 }
667 } else {
668 Fill_SSE2(dst, value: 127, size);
669 }
670}
671
672static WEBP_INLINE void HE8uv_SSE2(uint8_t* dst, const uint8_t* left) {
673 int j;
674 for (j = 0; j < 8; ++j) {
675 const __m128i values = _mm_set1_epi8(b: (char)left[j]);
676 _mm_storel_epi64(p: (__m128i*)dst, a: values);
677 dst += BPS;
678 }
679}
680
681static WEBP_INLINE void HE16_SSE2(uint8_t* dst, const uint8_t* left) {
682 int j;
683 for (j = 0; j < 16; ++j) {
684 const __m128i values = _mm_set1_epi8(b: (char)left[j]);
685 _mm_store_si128(p: (__m128i*)dst, b: values);
686 dst += BPS;
687 }
688}
689
690static WEBP_INLINE void HorizontalPred_SSE2(uint8_t* dst,
691 const uint8_t* left, int size) {
692 if (left != NULL) {
693 if (size == 8) {
694 HE8uv_SSE2(dst, left);
695 } else {
696 HE16_SSE2(dst, left);
697 }
698 } else {
699 Fill_SSE2(dst, value: 129, size);
700 }
701}
702
703static WEBP_INLINE void TM_SSE2(uint8_t* dst, const uint8_t* left,
704 const uint8_t* top, int size) {
705 const __m128i zero = _mm_setzero_si128();
706 int y;
707 if (size == 8) {
708 const __m128i top_values = _mm_loadl_epi64(p: (const __m128i*)top);
709 const __m128i top_base = _mm_unpacklo_epi8(a: top_values, b: zero);
710 for (y = 0; y < 8; ++y, dst += BPS) {
711 const int val = left[y] - left[-1];
712 const __m128i base = _mm_set1_epi16(w: val);
713 const __m128i out = _mm_packus_epi16(a: _mm_add_epi16(a: base, b: top_base), b: zero);
714 _mm_storel_epi64(p: (__m128i*)dst, a: out);
715 }
716 } else {
717 const __m128i top_values = _mm_load_si128(p: (const __m128i*)top);
718 const __m128i top_base_0 = _mm_unpacklo_epi8(a: top_values, b: zero);
719 const __m128i top_base_1 = _mm_unpackhi_epi8(a: top_values, b: zero);
720 for (y = 0; y < 16; ++y, dst += BPS) {
721 const int val = left[y] - left[-1];
722 const __m128i base = _mm_set1_epi16(w: val);
723 const __m128i out_0 = _mm_add_epi16(a: base, b: top_base_0);
724 const __m128i out_1 = _mm_add_epi16(a: base, b: top_base_1);
725 const __m128i out = _mm_packus_epi16(a: out_0, b: out_1);
726 _mm_store_si128(p: (__m128i*)dst, b: out);
727 }
728 }
729}
730
731static WEBP_INLINE void TrueMotion_SSE2(uint8_t* dst, const uint8_t* left,
732 const uint8_t* top, int size) {
733 if (left != NULL) {
734 if (top != NULL) {
735 TM_SSE2(dst, left, top, size);
736 } else {
737 HorizontalPred_SSE2(dst, left, size);
738 }
739 } else {
740 // true motion without left samples (hence: with default 129 value)
741 // is equivalent to VE prediction where you just copy the top samples.
742 // Note that if top samples are not available, the default value is
743 // then 129, and not 127 as in the VerticalPred case.
744 if (top != NULL) {
745 VerticalPred_SSE2(dst, top, size);
746 } else {
747 Fill_SSE2(dst, value: 129, size);
748 }
749 }
750}
751
752static WEBP_INLINE void DC8uv_SSE2(uint8_t* dst, const uint8_t* left,
753 const uint8_t* top) {
754 const __m128i top_values = _mm_loadl_epi64(p: (const __m128i*)top);
755 const __m128i left_values = _mm_loadl_epi64(p: (const __m128i*)left);
756 const __m128i combined = _mm_unpacklo_epi64(a: top_values, b: left_values);
757 const int DC = VP8HorizontalAdd8b(a: &combined) + 8;
758 Put8x8uv_SSE2(v: DC >> 4, dst);
759}
760
761static WEBP_INLINE void DC8uvNoLeft_SSE2(uint8_t* dst, const uint8_t* top) {
762 const __m128i zero = _mm_setzero_si128();
763 const __m128i top_values = _mm_loadl_epi64(p: (const __m128i*)top);
764 const __m128i sum = _mm_sad_epu8(a: top_values, b: zero);
765 const int DC = _mm_cvtsi128_si32(a: sum) + 4;
766 Put8x8uv_SSE2(v: DC >> 3, dst);
767}
768
769static WEBP_INLINE void DC8uvNoTop_SSE2(uint8_t* dst, const uint8_t* left) {
770 // 'left' is contiguous so we can reuse the top summation.
771 DC8uvNoLeft_SSE2(dst, top: left);
772}
773
774static WEBP_INLINE void DC8uvNoTopLeft_SSE2(uint8_t* dst) {
775 Put8x8uv_SSE2(v: 0x80, dst);
776}
777
778static WEBP_INLINE void DC8uvMode_SSE2(uint8_t* dst, const uint8_t* left,
779 const uint8_t* top) {
780 if (top != NULL) {
781 if (left != NULL) { // top and left present
782 DC8uv_SSE2(dst, left, top);
783 } else { // top, but no left
784 DC8uvNoLeft_SSE2(dst, top);
785 }
786 } else if (left != NULL) { // left but no top
787 DC8uvNoTop_SSE2(dst, left);
788 } else { // no top, no left, nothing.
789 DC8uvNoTopLeft_SSE2(dst);
790 }
791}
792
793static WEBP_INLINE void DC16_SSE2(uint8_t* dst, const uint8_t* left,
794 const uint8_t* top) {
795 const __m128i top_row = _mm_load_si128(p: (const __m128i*)top);
796 const __m128i left_row = _mm_load_si128(p: (const __m128i*)left);
797 const int DC =
798 VP8HorizontalAdd8b(a: &top_row) + VP8HorizontalAdd8b(a: &left_row) + 16;
799 Put16_SSE2(v: DC >> 5, dst);
800}
801
802static WEBP_INLINE void DC16NoLeft_SSE2(uint8_t* dst, const uint8_t* top) {
803 const __m128i top_row = _mm_load_si128(p: (const __m128i*)top);
804 const int DC = VP8HorizontalAdd8b(a: &top_row) + 8;
805 Put16_SSE2(v: DC >> 4, dst);
806}
807
808static WEBP_INLINE void DC16NoTop_SSE2(uint8_t* dst, const uint8_t* left) {
809 // 'left' is contiguous so we can reuse the top summation.
810 DC16NoLeft_SSE2(dst, top: left);
811}
812
813static WEBP_INLINE void DC16NoTopLeft_SSE2(uint8_t* dst) {
814 Put16_SSE2(v: 0x80, dst);
815}
816
817static WEBP_INLINE void DC16Mode_SSE2(uint8_t* dst, const uint8_t* left,
818 const uint8_t* top) {
819 if (top != NULL) {
820 if (left != NULL) { // top and left present
821 DC16_SSE2(dst, left, top);
822 } else { // top, but no left
823 DC16NoLeft_SSE2(dst, top);
824 }
825 } else if (left != NULL) { // left but no top
826 DC16NoTop_SSE2(dst, left);
827 } else { // no top, no left, nothing.
828 DC16NoTopLeft_SSE2(dst);
829 }
830}
831
832//------------------------------------------------------------------------------
833// 4x4 predictions
834
835#define DST(x, y) dst[(x) + (y) * BPS]
836#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
837#define AVG2(a, b) (((a) + (b) + 1) >> 1)
838
839// We use the following 8b-arithmetic tricks:
840// (a + 2 * b + c + 2) >> 2 = (AC + b + 1) >> 1
841// where: AC = (a + c) >> 1 = [(a + c + 1) >> 1] - [(a^c) & 1]
842// and:
843// (a + 2 * b + c + 2) >> 2 = (AB + BC + 1) >> 1 - (ab|bc)&lsb
844// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1
845// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1
846
847static WEBP_INLINE void VE4_SSE2(uint8_t* dst,
848 const uint8_t* top) { // vertical
849 const __m128i one = _mm_set1_epi8(b: 1);
850 const __m128i ABCDEFGH = _mm_loadl_epi64(p: (__m128i*)(top - 1));
851 const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
852 const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2);
853 const __m128i a = _mm_avg_epu8(a: ABCDEFGH, b: CDEFGH00);
854 const __m128i lsb = _mm_and_si128(a: _mm_xor_si128(a: ABCDEFGH, b: CDEFGH00), b: one);
855 const __m128i b = _mm_subs_epu8(a: a, b: lsb);
856 const __m128i avg = _mm_avg_epu8(a: b, b: BCDEFGH0);
857 const int vals = _mm_cvtsi128_si32(a: avg);
858 int i;
859 for (i = 0; i < 4; ++i) {
860 WebPInt32ToMem(ptr: dst + i * BPS, val: vals);
861 }
862}
863
864static WEBP_INLINE void HE4_SSE2(uint8_t* dst,
865 const uint8_t* top) { // horizontal
866 const int X = top[-1];
867 const int I = top[-2];
868 const int J = top[-3];
869 const int K = top[-4];
870 const int L = top[-5];
871 WebPUint32ToMem(ptr: dst + 0 * BPS, val: 0x01010101U * AVG3(X, I, J));
872 WebPUint32ToMem(ptr: dst + 1 * BPS, val: 0x01010101U * AVG3(I, J, K));
873 WebPUint32ToMem(ptr: dst + 2 * BPS, val: 0x01010101U * AVG3(J, K, L));
874 WebPUint32ToMem(ptr: dst + 3 * BPS, val: 0x01010101U * AVG3(K, L, L));
875}
876
877static WEBP_INLINE void DC4_SSE2(uint8_t* dst, const uint8_t* top) {
878 uint32_t dc = 4;
879 int i;
880 for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i];
881 Fill_SSE2(dst, value: dc >> 3, size: 4);
882}
883
884static WEBP_INLINE void LD4_SSE2(uint8_t* dst,
885 const uint8_t* top) { // Down-Left
886 const __m128i one = _mm_set1_epi8(b: 1);
887 const __m128i ABCDEFGH = _mm_loadl_epi64(p: (const __m128i*)top);
888 const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
889 const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2);
890 const __m128i CDEFGHH0 = _mm_insert_epi16(CDEFGH00, top[7], 3);
891 const __m128i avg1 = _mm_avg_epu8(a: ABCDEFGH, b: CDEFGHH0);
892 const __m128i lsb = _mm_and_si128(a: _mm_xor_si128(a: ABCDEFGH, b: CDEFGHH0), b: one);
893 const __m128i avg2 = _mm_subs_epu8(a: avg1, b: lsb);
894 const __m128i abcdefg = _mm_avg_epu8(a: avg2, b: BCDEFGH0);
895 WebPInt32ToMem(ptr: dst + 0 * BPS, val: _mm_cvtsi128_si32( a: abcdefg ));
896 WebPInt32ToMem(ptr: dst + 1 * BPS, val: _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
897 WebPInt32ToMem(ptr: dst + 2 * BPS, val: _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
898 WebPInt32ToMem(ptr: dst + 3 * BPS, val: _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
899}
900
901static WEBP_INLINE void VR4_SSE2(uint8_t* dst,
902 const uint8_t* top) { // Vertical-Right
903 const __m128i one = _mm_set1_epi8(b: 1);
904 const int I = top[-2];
905 const int J = top[-3];
906 const int K = top[-4];
907 const int X = top[-1];
908 const __m128i XABCD = _mm_loadl_epi64(p: (const __m128i*)(top - 1));
909 const __m128i ABCD0 = _mm_srli_si128(XABCD, 1);
910 const __m128i abcd = _mm_avg_epu8(a: XABCD, b: ABCD0);
911 const __m128i _XABCD = _mm_slli_si128(XABCD, 1);
912 const __m128i IXABCD = _mm_insert_epi16(_XABCD, (short)(I | (X << 8)), 0);
913 const __m128i avg1 = _mm_avg_epu8(a: IXABCD, b: ABCD0);
914 const __m128i lsb = _mm_and_si128(a: _mm_xor_si128(a: IXABCD, b: ABCD0), b: one);
915 const __m128i avg2 = _mm_subs_epu8(a: avg1, b: lsb);
916 const __m128i efgh = _mm_avg_epu8(a: avg2, b: XABCD);
917 WebPInt32ToMem(ptr: dst + 0 * BPS, val: _mm_cvtsi128_si32( a: abcd ));
918 WebPInt32ToMem(ptr: dst + 1 * BPS, val: _mm_cvtsi128_si32( a: efgh ));
919 WebPInt32ToMem(ptr: dst + 2 * BPS, val: _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1)));
920 WebPInt32ToMem(ptr: dst + 3 * BPS, val: _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1)));
921
922 // these two are hard to implement in SSE2, so we keep the C-version:
923 DST(0, 2) = AVG3(J, I, X);
924 DST(0, 3) = AVG3(K, J, I);
925}
926
927static WEBP_INLINE void VL4_SSE2(uint8_t* dst,
928 const uint8_t* top) { // Vertical-Left
929 const __m128i one = _mm_set1_epi8(b: 1);
930 const __m128i ABCDEFGH = _mm_loadl_epi64(p: (const __m128i*)top);
931 const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1);
932 const __m128i CDEFGH__ = _mm_srli_si128(ABCDEFGH, 2);
933 const __m128i avg1 = _mm_avg_epu8(a: ABCDEFGH, b: BCDEFGH_);
934 const __m128i avg2 = _mm_avg_epu8(a: CDEFGH__, b: BCDEFGH_);
935 const __m128i avg3 = _mm_avg_epu8(a: avg1, b: avg2);
936 const __m128i lsb1 = _mm_and_si128(a: _mm_xor_si128(a: avg1, b: avg2), b: one);
937 const __m128i ab = _mm_xor_si128(a: ABCDEFGH, b: BCDEFGH_);
938 const __m128i bc = _mm_xor_si128(a: CDEFGH__, b: BCDEFGH_);
939 const __m128i abbc = _mm_or_si128(a: ab, b: bc);
940 const __m128i lsb2 = _mm_and_si128(a: abbc, b: lsb1);
941 const __m128i avg4 = _mm_subs_epu8(a: avg3, b: lsb2);
942 const uint32_t extra_out =
943 (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(avg4, 4));
944 WebPInt32ToMem(ptr: dst + 0 * BPS, val: _mm_cvtsi128_si32( a: avg1 ));
945 WebPInt32ToMem(ptr: dst + 1 * BPS, val: _mm_cvtsi128_si32( a: avg4 ));
946 WebPInt32ToMem(ptr: dst + 2 * BPS, val: _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1)));
947 WebPInt32ToMem(ptr: dst + 3 * BPS, val: _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1)));
948
949 // these two are hard to get and irregular
950 DST(3, 2) = (extra_out >> 0) & 0xff;
951 DST(3, 3) = (extra_out >> 8) & 0xff;
952}
953
954static WEBP_INLINE void RD4_SSE2(uint8_t* dst,
955 const uint8_t* top) { // Down-right
956 const __m128i one = _mm_set1_epi8(b: 1);
957 const __m128i LKJIXABC = _mm_loadl_epi64(p: (const __m128i*)(top - 5));
958 const __m128i LKJIXABCD = _mm_insert_epi16(LKJIXABC, top[3], 4);
959 const __m128i KJIXABCD_ = _mm_srli_si128(LKJIXABCD, 1);
960 const __m128i JIXABCD__ = _mm_srli_si128(LKJIXABCD, 2);
961 const __m128i avg1 = _mm_avg_epu8(a: JIXABCD__, b: LKJIXABCD);
962 const __m128i lsb = _mm_and_si128(a: _mm_xor_si128(a: JIXABCD__, b: LKJIXABCD), b: one);
963 const __m128i avg2 = _mm_subs_epu8(a: avg1, b: lsb);
964 const __m128i abcdefg = _mm_avg_epu8(a: avg2, b: KJIXABCD_);
965 WebPInt32ToMem(ptr: dst + 3 * BPS, val: _mm_cvtsi128_si32( a: abcdefg ));
966 WebPInt32ToMem(ptr: dst + 2 * BPS, val: _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1)));
967 WebPInt32ToMem(ptr: dst + 1 * BPS, val: _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2)));
968 WebPInt32ToMem(ptr: dst + 0 * BPS, val: _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
969}
970
971static WEBP_INLINE void HU4_SSE2(uint8_t* dst, const uint8_t* top) {
972 const int I = top[-2];
973 const int J = top[-3];
974 const int K = top[-4];
975 const int L = top[-5];
976 DST(0, 0) = AVG2(I, J);
977 DST(2, 0) = DST(0, 1) = AVG2(J, K);
978 DST(2, 1) = DST(0, 2) = AVG2(K, L);
979 DST(1, 0) = AVG3(I, J, K);
980 DST(3, 0) = DST(1, 1) = AVG3(J, K, L);
981 DST(3, 1) = DST(1, 2) = AVG3(K, L, L);
982 DST(3, 2) = DST(2, 2) =
983 DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L;
984}
985
986static WEBP_INLINE void HD4_SSE2(uint8_t* dst, const uint8_t* top) {
987 const int X = top[-1];
988 const int I = top[-2];
989 const int J = top[-3];
990 const int K = top[-4];
991 const int L = top[-5];
992 const int A = top[0];
993 const int B = top[1];
994 const int C = top[2];
995
996 DST(0, 0) = DST(2, 1) = AVG2(I, X);
997 DST(0, 1) = DST(2, 2) = AVG2(J, I);
998 DST(0, 2) = DST(2, 3) = AVG2(K, J);
999 DST(0, 3) = AVG2(L, K);
1000
1001 DST(3, 0) = AVG3(A, B, C);
1002 DST(2, 0) = AVG3(X, A, B);
1003 DST(1, 0) = DST(3, 1) = AVG3(I, X, A);
1004 DST(1, 1) = DST(3, 2) = AVG3(J, I, X);
1005 DST(1, 2) = DST(3, 3) = AVG3(K, J, I);
1006 DST(1, 3) = AVG3(L, K, J);
1007}
1008
1009static WEBP_INLINE void TM4_SSE2(uint8_t* dst, const uint8_t* top) {
1010 const __m128i zero = _mm_setzero_si128();
1011 const __m128i top_values = _mm_cvtsi32_si128(a: WebPMemToInt32(ptr: top));
1012 const __m128i top_base = _mm_unpacklo_epi8(a: top_values, b: zero);
1013 int y;
1014 for (y = 0; y < 4; ++y, dst += BPS) {
1015 const int val = top[-2 - y] - top[-1];
1016 const __m128i base = _mm_set1_epi16(w: val);
1017 const __m128i out = _mm_packus_epi16(a: _mm_add_epi16(a: base, b: top_base), b: zero);
1018 WebPInt32ToMem(ptr: dst, val: _mm_cvtsi128_si32(a: out));
1019 }
1020}
1021
1022#undef DST
1023#undef AVG3
1024#undef AVG2
1025
1026//------------------------------------------------------------------------------
1027// luma 4x4 prediction
1028
1029// Left samples are top[-5 .. -2], top_left is top[-1], top are
1030// located at top[0..3], and top right is top[4..7]
1031static void Intra4Preds_SSE2(uint8_t* dst, const uint8_t* top) {
1032 DC4_SSE2(I4DC4 + dst, top);
1033 TM4_SSE2(I4TM4 + dst, top);
1034 VE4_SSE2(I4VE4 + dst, top);
1035 HE4_SSE2(I4HE4 + dst, top);
1036 RD4_SSE2(I4RD4 + dst, top);
1037 VR4_SSE2(I4VR4 + dst, top);
1038 LD4_SSE2(I4LD4 + dst, top);
1039 VL4_SSE2(I4VL4 + dst, top);
1040 HD4_SSE2(I4HD4 + dst, top);
1041 HU4_SSE2(I4HU4 + dst, top);
1042}
1043
1044//------------------------------------------------------------------------------
1045// Chroma 8x8 prediction (paragraph 12.2)
1046
1047static void IntraChromaPreds_SSE2(uint8_t* dst, const uint8_t* left,
1048 const uint8_t* top) {
1049 // U block
1050 DC8uvMode_SSE2(C8DC8 + dst, left, top);
1051 VerticalPred_SSE2(C8VE8 + dst, top, size: 8);
1052 HorizontalPred_SSE2(C8HE8 + dst, left, size: 8);
1053 TrueMotion_SSE2(C8TM8 + dst, left, top, size: 8);
1054 // V block
1055 dst += 8;
1056 if (top != NULL) top += 8;
1057 if (left != NULL) left += 16;
1058 DC8uvMode_SSE2(C8DC8 + dst, left, top);
1059 VerticalPred_SSE2(C8VE8 + dst, top, size: 8);
1060 HorizontalPred_SSE2(C8HE8 + dst, left, size: 8);
1061 TrueMotion_SSE2(C8TM8 + dst, left, top, size: 8);
1062}
1063
1064//------------------------------------------------------------------------------
1065// luma 16x16 prediction (paragraph 12.3)
1066
1067static void Intra16Preds_SSE2(uint8_t* dst,
1068 const uint8_t* left, const uint8_t* top) {
1069 DC16Mode_SSE2(I16DC16 + dst, left, top);
1070 VerticalPred_SSE2(I16VE16 + dst, top, size: 16);
1071 HorizontalPred_SSE2(I16HE16 + dst, left, size: 16);
1072 TrueMotion_SSE2(I16TM16 + dst, left, top, size: 16);
1073}
1074
1075//------------------------------------------------------------------------------
1076// Metric
1077
1078static WEBP_INLINE void SubtractAndAccumulate_SSE2(const __m128i a,
1079 const __m128i b,
1080 __m128i* const sum) {
1081 // take abs(a-b) in 8b
1082 const __m128i a_b = _mm_subs_epu8(a: a, b: b);
1083 const __m128i b_a = _mm_subs_epu8(a: b, b: a);
1084 const __m128i abs_a_b = _mm_or_si128(a: a_b, b: b_a);
1085 // zero-extend to 16b
1086 const __m128i zero = _mm_setzero_si128();
1087 const __m128i C0 = _mm_unpacklo_epi8(a: abs_a_b, b: zero);
1088 const __m128i C1 = _mm_unpackhi_epi8(a: abs_a_b, b: zero);
1089 // multiply with self
1090 const __m128i sum1 = _mm_madd_epi16(a: C0, b: C0);
1091 const __m128i sum2 = _mm_madd_epi16(a: C1, b: C1);
1092 *sum = _mm_add_epi32(a: sum1, b: sum2);
1093}
1094
1095static WEBP_INLINE int SSE_16xN_SSE2(const uint8_t* a, const uint8_t* b,
1096 int num_pairs) {
1097 __m128i sum = _mm_setzero_si128();
1098 int32_t tmp[4];
1099 int i;
1100
1101 for (i = 0; i < num_pairs; ++i) {
1102 const __m128i a0 = _mm_loadu_si128(p: (const __m128i*)&a[BPS * 0]);
1103 const __m128i b0 = _mm_loadu_si128(p: (const __m128i*)&b[BPS * 0]);
1104 const __m128i a1 = _mm_loadu_si128(p: (const __m128i*)&a[BPS * 1]);
1105 const __m128i b1 = _mm_loadu_si128(p: (const __m128i*)&b[BPS * 1]);
1106 __m128i sum1, sum2;
1107 SubtractAndAccumulate_SSE2(a: a0, b: b0, sum: &sum1);
1108 SubtractAndAccumulate_SSE2(a: a1, b: b1, sum: &sum2);
1109 sum = _mm_add_epi32(a: sum, b: _mm_add_epi32(a: sum1, b: sum2));
1110 a += 2 * BPS;
1111 b += 2 * BPS;
1112 }
1113 _mm_storeu_si128(p: (__m128i*)tmp, b: sum);
1114 return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
1115}
1116
1117static int SSE16x16_SSE2(const uint8_t* a, const uint8_t* b) {
1118 return SSE_16xN_SSE2(a, b, num_pairs: 8);
1119}
1120
1121static int SSE16x8_SSE2(const uint8_t* a, const uint8_t* b) {
1122 return SSE_16xN_SSE2(a, b, num_pairs: 4);
1123}
1124
1125#define LOAD_8x16b(ptr) \
1126 _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(ptr)), zero)
1127
1128static int SSE8x8_SSE2(const uint8_t* a, const uint8_t* b) {
1129 const __m128i zero = _mm_setzero_si128();
1130 int num_pairs = 4;
1131 __m128i sum = zero;
1132 int32_t tmp[4];
1133 while (num_pairs-- > 0) {
1134 const __m128i a0 = LOAD_8x16b(&a[BPS * 0]);
1135 const __m128i a1 = LOAD_8x16b(&a[BPS * 1]);
1136 const __m128i b0 = LOAD_8x16b(&b[BPS * 0]);
1137 const __m128i b1 = LOAD_8x16b(&b[BPS * 1]);
1138 // subtract
1139 const __m128i c0 = _mm_subs_epi16(a: a0, b: b0);
1140 const __m128i c1 = _mm_subs_epi16(a: a1, b: b1);
1141 // multiply/accumulate with self
1142 const __m128i d0 = _mm_madd_epi16(a: c0, b: c0);
1143 const __m128i d1 = _mm_madd_epi16(a: c1, b: c1);
1144 // collect
1145 const __m128i sum01 = _mm_add_epi32(a: d0, b: d1);
1146 sum = _mm_add_epi32(a: sum, b: sum01);
1147 a += 2 * BPS;
1148 b += 2 * BPS;
1149 }
1150 _mm_storeu_si128(p: (__m128i*)tmp, b: sum);
1151 return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
1152}
1153#undef LOAD_8x16b
1154
1155static int SSE4x4_SSE2(const uint8_t* a, const uint8_t* b) {
1156 const __m128i zero = _mm_setzero_si128();
1157
1158 // Load values. Note that we read 8 pixels instead of 4,
1159 // but the a/b buffers are over-allocated to that effect.
1160 const __m128i a0 = _mm_loadl_epi64(p: (const __m128i*)&a[BPS * 0]);
1161 const __m128i a1 = _mm_loadl_epi64(p: (const __m128i*)&a[BPS * 1]);
1162 const __m128i a2 = _mm_loadl_epi64(p: (const __m128i*)&a[BPS * 2]);
1163 const __m128i a3 = _mm_loadl_epi64(p: (const __m128i*)&a[BPS * 3]);
1164 const __m128i b0 = _mm_loadl_epi64(p: (const __m128i*)&b[BPS * 0]);
1165 const __m128i b1 = _mm_loadl_epi64(p: (const __m128i*)&b[BPS * 1]);
1166 const __m128i b2 = _mm_loadl_epi64(p: (const __m128i*)&b[BPS * 2]);
1167 const __m128i b3 = _mm_loadl_epi64(p: (const __m128i*)&b[BPS * 3]);
1168 // Combine pair of lines.
1169 const __m128i a01 = _mm_unpacklo_epi32(a: a0, b: a1);
1170 const __m128i a23 = _mm_unpacklo_epi32(a: a2, b: a3);
1171 const __m128i b01 = _mm_unpacklo_epi32(a: b0, b: b1);
1172 const __m128i b23 = _mm_unpacklo_epi32(a: b2, b: b3);
1173 // Convert to 16b.
1174 const __m128i a01s = _mm_unpacklo_epi8(a: a01, b: zero);
1175 const __m128i a23s = _mm_unpacklo_epi8(a: a23, b: zero);
1176 const __m128i b01s = _mm_unpacklo_epi8(a: b01, b: zero);
1177 const __m128i b23s = _mm_unpacklo_epi8(a: b23, b: zero);
1178 // subtract, square and accumulate
1179 const __m128i d0 = _mm_subs_epi16(a: a01s, b: b01s);
1180 const __m128i d1 = _mm_subs_epi16(a: a23s, b: b23s);
1181 const __m128i e0 = _mm_madd_epi16(a: d0, b: d0);
1182 const __m128i e1 = _mm_madd_epi16(a: d1, b: d1);
1183 const __m128i sum = _mm_add_epi32(a: e0, b: e1);
1184
1185 int32_t tmp[4];
1186 _mm_storeu_si128(p: (__m128i*)tmp, b: sum);
1187 return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
1188}
1189
1190//------------------------------------------------------------------------------
1191
1192static void Mean16x4_SSE2(const uint8_t* ref, uint32_t dc[4]) {
1193 const __m128i mask = _mm_set1_epi16(w: 0x00ff);
1194 const __m128i a0 = _mm_loadu_si128(p: (const __m128i*)&ref[BPS * 0]);
1195 const __m128i a1 = _mm_loadu_si128(p: (const __m128i*)&ref[BPS * 1]);
1196 const __m128i a2 = _mm_loadu_si128(p: (const __m128i*)&ref[BPS * 2]);
1197 const __m128i a3 = _mm_loadu_si128(p: (const __m128i*)&ref[BPS * 3]);
1198 const __m128i b0 = _mm_srli_epi16(a: a0, count: 8); // hi byte
1199 const __m128i b1 = _mm_srli_epi16(a: a1, count: 8);
1200 const __m128i b2 = _mm_srli_epi16(a: a2, count: 8);
1201 const __m128i b3 = _mm_srli_epi16(a: a3, count: 8);
1202 const __m128i c0 = _mm_and_si128(a: a0, b: mask); // lo byte
1203 const __m128i c1 = _mm_and_si128(a: a1, b: mask);
1204 const __m128i c2 = _mm_and_si128(a: a2, b: mask);
1205 const __m128i c3 = _mm_and_si128(a: a3, b: mask);
1206 const __m128i d0 = _mm_add_epi32(a: b0, b: c0);
1207 const __m128i d1 = _mm_add_epi32(a: b1, b: c1);
1208 const __m128i d2 = _mm_add_epi32(a: b2, b: c2);
1209 const __m128i d3 = _mm_add_epi32(a: b3, b: c3);
1210 const __m128i e0 = _mm_add_epi32(a: d0, b: d1);
1211 const __m128i e1 = _mm_add_epi32(a: d2, b: d3);
1212 const __m128i f0 = _mm_add_epi32(a: e0, b: e1);
1213 uint16_t tmp[8];
1214 _mm_storeu_si128(p: (__m128i*)tmp, b: f0);
1215 dc[0] = tmp[0] + tmp[1];
1216 dc[1] = tmp[2] + tmp[3];
1217 dc[2] = tmp[4] + tmp[5];
1218 dc[3] = tmp[6] + tmp[7];
1219}
1220
1221//------------------------------------------------------------------------------
1222// Texture distortion
1223//
1224// We try to match the spectral content (weighted) between source and
1225// reconstructed samples.
1226
1227// Hadamard transform
1228// Returns the weighted sum of the absolute value of transformed coefficients.
1229// w[] contains a row-major 4 by 4 symmetric matrix.
1230static int TTransform_SSE2(const uint8_t* inA, const uint8_t* inB,
1231 const uint16_t* const w) {
1232 int32_t sum[4];
1233 __m128i tmp_0, tmp_1, tmp_2, tmp_3;
1234 const __m128i zero = _mm_setzero_si128();
1235
1236 // Load and combine inputs.
1237 {
1238 const __m128i inA_0 = _mm_loadl_epi64(p: (const __m128i*)&inA[BPS * 0]);
1239 const __m128i inA_1 = _mm_loadl_epi64(p: (const __m128i*)&inA[BPS * 1]);
1240 const __m128i inA_2 = _mm_loadl_epi64(p: (const __m128i*)&inA[BPS * 2]);
1241 const __m128i inA_3 = _mm_loadl_epi64(p: (const __m128i*)&inA[BPS * 3]);
1242 const __m128i inB_0 = _mm_loadl_epi64(p: (const __m128i*)&inB[BPS * 0]);
1243 const __m128i inB_1 = _mm_loadl_epi64(p: (const __m128i*)&inB[BPS * 1]);
1244 const __m128i inB_2 = _mm_loadl_epi64(p: (const __m128i*)&inB[BPS * 2]);
1245 const __m128i inB_3 = _mm_loadl_epi64(p: (const __m128i*)&inB[BPS * 3]);
1246
1247 // Combine inA and inB (we'll do two transforms in parallel).
1248 const __m128i inAB_0 = _mm_unpacklo_epi32(a: inA_0, b: inB_0);
1249 const __m128i inAB_1 = _mm_unpacklo_epi32(a: inA_1, b: inB_1);
1250 const __m128i inAB_2 = _mm_unpacklo_epi32(a: inA_2, b: inB_2);
1251 const __m128i inAB_3 = _mm_unpacklo_epi32(a: inA_3, b: inB_3);
1252 tmp_0 = _mm_unpacklo_epi8(a: inAB_0, b: zero);
1253 tmp_1 = _mm_unpacklo_epi8(a: inAB_1, b: zero);
1254 tmp_2 = _mm_unpacklo_epi8(a: inAB_2, b: zero);
1255 tmp_3 = _mm_unpacklo_epi8(a: inAB_3, b: zero);
1256 // a00 a01 a02 a03 b00 b01 b02 b03
1257 // a10 a11 a12 a13 b10 b11 b12 b13
1258 // a20 a21 a22 a23 b20 b21 b22 b23
1259 // a30 a31 a32 a33 b30 b31 b32 b33
1260 }
1261
1262 // Vertical pass first to avoid a transpose (vertical and horizontal passes
1263 // are commutative because w/kWeightY is symmetric) and subsequent transpose.
1264 {
1265 // Calculate a and b (two 4x4 at once).
1266 const __m128i a0 = _mm_add_epi16(a: tmp_0, b: tmp_2);
1267 const __m128i a1 = _mm_add_epi16(a: tmp_1, b: tmp_3);
1268 const __m128i a2 = _mm_sub_epi16(a: tmp_1, b: tmp_3);
1269 const __m128i a3 = _mm_sub_epi16(a: tmp_0, b: tmp_2);
1270 const __m128i b0 = _mm_add_epi16(a: a0, b: a1);
1271 const __m128i b1 = _mm_add_epi16(a: a3, b: a2);
1272 const __m128i b2 = _mm_sub_epi16(a: a3, b: a2);
1273 const __m128i b3 = _mm_sub_epi16(a: a0, b: a1);
1274 // a00 a01 a02 a03 b00 b01 b02 b03
1275 // a10 a11 a12 a13 b10 b11 b12 b13
1276 // a20 a21 a22 a23 b20 b21 b22 b23
1277 // a30 a31 a32 a33 b30 b31 b32 b33
1278
1279 // Transpose the two 4x4.
1280 VP8Transpose_2_4x4_16b(in0: &b0, in1: &b1, in2: &b2, in3: &b3, out0: &tmp_0, out1: &tmp_1, out2: &tmp_2, out3: &tmp_3);
1281 }
1282
1283 // Horizontal pass and difference of weighted sums.
1284 {
1285 // Load all inputs.
1286 const __m128i w_0 = _mm_loadu_si128(p: (const __m128i*)&w[0]);
1287 const __m128i w_8 = _mm_loadu_si128(p: (const __m128i*)&w[8]);
1288
1289 // Calculate a and b (two 4x4 at once).
1290 const __m128i a0 = _mm_add_epi16(a: tmp_0, b: tmp_2);
1291 const __m128i a1 = _mm_add_epi16(a: tmp_1, b: tmp_3);
1292 const __m128i a2 = _mm_sub_epi16(a: tmp_1, b: tmp_3);
1293 const __m128i a3 = _mm_sub_epi16(a: tmp_0, b: tmp_2);
1294 const __m128i b0 = _mm_add_epi16(a: a0, b: a1);
1295 const __m128i b1 = _mm_add_epi16(a: a3, b: a2);
1296 const __m128i b2 = _mm_sub_epi16(a: a3, b: a2);
1297 const __m128i b3 = _mm_sub_epi16(a: a0, b: a1);
1298
1299 // Separate the transforms of inA and inB.
1300 __m128i A_b0 = _mm_unpacklo_epi64(a: b0, b: b1);
1301 __m128i A_b2 = _mm_unpacklo_epi64(a: b2, b: b3);
1302 __m128i B_b0 = _mm_unpackhi_epi64(a: b0, b: b1);
1303 __m128i B_b2 = _mm_unpackhi_epi64(a: b2, b: b3);
1304
1305 {
1306 const __m128i d0 = _mm_sub_epi16(a: zero, b: A_b0);
1307 const __m128i d1 = _mm_sub_epi16(a: zero, b: A_b2);
1308 const __m128i d2 = _mm_sub_epi16(a: zero, b: B_b0);
1309 const __m128i d3 = _mm_sub_epi16(a: zero, b: B_b2);
1310 A_b0 = _mm_max_epi16(a: A_b0, b: d0); // abs(v), 16b
1311 A_b2 = _mm_max_epi16(a: A_b2, b: d1);
1312 B_b0 = _mm_max_epi16(a: B_b0, b: d2);
1313 B_b2 = _mm_max_epi16(a: B_b2, b: d3);
1314 }
1315
1316 // weighted sums
1317 A_b0 = _mm_madd_epi16(a: A_b0, b: w_0);
1318 A_b2 = _mm_madd_epi16(a: A_b2, b: w_8);
1319 B_b0 = _mm_madd_epi16(a: B_b0, b: w_0);
1320 B_b2 = _mm_madd_epi16(a: B_b2, b: w_8);
1321 A_b0 = _mm_add_epi32(a: A_b0, b: A_b2);
1322 B_b0 = _mm_add_epi32(a: B_b0, b: B_b2);
1323
1324 // difference of weighted sums
1325 A_b0 = _mm_sub_epi32(a: A_b0, b: B_b0);
1326 _mm_storeu_si128(p: (__m128i*)&sum[0], b: A_b0);
1327 }
1328 return sum[0] + sum[1] + sum[2] + sum[3];
1329}
1330
1331static int Disto4x4_SSE2(const uint8_t* const a, const uint8_t* const b,
1332 const uint16_t* const w) {
1333 const int diff_sum = TTransform_SSE2(inA: a, inB: b, w);
1334 return abs(x: diff_sum) >> 5;
1335}
1336
1337static int Disto16x16_SSE2(const uint8_t* const a, const uint8_t* const b,
1338 const uint16_t* const w) {
1339 int D = 0;
1340 int x, y;
1341 for (y = 0; y < 16 * BPS; y += 4 * BPS) {
1342 for (x = 0; x < 16; x += 4) {
1343 D += Disto4x4_SSE2(a: a + x + y, b: b + x + y, w);
1344 }
1345 }
1346 return D;
1347}
1348
1349//------------------------------------------------------------------------------
1350// Quantization
1351//
1352
1353static WEBP_INLINE int DoQuantizeBlock_SSE2(int16_t in[16], int16_t out[16],
1354 const uint16_t* const sharpen,
1355 const VP8Matrix* const mtx) {
1356 const __m128i max_coeff_2047 = _mm_set1_epi16(w: MAX_LEVEL);
1357 const __m128i zero = _mm_setzero_si128();
1358 __m128i coeff0, coeff8;
1359 __m128i out0, out8;
1360 __m128i packed_out;
1361
1362 // Load all inputs.
1363 __m128i in0 = _mm_loadu_si128(p: (__m128i*)&in[0]);
1364 __m128i in8 = _mm_loadu_si128(p: (__m128i*)&in[8]);
1365 const __m128i iq0 = _mm_loadu_si128(p: (const __m128i*)&mtx->iq_[0]);
1366 const __m128i iq8 = _mm_loadu_si128(p: (const __m128i*)&mtx->iq_[8]);
1367 const __m128i q0 = _mm_loadu_si128(p: (const __m128i*)&mtx->q_[0]);
1368 const __m128i q8 = _mm_loadu_si128(p: (const __m128i*)&mtx->q_[8]);
1369
1370 // extract sign(in) (0x0000 if positive, 0xffff if negative)
1371 const __m128i sign0 = _mm_cmpgt_epi16(a: zero, b: in0);
1372 const __m128i sign8 = _mm_cmpgt_epi16(a: zero, b: in8);
1373
1374 // coeff = abs(in) = (in ^ sign) - sign
1375 coeff0 = _mm_xor_si128(a: in0, b: sign0);
1376 coeff8 = _mm_xor_si128(a: in8, b: sign8);
1377 coeff0 = _mm_sub_epi16(a: coeff0, b: sign0);
1378 coeff8 = _mm_sub_epi16(a: coeff8, b: sign8);
1379
1380 // coeff = abs(in) + sharpen
1381 if (sharpen != NULL) {
1382 const __m128i sharpen0 = _mm_loadu_si128(p: (const __m128i*)&sharpen[0]);
1383 const __m128i sharpen8 = _mm_loadu_si128(p: (const __m128i*)&sharpen[8]);
1384 coeff0 = _mm_add_epi16(a: coeff0, b: sharpen0);
1385 coeff8 = _mm_add_epi16(a: coeff8, b: sharpen8);
1386 }
1387
1388 // out = (coeff * iQ + B) >> QFIX
1389 {
1390 // doing calculations with 32b precision (QFIX=17)
1391 // out = (coeff * iQ)
1392 const __m128i coeff_iQ0H = _mm_mulhi_epu16(a: coeff0, b: iq0);
1393 const __m128i coeff_iQ0L = _mm_mullo_epi16(a: coeff0, b: iq0);
1394 const __m128i coeff_iQ8H = _mm_mulhi_epu16(a: coeff8, b: iq8);
1395 const __m128i coeff_iQ8L = _mm_mullo_epi16(a: coeff8, b: iq8);
1396 __m128i out_00 = _mm_unpacklo_epi16(a: coeff_iQ0L, b: coeff_iQ0H);
1397 __m128i out_04 = _mm_unpackhi_epi16(a: coeff_iQ0L, b: coeff_iQ0H);
1398 __m128i out_08 = _mm_unpacklo_epi16(a: coeff_iQ8L, b: coeff_iQ8H);
1399 __m128i out_12 = _mm_unpackhi_epi16(a: coeff_iQ8L, b: coeff_iQ8H);
1400 // out = (coeff * iQ + B)
1401 const __m128i bias_00 = _mm_loadu_si128(p: (const __m128i*)&mtx->bias_[0]);
1402 const __m128i bias_04 = _mm_loadu_si128(p: (const __m128i*)&mtx->bias_[4]);
1403 const __m128i bias_08 = _mm_loadu_si128(p: (const __m128i*)&mtx->bias_[8]);
1404 const __m128i bias_12 = _mm_loadu_si128(p: (const __m128i*)&mtx->bias_[12]);
1405 out_00 = _mm_add_epi32(a: out_00, b: bias_00);
1406 out_04 = _mm_add_epi32(a: out_04, b: bias_04);
1407 out_08 = _mm_add_epi32(a: out_08, b: bias_08);
1408 out_12 = _mm_add_epi32(a: out_12, b: bias_12);
1409 // out = QUANTDIV(coeff, iQ, B, QFIX)
1410 out_00 = _mm_srai_epi32(a: out_00, QFIX);
1411 out_04 = _mm_srai_epi32(a: out_04, QFIX);
1412 out_08 = _mm_srai_epi32(a: out_08, QFIX);
1413 out_12 = _mm_srai_epi32(a: out_12, QFIX);
1414
1415 // pack result as 16b
1416 out0 = _mm_packs_epi32(a: out_00, b: out_04);
1417 out8 = _mm_packs_epi32(a: out_08, b: out_12);
1418
1419 // if (coeff > 2047) coeff = 2047
1420 out0 = _mm_min_epi16(a: out0, b: max_coeff_2047);
1421 out8 = _mm_min_epi16(a: out8, b: max_coeff_2047);
1422 }
1423
1424 // get sign back (if (sign[j]) out_n = -out_n)
1425 out0 = _mm_xor_si128(a: out0, b: sign0);
1426 out8 = _mm_xor_si128(a: out8, b: sign8);
1427 out0 = _mm_sub_epi16(a: out0, b: sign0);
1428 out8 = _mm_sub_epi16(a: out8, b: sign8);
1429
1430 // in = out * Q
1431 in0 = _mm_mullo_epi16(a: out0, b: q0);
1432 in8 = _mm_mullo_epi16(a: out8, b: q8);
1433
1434 _mm_storeu_si128(p: (__m128i*)&in[0], b: in0);
1435 _mm_storeu_si128(p: (__m128i*)&in[8], b: in8);
1436
1437 // zigzag the output before storing it.
1438 //
1439 // The zigzag pattern can almost be reproduced with a small sequence of
1440 // shuffles. After it, we only need to swap the 7th (ending up in third
1441 // position instead of twelfth) and 8th values.
1442 {
1443 __m128i outZ0, outZ8;
1444 outZ0 = _mm_shufflehi_epi16(out0, _MM_SHUFFLE(2, 1, 3, 0));
1445 outZ0 = _mm_shuffle_epi32 (outZ0, _MM_SHUFFLE(3, 1, 2, 0));
1446 outZ0 = _mm_shufflehi_epi16(outZ0, _MM_SHUFFLE(3, 1, 0, 2));
1447 outZ8 = _mm_shufflelo_epi16(out8, _MM_SHUFFLE(3, 0, 2, 1));
1448 outZ8 = _mm_shuffle_epi32 (outZ8, _MM_SHUFFLE(3, 1, 2, 0));
1449 outZ8 = _mm_shufflelo_epi16(outZ8, _MM_SHUFFLE(1, 3, 2, 0));
1450 _mm_storeu_si128(p: (__m128i*)&out[0], b: outZ0);
1451 _mm_storeu_si128(p: (__m128i*)&out[8], b: outZ8);
1452 packed_out = _mm_packs_epi16(a: outZ0, b: outZ8);
1453 }
1454 {
1455 const int16_t outZ_12 = out[12];
1456 const int16_t outZ_3 = out[3];
1457 out[3] = outZ_12;
1458 out[12] = outZ_3;
1459 }
1460
1461 // detect if all 'out' values are zeroes or not
1462 return (_mm_movemask_epi8(a: _mm_cmpeq_epi8(a: packed_out, b: zero)) != 0xffff);
1463}
1464
1465static int QuantizeBlock_SSE2(int16_t in[16], int16_t out[16],
1466 const VP8Matrix* const mtx) {
1467 return DoQuantizeBlock_SSE2(in, out, sharpen: &mtx->sharpen_[0], mtx);
1468}
1469
1470static int QuantizeBlockWHT_SSE2(int16_t in[16], int16_t out[16],
1471 const VP8Matrix* const mtx) {
1472 return DoQuantizeBlock_SSE2(in, out, NULL, mtx);
1473}
1474
1475static int Quantize2Blocks_SSE2(int16_t in[32], int16_t out[32],
1476 const VP8Matrix* const mtx) {
1477 int nz;
1478 const uint16_t* const sharpen = &mtx->sharpen_[0];
1479 nz = DoQuantizeBlock_SSE2(in: in + 0 * 16, out: out + 0 * 16, sharpen, mtx) << 0;
1480 nz |= DoQuantizeBlock_SSE2(in: in + 1 * 16, out: out + 1 * 16, sharpen, mtx) << 1;
1481 return nz;
1482}
1483
1484//------------------------------------------------------------------------------
1485// Entry point
1486
1487extern void VP8EncDspInitSSE2(void);
1488
1489WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitSSE2(void) {
1490 VP8CollectHistogram = CollectHistogram_SSE2;
1491 VP8EncPredLuma16 = Intra16Preds_SSE2;
1492 VP8EncPredChroma8 = IntraChromaPreds_SSE2;
1493 VP8EncPredLuma4 = Intra4Preds_SSE2;
1494 VP8EncQuantizeBlock = QuantizeBlock_SSE2;
1495 VP8EncQuantize2Blocks = Quantize2Blocks_SSE2;
1496 VP8EncQuantizeBlockWHT = QuantizeBlockWHT_SSE2;
1497 VP8ITransform = ITransform_SSE2;
1498 VP8FTransform = FTransform_SSE2;
1499 VP8FTransform2 = FTransform2_SSE2;
1500 VP8FTransformWHT = FTransformWHT_SSE2;
1501 VP8SSE16x16 = SSE16x16_SSE2;
1502 VP8SSE16x8 = SSE16x8_SSE2;
1503 VP8SSE8x8 = SSE8x8_SSE2;
1504 VP8SSE4x4 = SSE4x4_SSE2;
1505 VP8TDisto4x4 = Disto4x4_SSE2;
1506 VP8TDisto16x16 = Disto16x16_SSE2;
1507 VP8Mean16x4 = Mean16x4_SSE2;
1508}
1509
1510#else // !WEBP_USE_SSE2
1511
1512WEBP_DSP_INIT_STUB(VP8EncDspInitSSE2)
1513
1514#endif // WEBP_USE_SSE2
1515

source code of qtimageformats/src/3rdparty/libwebp/src/dsp/enc_sse2.c