1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // -----------------------------------------------------------------------------
7 //
8 // ARM NEON version of speed-critical encoding functions.
9 //
10 // adapted from libvpx (http://www.webmproject.org/code/)
11
12 #include "./dsp.h"
13
14 #if defined(__cplusplus) || defined(c_plusplus)
15 extern "C" {
16 #endif
17
18 #if defined(WEBP_USE_NEON)
19
20 #include "../enc/vp8enci.h"
21
22 //------------------------------------------------------------------------------
23 // Transforms (Paragraph 14.4)
24
25 // Inverse transform.
26 // This code is pretty much the same as TransformOneNEON in the decoder, except
27 // for subtraction to *ref. See the comments there for algorithmic explanations.
ITransformOne(const uint8_t * ref,const int16_t * in,uint8_t * dst)28 static void ITransformOne(const uint8_t* ref,
29 const int16_t* in, uint8_t* dst) {
30 const int kBPS = BPS;
31 const int16_t kC1C2[] = { 20091, 17734, 0, 0 }; // kC1 / (kC2 >> 1) / 0 / 0
32
33 __asm__ volatile (
34 "vld1.16 {q1, q2}, [%[in]] \n"
35 "vld1.16 {d0}, [%[kC1C2]] \n"
36
37 // d2: in[0]
38 // d3: in[8]
39 // d4: in[4]
40 // d5: in[12]
41 "vswp d3, d4 \n"
42
43 // q8 = {in[4], in[12]} * kC1 * 2 >> 16
44 // q9 = {in[4], in[12]} * kC2 >> 16
45 "vqdmulh.s16 q8, q2, d0[0] \n"
46 "vqdmulh.s16 q9, q2, d0[1] \n"
47
48 // d22 = a = in[0] + in[8]
49 // d23 = b = in[0] - in[8]
50 "vqadd.s16 d22, d2, d3 \n"
51 "vqsub.s16 d23, d2, d3 \n"
52
53 // q8 = in[4]/[12] * kC1 >> 16
54 "vshr.s16 q8, q8, #1 \n"
55
56 // Add {in[4], in[12]} back after the multiplication.
57 "vqadd.s16 q8, q2, q8 \n"
58
59 // d20 = c = in[4]*kC2 - in[12]*kC1
60 // d21 = d = in[4]*kC1 + in[12]*kC2
61 "vqsub.s16 d20, d18, d17 \n"
62 "vqadd.s16 d21, d19, d16 \n"
63
64 // d2 = tmp[0] = a + d
65 // d3 = tmp[1] = b + c
66 // d4 = tmp[2] = b - c
67 // d5 = tmp[3] = a - d
68 "vqadd.s16 d2, d22, d21 \n"
69 "vqadd.s16 d3, d23, d20 \n"
70 "vqsub.s16 d4, d23, d20 \n"
71 "vqsub.s16 d5, d22, d21 \n"
72
73 "vzip.16 q1, q2 \n"
74 "vzip.16 q1, q2 \n"
75
76 "vswp d3, d4 \n"
77
78 // q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16
79 // q9 = {tmp[4], tmp[12]} * kC2 >> 16
80 "vqdmulh.s16 q8, q2, d0[0] \n"
81 "vqdmulh.s16 q9, q2, d0[1] \n"
82
83 // d22 = a = tmp[0] + tmp[8]
84 // d23 = b = tmp[0] - tmp[8]
85 "vqadd.s16 d22, d2, d3 \n"
86 "vqsub.s16 d23, d2, d3 \n"
87
88 "vshr.s16 q8, q8, #1 \n"
89 "vqadd.s16 q8, q2, q8 \n"
90
91 // d20 = c = in[4]*kC2 - in[12]*kC1
92 // d21 = d = in[4]*kC1 + in[12]*kC2
93 "vqsub.s16 d20, d18, d17 \n"
94 "vqadd.s16 d21, d19, d16 \n"
95
96 // d2 = tmp[0] = a + d
97 // d3 = tmp[1] = b + c
98 // d4 = tmp[2] = b - c
99 // d5 = tmp[3] = a - d
100 "vqadd.s16 d2, d22, d21 \n"
101 "vqadd.s16 d3, d23, d20 \n"
102 "vqsub.s16 d4, d23, d20 \n"
103 "vqsub.s16 d5, d22, d21 \n"
104
105 "vld1.32 d6[0], [%[ref]], %[kBPS] \n"
106 "vld1.32 d6[1], [%[ref]], %[kBPS] \n"
107 "vld1.32 d7[0], [%[ref]], %[kBPS] \n"
108 "vld1.32 d7[1], [%[ref]], %[kBPS] \n"
109
110 "sub %[ref], %[ref], %[kBPS], lsl #2 \n"
111
112 // (val) + 4 >> 3
113 "vrshr.s16 d2, d2, #3 \n"
114 "vrshr.s16 d3, d3, #3 \n"
115 "vrshr.s16 d4, d4, #3 \n"
116 "vrshr.s16 d5, d5, #3 \n"
117
118 "vzip.16 q1, q2 \n"
119 "vzip.16 q1, q2 \n"
120
121 // Must accumulate before saturating
122 "vmovl.u8 q8, d6 \n"
123 "vmovl.u8 q9, d7 \n"
124
125 "vqadd.s16 q1, q1, q8 \n"
126 "vqadd.s16 q2, q2, q9 \n"
127
128 "vqmovun.s16 d0, q1 \n"
129 "vqmovun.s16 d1, q2 \n"
130
131 "vst1.32 d0[0], [%[dst]], %[kBPS] \n"
132 "vst1.32 d0[1], [%[dst]], %[kBPS] \n"
133 "vst1.32 d1[0], [%[dst]], %[kBPS] \n"
134 "vst1.32 d1[1], [%[dst]] \n"
135
136 : [in] "+r"(in), [dst] "+r"(dst) // modified registers
137 : [kBPS] "r"(kBPS), [kC1C2] "r"(kC1C2), [ref] "r"(ref) // constants
138 : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" // clobbered
139 );
140 }
141
ITransform(const uint8_t * ref,const int16_t * in,uint8_t * dst,int do_two)142 static void ITransform(const uint8_t* ref,
143 const int16_t* in, uint8_t* dst, int do_two) {
144 ITransformOne(ref, in, dst);
145 if (do_two) {
146 ITransformOne(ref + 4, in + 16, dst + 4);
147 }
148 }
149
150 // Same code as dec_neon.c
ITransformWHT(const int16_t * in,int16_t * out)151 static void ITransformWHT(const int16_t* in, int16_t* out) {
152 const int kStep = 32; // The store is only incrementing the pointer as if we
153 // had stored a single byte.
154 __asm__ volatile (
155 // part 1
156 // load data into q0, q1
157 "vld1.16 {q0, q1}, [%[in]] \n"
158
159 "vaddl.s16 q2, d0, d3 \n" // a0 = in[0] + in[12]
160 "vaddl.s16 q3, d1, d2 \n" // a1 = in[4] + in[8]
161 "vsubl.s16 q4, d1, d2 \n" // a2 = in[4] - in[8]
162 "vsubl.s16 q5, d0, d3 \n" // a3 = in[0] - in[12]
163
164 "vadd.s32 q0, q2, q3 \n" // tmp[0] = a0 + a1
165 "vsub.s32 q2, q2, q3 \n" // tmp[8] = a0 - a1
166 "vadd.s32 q1, q5, q4 \n" // tmp[4] = a3 + a2
167 "vsub.s32 q3, q5, q4 \n" // tmp[12] = a3 - a2
168
169 // Transpose
170 // q0 = tmp[0, 4, 8, 12], q1 = tmp[2, 6, 10, 14]
171 // q2 = tmp[1, 5, 9, 13], q3 = tmp[3, 7, 11, 15]
172 "vswp d1, d4 \n" // vtrn.64 q0, q2
173 "vswp d3, d6 \n" // vtrn.64 q1, q3
174 "vtrn.32 q0, q1 \n"
175 "vtrn.32 q2, q3 \n"
176
177 "vmov.s32 q4, #3 \n" // dc = 3
178 "vadd.s32 q0, q0, q4 \n" // dc = tmp[0] + 3
179 "vadd.s32 q6, q0, q3 \n" // a0 = dc + tmp[3]
180 "vadd.s32 q7, q1, q2 \n" // a1 = tmp[1] + tmp[2]
181 "vsub.s32 q8, q1, q2 \n" // a2 = tmp[1] - tmp[2]
182 "vsub.s32 q9, q0, q3 \n" // a3 = dc - tmp[3]
183
184 "vadd.s32 q0, q6, q7 \n"
185 "vshrn.s32 d0, q0, #3 \n" // (a0 + a1) >> 3
186 "vadd.s32 q1, q9, q8 \n"
187 "vshrn.s32 d1, q1, #3 \n" // (a3 + a2) >> 3
188 "vsub.s32 q2, q6, q7 \n"
189 "vshrn.s32 d2, q2, #3 \n" // (a0 - a1) >> 3
190 "vsub.s32 q3, q9, q8 \n"
191 "vshrn.s32 d3, q3, #3 \n" // (a3 - a2) >> 3
192
193 // set the results to output
194 "vst1.16 d0[0], [%[out]], %[kStep] \n"
195 "vst1.16 d1[0], [%[out]], %[kStep] \n"
196 "vst1.16 d2[0], [%[out]], %[kStep] \n"
197 "vst1.16 d3[0], [%[out]], %[kStep] \n"
198 "vst1.16 d0[1], [%[out]], %[kStep] \n"
199 "vst1.16 d1[1], [%[out]], %[kStep] \n"
200 "vst1.16 d2[1], [%[out]], %[kStep] \n"
201 "vst1.16 d3[1], [%[out]], %[kStep] \n"
202 "vst1.16 d0[2], [%[out]], %[kStep] \n"
203 "vst1.16 d1[2], [%[out]], %[kStep] \n"
204 "vst1.16 d2[2], [%[out]], %[kStep] \n"
205 "vst1.16 d3[2], [%[out]], %[kStep] \n"
206 "vst1.16 d0[3], [%[out]], %[kStep] \n"
207 "vst1.16 d1[3], [%[out]], %[kStep] \n"
208 "vst1.16 d2[3], [%[out]], %[kStep] \n"
209 "vst1.16 d3[3], [%[out]], %[kStep] \n"
210
211 : [out] "+r"(out) // modified registers
212 : [in] "r"(in), [kStep] "r"(kStep) // constants
213 : "memory", "q0", "q1", "q2", "q3", "q4",
214 "q5", "q6", "q7", "q8", "q9" // clobbered
215 );
216 }
217
218 // Forward transform.
219
220 // adapted from vp8/encoder/arm/neon/shortfdct_neon.asm
221 static const int16_t kCoeff16[] = {
222 5352, 5352, 5352, 5352, 2217, 2217, 2217, 2217
223 };
224 static const int32_t kCoeff32[] = {
225 1812, 1812, 1812, 1812,
226 937, 937, 937, 937,
227 12000, 12000, 12000, 12000,
228 51000, 51000, 51000, 51000
229 };
230
FTransform(const uint8_t * src,const uint8_t * ref,int16_t * out)231 static void FTransform(const uint8_t* src, const uint8_t* ref,
232 int16_t* out) {
233 const int kBPS = BPS;
234 const uint8_t* src_ptr = src;
235 const uint8_t* ref_ptr = ref;
236 const int16_t* coeff16 = kCoeff16;
237 const int32_t* coeff32 = kCoeff32;
238
239 __asm__ volatile (
240 // load src into q4, q5 in high half
241 "vld1.8 {d8}, [%[src_ptr]], %[kBPS] \n"
242 "vld1.8 {d10}, [%[src_ptr]], %[kBPS] \n"
243 "vld1.8 {d9}, [%[src_ptr]], %[kBPS] \n"
244 "vld1.8 {d11}, [%[src_ptr]] \n"
245
246 // load ref into q6, q7 in high half
247 "vld1.8 {d12}, [%[ref_ptr]], %[kBPS] \n"
248 "vld1.8 {d14}, [%[ref_ptr]], %[kBPS] \n"
249 "vld1.8 {d13}, [%[ref_ptr]], %[kBPS] \n"
250 "vld1.8 {d15}, [%[ref_ptr]] \n"
251
252 // Pack the high values in to q4 and q6
253 "vtrn.32 q4, q5 \n"
254 "vtrn.32 q6, q7 \n"
255
256 // d[0-3] = src - ref
257 "vsubl.u8 q0, d8, d12 \n"
258 "vsubl.u8 q1, d9, d13 \n"
259
260 // load coeff16 into q8(d16=5352, d17=2217)
261 "vld1.16 {q8}, [%[coeff16]] \n"
262
263 // load coeff32 high half into q9 = 1812, q10 = 937
264 "vld1.32 {q9, q10}, [%[coeff32]]! \n"
265
266 // load coeff32 low half into q11=12000, q12=51000
267 "vld1.32 {q11,q12}, [%[coeff32]] \n"
268
269 // part 1
270 // Transpose. Register dN is the same as dN in C
271 "vtrn.32 d0, d2 \n"
272 "vtrn.32 d1, d3 \n"
273 "vtrn.16 d0, d1 \n"
274 "vtrn.16 d2, d3 \n"
275
276 "vadd.s16 d4, d0, d3 \n" // a0 = d0 + d3
277 "vadd.s16 d5, d1, d2 \n" // a1 = d1 + d2
278 "vsub.s16 d6, d1, d2 \n" // a2 = d1 - d2
279 "vsub.s16 d7, d0, d3 \n" // a3 = d0 - d3
280
281 "vadd.s16 d0, d4, d5 \n" // a0 + a1
282 "vshl.s16 d0, d0, #3 \n" // temp[0+i*4] = (a0+a1) << 3
283 "vsub.s16 d2, d4, d5 \n" // a0 - a1
284 "vshl.s16 d2, d2, #3 \n" // (temp[2+i*4] = (a0-a1) << 3
285
286 "vmlal.s16 q9, d7, d16 \n" // a3*5352 + 1812
287 "vmlal.s16 q10, d7, d17 \n" // a3*2217 + 937
288 "vmlal.s16 q9, d6, d17 \n" // a2*2217 + a3*5352 + 1812
289 "vmlsl.s16 q10, d6, d16 \n" // a3*2217 + 937 - a2*5352
290
291 // temp[1+i*4] = (d2*2217 + d3*5352 + 1812) >> 9
292 // temp[3+i*4] = (d3*2217 + 937 - d2*5352) >> 9
293 "vshrn.s32 d1, q9, #9 \n"
294 "vshrn.s32 d3, q10, #9 \n"
295
296 // part 2
297 // transpose d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12]
298 "vtrn.32 d0, d2 \n"
299 "vtrn.32 d1, d3 \n"
300 "vtrn.16 d0, d1 \n"
301 "vtrn.16 d2, d3 \n"
302
303 "vmov.s16 d26, #7 \n"
304
305 "vadd.s16 d4, d0, d3 \n" // a1 = ip[0] + ip[12]
306 "vadd.s16 d5, d1, d2 \n" // b1 = ip[4] + ip[8]
307 "vsub.s16 d6, d1, d2 \n" // c1 = ip[4] - ip[8]
308 "vadd.s16 d4, d4, d26 \n" // a1 + 7
309 "vsub.s16 d7, d0, d3 \n" // d1 = ip[0] - ip[12]
310
311 "vadd.s16 d0, d4, d5 \n" // op[0] = a1 + b1 + 7
312 "vsub.s16 d2, d4, d5 \n" // op[8] = a1 - b1 + 7
313
314 "vmlal.s16 q11, d7, d16 \n" // d1*5352 + 12000
315 "vmlal.s16 q12, d7, d17 \n" // d1*2217 + 51000
316
317 "vceq.s16 d4, d7, #0 \n"
318
319 "vshr.s16 d0, d0, #4 \n"
320 "vshr.s16 d2, d2, #4 \n"
321
322 "vmlal.s16 q11, d6, d17 \n" // c1*2217 + d1*5352 + 12000
323 "vmlsl.s16 q12, d6, d16 \n" // d1*2217 - c1*5352 + 51000
324
325 "vmvn.s16 d4, d4 \n"
326 // op[4] = (c1*2217 + d1*5352 + 12000)>>16
327 "vshrn.s32 d1, q11, #16 \n"
328 // op[4] += (d1!=0)
329 "vsub.s16 d1, d1, d4 \n"
330 // op[12]= (d1*2217 - c1*5352 + 51000)>>16
331 "vshrn.s32 d3, q12, #16 \n"
332
333 // set result to out array
334 "vst1.16 {q0, q1}, [%[out]] \n"
335 : [src_ptr] "+r"(src_ptr), [ref_ptr] "+r"(ref_ptr),
336 [coeff32] "+r"(coeff32) // modified registers
337 : [kBPS] "r"(kBPS), [coeff16] "r"(coeff16),
338 [out] "r"(out) // constants
339 : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
340 "q10", "q11", "q12", "q13" // clobbered
341 );
342 }
343
FTransformWHT(const int16_t * in,int16_t * out)344 static void FTransformWHT(const int16_t* in, int16_t* out) {
345 const int kStep = 32;
346 __asm__ volatile (
347 // d0 = in[0 * 16] , d1 = in[1 * 16]
348 // d2 = in[2 * 16] , d3 = in[3 * 16]
349 "vld1.16 d0[0], [%[in]], %[kStep] \n"
350 "vld1.16 d1[0], [%[in]], %[kStep] \n"
351 "vld1.16 d2[0], [%[in]], %[kStep] \n"
352 "vld1.16 d3[0], [%[in]], %[kStep] \n"
353 "vld1.16 d0[1], [%[in]], %[kStep] \n"
354 "vld1.16 d1[1], [%[in]], %[kStep] \n"
355 "vld1.16 d2[1], [%[in]], %[kStep] \n"
356 "vld1.16 d3[1], [%[in]], %[kStep] \n"
357 "vld1.16 d0[2], [%[in]], %[kStep] \n"
358 "vld1.16 d1[2], [%[in]], %[kStep] \n"
359 "vld1.16 d2[2], [%[in]], %[kStep] \n"
360 "vld1.16 d3[2], [%[in]], %[kStep] \n"
361 "vld1.16 d0[3], [%[in]], %[kStep] \n"
362 "vld1.16 d1[3], [%[in]], %[kStep] \n"
363 "vld1.16 d2[3], [%[in]], %[kStep] \n"
364 "vld1.16 d3[3], [%[in]], %[kStep] \n"
365
366 "vaddl.s16 q2, d0, d2 \n"
367 "vshl.s32 q2, q2, #2 \n" // a0=(in[0*16]+in[2*16])<<2
368 "vaddl.s16 q3, d1, d3 \n"
369 "vshl.s32 q3, q3, #2 \n" // a1=(in[1*16]+in[3*16])<<2
370 "vsubl.s16 q4, d1, d3 \n"
371 "vshl.s32 q4, q4, #2 \n" // a2=(in[1*16]-in[3*16])<<2
372 "vsubl.s16 q5, d0, d2 \n"
373 "vshl.s32 q5, q5, #2 \n" // a3=(in[0*16]-in[2*16])<<2
374
375 "vceq.s32 q10, q2, #0 \n"
376 "vmvn.s32 q10, q10 \n" // (a0 != 0)
377 "vqadd.s32 q6, q2, q3 \n" // (a0 + a1)
378 "vqsub.s32 q6, q6, q10 \n" // (a0 + a1) + (a0 != 0)
379 "vqadd.s32 q7, q5, q4 \n" // a3 + a2
380 "vqsub.s32 q8, q5, q4 \n" // a3 - a2
381 "vqsub.s32 q9, q2, q3 \n" // a0 - a1
382
383 // Transpose
384 // q6 = tmp[0, 1, 2, 3] ; q7 = tmp[ 4, 5, 6, 7]
385 // q8 = tmp[8, 9, 10, 11] ; q9 = tmp[12, 13, 14, 15]
386 "vswp d13, d16 \n" // vtrn.64 q0, q2
387 "vswp d15, d18 \n" // vtrn.64 q1, q3
388 "vtrn.32 q6, q7 \n"
389 "vtrn.32 q8, q9 \n"
390
391 "vqadd.s32 q0, q6, q8 \n" // a0 = tmp[0] + tmp[8]
392 "vqadd.s32 q1, q7, q9 \n" // a1 = tmp[4] + tmp[12]
393 "vqsub.s32 q2, q7, q9 \n" // a2 = tmp[4] - tmp[12]
394 "vqsub.s32 q3, q6, q8 \n" // a3 = tmp[0] - tmp[8]
395
396 "vqadd.s32 q4, q0, q1 \n" // b0 = a0 + a1
397 "vqadd.s32 q5, q3, q2 \n" // b1 = a3 + a2
398 "vqsub.s32 q6, q3, q2 \n" // b2 = a3 - a2
399 "vqsub.s32 q7, q0, q1 \n" // b3 = a0 - a1
400
401 "vmov.s32 q0, #3 \n" // q0 = 3
402
403 "vcgt.s32 q1, q4, #0 \n" // (b0>0)
404 "vqsub.s32 q2, q4, q1 \n" // (b0+(b0>0))
405 "vqadd.s32 q3, q2, q0 \n" // (b0+(b0>0)+3)
406 "vshrn.s32 d18, q3, #3 \n" // (b0+(b0>0)+3) >> 3
407
408 "vcgt.s32 q1, q5, #0 \n" // (b1>0)
409 "vqsub.s32 q2, q5, q1 \n" // (b1+(b1>0))
410 "vqadd.s32 q3, q2, q0 \n" // (b1+(b1>0)+3)
411 "vshrn.s32 d19, q3, #3 \n" // (b1+(b1>0)+3) >> 3
412
413 "vcgt.s32 q1, q6, #0 \n" // (b2>0)
414 "vqsub.s32 q2, q6, q1 \n" // (b2+(b2>0))
415 "vqadd.s32 q3, q2, q0 \n" // (b2+(b2>0)+3)
416 "vshrn.s32 d20, q3, #3 \n" // (b2+(b2>0)+3) >> 3
417
418 "vcgt.s32 q1, q7, #0 \n" // (b3>0)
419 "vqsub.s32 q2, q7, q1 \n" // (b3+(b3>0))
420 "vqadd.s32 q3, q2, q0 \n" // (b3+(b3>0)+3)
421 "vshrn.s32 d21, q3, #3 \n" // (b3+(b3>0)+3) >> 3
422
423 "vst1.16 {q9, q10}, [%[out]] \n"
424
425 : [in] "+r"(in)
426 : [kStep] "r"(kStep), [out] "r"(out)
427 : "memory", "q0", "q1", "q2", "q3", "q4", "q5",
428 "q6", "q7", "q8", "q9", "q10" // clobbered
429 ) ;
430 }
431
432 //------------------------------------------------------------------------------
433 // Texture distortion
434 //
435 // We try to match the spectral content (weighted) between source and
436 // reconstructed samples.
437
438 // Hadamard transform
439 // Returns the weighted sum of the absolute value of transformed coefficients.
440 // This uses a TTransform helper function in C
Disto4x4(const uint8_t * const a,const uint8_t * const b,const uint16_t * const w)441 static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
442 const uint16_t* const w) {
443 const int kBPS = BPS;
444 const uint8_t* A = a;
445 const uint8_t* B = b;
446 const uint16_t* W = w;
447 int sum;
448 __asm__ volatile (
449 "vld1.32 d0[0], [%[a]], %[kBPS] \n"
450 "vld1.32 d0[1], [%[a]], %[kBPS] \n"
451 "vld1.32 d2[0], [%[a]], %[kBPS] \n"
452 "vld1.32 d2[1], [%[a]] \n"
453
454 "vld1.32 d1[0], [%[b]], %[kBPS] \n"
455 "vld1.32 d1[1], [%[b]], %[kBPS] \n"
456 "vld1.32 d3[0], [%[b]], %[kBPS] \n"
457 "vld1.32 d3[1], [%[b]] \n"
458
459 // a d0/d2, b d1/d3
460 // d0/d1: 01 01 01 01
461 // d2/d3: 23 23 23 23
462 // But: it goes 01 45 23 67
463 // Notice the middle values are transposed
464 "vtrn.16 q0, q1 \n"
465
466 // {a0, a1} = {in[0] + in[2], in[1] + in[3]}
467 "vaddl.u8 q2, d0, d2 \n"
468 "vaddl.u8 q10, d1, d3 \n"
469 // {a3, a2} = {in[0] - in[2], in[1] - in[3]}
470 "vsubl.u8 q3, d0, d2 \n"
471 "vsubl.u8 q11, d1, d3 \n"
472
473 // tmp[0] = a0 + a1
474 "vpaddl.s16 q0, q2 \n"
475 "vpaddl.s16 q8, q10 \n"
476
477 // tmp[1] = a3 + a2
478 "vpaddl.s16 q1, q3 \n"
479 "vpaddl.s16 q9, q11 \n"
480
481 // No pair subtract
482 // q2 = {a0, a3}
483 // q3 = {a1, a2}
484 "vtrn.16 q2, q3 \n"
485 "vtrn.16 q10, q11 \n"
486
487 // {tmp[3], tmp[2]} = {a0 - a1, a3 - a2}
488 "vsubl.s16 q12, d4, d6 \n"
489 "vsubl.s16 q13, d5, d7 \n"
490 "vsubl.s16 q14, d20, d22 \n"
491 "vsubl.s16 q15, d21, d23 \n"
492
493 // separate tmp[3] and tmp[2]
494 // q12 = tmp[3]
495 // q13 = tmp[2]
496 "vtrn.32 q12, q13 \n"
497 "vtrn.32 q14, q15 \n"
498
499 // Transpose tmp for a
500 "vswp d1, d26 \n" // vtrn.64
501 "vswp d3, d24 \n" // vtrn.64
502 "vtrn.32 q0, q1 \n"
503 "vtrn.32 q13, q12 \n"
504
505 // Transpose tmp for b
506 "vswp d17, d30 \n" // vtrn.64
507 "vswp d19, d28 \n" // vtrn.64
508 "vtrn.32 q8, q9 \n"
509 "vtrn.32 q15, q14 \n"
510
511 // The first Q register is a, the second b.
512 // q0/8 tmp[0-3]
513 // q13/15 tmp[4-7]
514 // q1/9 tmp[8-11]
515 // q12/14 tmp[12-15]
516
517 // These are still in 01 45 23 67 order. We fix it easily in the addition
518 // case but the subtraction propegates them.
519 "vswp d3, d27 \n"
520 "vswp d19, d31 \n"
521
522 // a0 = tmp[0] + tmp[8]
523 "vadd.s32 q2, q0, q1 \n"
524 "vadd.s32 q3, q8, q9 \n"
525
526 // a1 = tmp[4] + tmp[12]
527 "vadd.s32 q10, q13, q12 \n"
528 "vadd.s32 q11, q15, q14 \n"
529
530 // a2 = tmp[4] - tmp[12]
531 "vsub.s32 q13, q13, q12 \n"
532 "vsub.s32 q15, q15, q14 \n"
533
534 // a3 = tmp[0] - tmp[8]
535 "vsub.s32 q0, q0, q1 \n"
536 "vsub.s32 q8, q8, q9 \n"
537
538 // b0 = a0 + a1
539 "vadd.s32 q1, q2, q10 \n"
540 "vadd.s32 q9, q3, q11 \n"
541
542 // b1 = a3 + a2
543 "vadd.s32 q12, q0, q13 \n"
544 "vadd.s32 q14, q8, q15 \n"
545
546 // b2 = a3 - a2
547 "vsub.s32 q0, q0, q13 \n"
548 "vsub.s32 q8, q8, q15 \n"
549
550 // b3 = a0 - a1
551 "vsub.s32 q2, q2, q10 \n"
552 "vsub.s32 q3, q3, q11 \n"
553
554 "vld1.64 {q10, q11}, [%[w]] \n"
555
556 // abs(b0)
557 "vabs.s32 q1, q1 \n"
558 "vabs.s32 q9, q9 \n"
559 // abs(b1)
560 "vabs.s32 q12, q12 \n"
561 "vabs.s32 q14, q14 \n"
562 // abs(b2)
563 "vabs.s32 q0, q0 \n"
564 "vabs.s32 q8, q8 \n"
565 // abs(b3)
566 "vabs.s32 q2, q2 \n"
567 "vabs.s32 q3, q3 \n"
568
569 // expand w before using.
570 "vmovl.u16 q13, d20 \n"
571 "vmovl.u16 q15, d21 \n"
572
573 // w[0] * abs(b0)
574 "vmul.u32 q1, q1, q13 \n"
575 "vmul.u32 q9, q9, q13 \n"
576
577 // w[4] * abs(b1)
578 "vmla.u32 q1, q12, q15 \n"
579 "vmla.u32 q9, q14, q15 \n"
580
581 // expand w before using.
582 "vmovl.u16 q13, d22 \n"
583 "vmovl.u16 q15, d23 \n"
584
585 // w[8] * abs(b1)
586 "vmla.u32 q1, q0, q13 \n"
587 "vmla.u32 q9, q8, q13 \n"
588
589 // w[12] * abs(b1)
590 "vmla.u32 q1, q2, q15 \n"
591 "vmla.u32 q9, q3, q15 \n"
592
593 // Sum the arrays
594 "vpaddl.u32 q1, q1 \n"
595 "vpaddl.u32 q9, q9 \n"
596 "vadd.u64 d2, d3 \n"
597 "vadd.u64 d18, d19 \n"
598
599 // Hadamard transform needs 4 bits of extra precision (2 bits in each
600 // direction) for dynamic raw. Weights w[] are 16bits at max, so the maximum
601 // precision for coeff is 8bit of input + 4bits of Hadamard transform +
602 // 16bits for w[] + 2 bits of abs() summation.
603 //
604 // This uses a maximum of 31 bits (signed). Discarding the top 32 bits is
605 // A-OK.
606
607 // sum2 - sum1
608 "vsub.u32 d0, d2, d18 \n"
609 // abs(sum2 - sum1)
610 "vabs.s32 d0, d0 \n"
611 // abs(sum2 - sum1) >> 5
612 "vshr.u32 d0, #5 \n"
613
614 // It would be better to move the value straight into r0 but I'm not
615 // entirely sure how this works with inline assembly.
616 "vmov.32 %[sum], d0[0] \n"
617
618 : [sum] "=r"(sum), [a] "+r"(A), [b] "+r"(B), [w] "+r"(W)
619 : [kBPS] "r"(kBPS)
620 : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
621 "q10", "q11", "q12", "q13", "q14", "q15" // clobbered
622 ) ;
623
624 return sum;
625 }
626
Disto16x16(const uint8_t * const a,const uint8_t * const b,const uint16_t * const w)627 static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
628 const uint16_t* const w) {
629 int D = 0;
630 int x, y;
631 for (y = 0; y < 16 * BPS; y += 4 * BPS) {
632 for (x = 0; x < 16; x += 4) {
633 D += Disto4x4(a + x + y, b + x + y, w);
634 }
635 }
636 return D;
637 }
638
639 #endif // WEBP_USE_NEON
640
641 //------------------------------------------------------------------------------
642 // Entry point
643
644 extern void VP8EncDspInitNEON(void);
645
VP8EncDspInitNEON(void)646 void VP8EncDspInitNEON(void) {
647 #if defined(WEBP_USE_NEON)
648 VP8ITransform = ITransform;
649 VP8FTransform = FTransform;
650
651 VP8ITransformWHT = ITransformWHT;
652 VP8FTransformWHT = FTransformWHT;
653
654 VP8TDisto4x4 = Disto4x4;
655 VP8TDisto16x16 = Disto16x16;
656 #endif // WEBP_USE_NEON
657 }
658
659 #if defined(__cplusplus) || defined(c_plusplus)
660 } // extern "C"
661 #endif
662