1 /*
2 * Copyright (c) 2014 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <arm_neon.h>
12 #include <assert.h>
13
14 #include "./vpx_config.h"
15 #include "./vpx_dsp_rtcd.h"
16 #include "vpx/vpx_integer.h"
17 #include "vpx_ports/mem.h"
18
MULTIPLY_BY_Q0(int16x4_t dsrc0,int16x4_t dsrc1,int16x4_t dsrc2,int16x4_t dsrc3,int16x4_t dsrc4,int16x4_t dsrc5,int16x4_t dsrc6,int16x4_t dsrc7,int16x8_t q0s16)19 static INLINE int32x4_t MULTIPLY_BY_Q0(
20 int16x4_t dsrc0,
21 int16x4_t dsrc1,
22 int16x4_t dsrc2,
23 int16x4_t dsrc3,
24 int16x4_t dsrc4,
25 int16x4_t dsrc5,
26 int16x4_t dsrc6,
27 int16x4_t dsrc7,
28 int16x8_t q0s16) {
29 int32x4_t qdst;
30 int16x4_t d0s16, d1s16;
31
32 d0s16 = vget_low_s16(q0s16);
33 d1s16 = vget_high_s16(q0s16);
34
35 qdst = vmull_lane_s16(dsrc0, d0s16, 0);
36 qdst = vmlal_lane_s16(qdst, dsrc1, d0s16, 1);
37 qdst = vmlal_lane_s16(qdst, dsrc2, d0s16, 2);
38 qdst = vmlal_lane_s16(qdst, dsrc3, d0s16, 3);
39 qdst = vmlal_lane_s16(qdst, dsrc4, d1s16, 0);
40 qdst = vmlal_lane_s16(qdst, dsrc5, d1s16, 1);
41 qdst = vmlal_lane_s16(qdst, dsrc6, d1s16, 2);
42 qdst = vmlal_lane_s16(qdst, dsrc7, d1s16, 3);
43 return qdst;
44 }
45
vpx_convolve8_avg_horiz_neon(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const int16_t * filter_x,int x_step_q4,const int16_t * filter_y,int y_step_q4,int w,int h)46 void vpx_convolve8_avg_horiz_neon(
47 const uint8_t *src,
48 ptrdiff_t src_stride,
49 uint8_t *dst,
50 ptrdiff_t dst_stride,
51 const int16_t *filter_x,
52 int x_step_q4,
53 const int16_t *filter_y, // unused
54 int y_step_q4, // unused
55 int w,
56 int h) {
57 int width;
58 const uint8_t *s;
59 uint8_t *d;
60 uint8x8_t d2u8, d3u8, d24u8, d25u8, d26u8, d27u8, d28u8, d29u8;
61 uint32x2_t d2u32, d3u32, d6u32, d7u32, d28u32, d29u32, d30u32, d31u32;
62 uint8x16_t q1u8, q3u8, q12u8, q13u8, q14u8, q15u8;
63 int16x4_t d16s16, d17s16, d18s16, d19s16, d20s16, d22s16, d23s16;
64 int16x4_t d24s16, d25s16, d26s16, d27s16;
65 uint16x4_t d2u16, d3u16, d4u16, d5u16, d16u16, d17u16, d18u16, d19u16;
66 int16x8_t q0s16;
67 uint16x8_t q1u16, q2u16, q8u16, q9u16, q10u16, q11u16, q12u16, q13u16;
68 int32x4_t q1s32, q2s32, q14s32, q15s32;
69 uint16x8x2_t q0x2u16;
70 uint8x8x2_t d0x2u8, d1x2u8;
71 uint32x2x2_t d0x2u32;
72 uint16x4x2_t d0x2u16, d1x2u16;
73 uint32x4x2_t q0x2u32;
74
75 assert(x_step_q4 == 16);
76
77 q0s16 = vld1q_s16(filter_x);
78
79 src -= 3; // adjust for taps
80 for (; h > 0; h -= 4) { // loop_horiz_v
81 s = src;
82 d24u8 = vld1_u8(s);
83 s += src_stride;
84 d25u8 = vld1_u8(s);
85 s += src_stride;
86 d26u8 = vld1_u8(s);
87 s += src_stride;
88 d27u8 = vld1_u8(s);
89
90 q12u8 = vcombine_u8(d24u8, d25u8);
91 q13u8 = vcombine_u8(d26u8, d27u8);
92
93 q0x2u16 = vtrnq_u16(vreinterpretq_u16_u8(q12u8),
94 vreinterpretq_u16_u8(q13u8));
95 d24u8 = vreinterpret_u8_u16(vget_low_u16(q0x2u16.val[0]));
96 d25u8 = vreinterpret_u8_u16(vget_high_u16(q0x2u16.val[0]));
97 d26u8 = vreinterpret_u8_u16(vget_low_u16(q0x2u16.val[1]));
98 d27u8 = vreinterpret_u8_u16(vget_high_u16(q0x2u16.val[1]));
99 d0x2u8 = vtrn_u8(d24u8, d25u8);
100 d1x2u8 = vtrn_u8(d26u8, d27u8);
101
102 __builtin_prefetch(src + src_stride * 4);
103 __builtin_prefetch(src + src_stride * 5);
104
105 q8u16 = vmovl_u8(d0x2u8.val[0]);
106 q9u16 = vmovl_u8(d0x2u8.val[1]);
107 q10u16 = vmovl_u8(d1x2u8.val[0]);
108 q11u16 = vmovl_u8(d1x2u8.val[1]);
109
110 src += 7;
111 d16u16 = vget_low_u16(q8u16);
112 d17u16 = vget_high_u16(q8u16);
113 d18u16 = vget_low_u16(q9u16);
114 d19u16 = vget_high_u16(q9u16);
115 q8u16 = vcombine_u16(d16u16, d18u16); // vswp 17 18
116 q9u16 = vcombine_u16(d17u16, d19u16);
117
118 d20s16 = vreinterpret_s16_u16(vget_low_u16(q10u16));
119 d23s16 = vreinterpret_s16_u16(vget_high_u16(q10u16)); // vmov 23 21
120 for (width = w;
121 width > 0;
122 width -= 4, src += 4, dst += 4) { // loop_horiz
123 s = src;
124 d28u32 = vld1_dup_u32((const uint32_t *)s);
125 s += src_stride;
126 d29u32 = vld1_dup_u32((const uint32_t *)s);
127 s += src_stride;
128 d31u32 = vld1_dup_u32((const uint32_t *)s);
129 s += src_stride;
130 d30u32 = vld1_dup_u32((const uint32_t *)s);
131
132 __builtin_prefetch(src + 64);
133
134 d0x2u16 = vtrn_u16(vreinterpret_u16_u32(d28u32),
135 vreinterpret_u16_u32(d31u32));
136 d1x2u16 = vtrn_u16(vreinterpret_u16_u32(d29u32),
137 vreinterpret_u16_u32(d30u32));
138 d0x2u8 = vtrn_u8(vreinterpret_u8_u16(d0x2u16.val[0]), // d28
139 vreinterpret_u8_u16(d1x2u16.val[0])); // d29
140 d1x2u8 = vtrn_u8(vreinterpret_u8_u16(d0x2u16.val[1]), // d31
141 vreinterpret_u8_u16(d1x2u16.val[1])); // d30
142
143 __builtin_prefetch(src + 64 + src_stride);
144
145 q14u8 = vcombine_u8(d0x2u8.val[0], d0x2u8.val[1]);
146 q15u8 = vcombine_u8(d1x2u8.val[1], d1x2u8.val[0]);
147 q0x2u32 = vtrnq_u32(vreinterpretq_u32_u8(q14u8),
148 vreinterpretq_u32_u8(q15u8));
149
150 d28u8 = vreinterpret_u8_u32(vget_low_u32(q0x2u32.val[0]));
151 d29u8 = vreinterpret_u8_u32(vget_high_u32(q0x2u32.val[0]));
152 q12u16 = vmovl_u8(d28u8);
153 q13u16 = vmovl_u8(d29u8);
154
155 __builtin_prefetch(src + 64 + src_stride * 2);
156
157 d = dst;
158 d6u32 = vld1_lane_u32((const uint32_t *)d, d6u32, 0);
159 d += dst_stride;
160 d7u32 = vld1_lane_u32((const uint32_t *)d, d7u32, 0);
161 d += dst_stride;
162 d6u32 = vld1_lane_u32((const uint32_t *)d, d6u32, 1);
163 d += dst_stride;
164 d7u32 = vld1_lane_u32((const uint32_t *)d, d7u32, 1);
165
166 d16s16 = vreinterpret_s16_u16(vget_low_u16(q8u16));
167 d17s16 = vreinterpret_s16_u16(vget_high_u16(q8u16));
168 d18s16 = vreinterpret_s16_u16(vget_low_u16(q9u16));
169 d19s16 = vreinterpret_s16_u16(vget_high_u16(q9u16));
170 d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16));
171 d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16));
172 d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16));
173 d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16));
174 d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16));
175
176 q1s32 = MULTIPLY_BY_Q0(d16s16, d17s16, d20s16, d22s16,
177 d18s16, d19s16, d23s16, d24s16, q0s16);
178 q2s32 = MULTIPLY_BY_Q0(d17s16, d20s16, d22s16, d18s16,
179 d19s16, d23s16, d24s16, d26s16, q0s16);
180 q14s32 = MULTIPLY_BY_Q0(d20s16, d22s16, d18s16, d19s16,
181 d23s16, d24s16, d26s16, d27s16, q0s16);
182 q15s32 = MULTIPLY_BY_Q0(d22s16, d18s16, d19s16, d23s16,
183 d24s16, d26s16, d27s16, d25s16, q0s16);
184
185 __builtin_prefetch(src + 64 + src_stride * 3);
186
187 d2u16 = vqrshrun_n_s32(q1s32, 7);
188 d3u16 = vqrshrun_n_s32(q2s32, 7);
189 d4u16 = vqrshrun_n_s32(q14s32, 7);
190 d5u16 = vqrshrun_n_s32(q15s32, 7);
191
192 q1u16 = vcombine_u16(d2u16, d3u16);
193 q2u16 = vcombine_u16(d4u16, d5u16);
194
195 d2u8 = vqmovn_u16(q1u16);
196 d3u8 = vqmovn_u16(q2u16);
197
198 d0x2u16 = vtrn_u16(vreinterpret_u16_u8(d2u8),
199 vreinterpret_u16_u8(d3u8));
200 d0x2u32 = vtrn_u32(vreinterpret_u32_u16(d0x2u16.val[0]),
201 vreinterpret_u32_u16(d0x2u16.val[1]));
202 d0x2u8 = vtrn_u8(vreinterpret_u8_u32(d0x2u32.val[0]),
203 vreinterpret_u8_u32(d0x2u32.val[1]));
204
205 q1u8 = vcombine_u8(d0x2u8.val[0], d0x2u8.val[1]);
206 q3u8 = vreinterpretq_u8_u32(vcombine_u32(d6u32, d7u32));
207
208 q1u8 = vrhaddq_u8(q1u8, q3u8);
209
210 d2u32 = vreinterpret_u32_u8(vget_low_u8(q1u8));
211 d3u32 = vreinterpret_u32_u8(vget_high_u8(q1u8));
212
213 d = dst;
214 vst1_lane_u32((uint32_t *)d, d2u32, 0);
215 d += dst_stride;
216 vst1_lane_u32((uint32_t *)d, d3u32, 0);
217 d += dst_stride;
218 vst1_lane_u32((uint32_t *)d, d2u32, 1);
219 d += dst_stride;
220 vst1_lane_u32((uint32_t *)d, d3u32, 1);
221
222 q8u16 = q9u16;
223 d20s16 = d23s16;
224 q11u16 = q12u16;
225 q9u16 = q13u16;
226 d23s16 = vreinterpret_s16_u16(vget_high_u16(q11u16));
227 }
228 src += src_stride * 4 - w - 7;
229 dst += dst_stride * 4 - w;
230 }
231 return;
232 }
233
vpx_convolve8_avg_vert_neon(const uint8_t * src,ptrdiff_t src_stride,uint8_t * dst,ptrdiff_t dst_stride,const int16_t * filter_x,int x_step_q4,const int16_t * filter_y,int y_step_q4,int w,int h)234 void vpx_convolve8_avg_vert_neon(
235 const uint8_t *src,
236 ptrdiff_t src_stride,
237 uint8_t *dst,
238 ptrdiff_t dst_stride,
239 const int16_t *filter_x, // unused
240 int x_step_q4, // unused
241 const int16_t *filter_y,
242 int y_step_q4,
243 int w,
244 int h) {
245 int height;
246 const uint8_t *s;
247 uint8_t *d;
248 uint8x8_t d2u8, d3u8;
249 uint32x2_t d2u32, d3u32, d6u32, d7u32;
250 uint32x2_t d16u32, d18u32, d20u32, d22u32, d24u32, d26u32;
251 uint8x16_t q1u8, q3u8;
252 int16x4_t d16s16, d17s16, d18s16, d19s16, d20s16, d21s16, d22s16;
253 int16x4_t d24s16, d25s16, d26s16, d27s16;
254 uint16x4_t d2u16, d3u16, d4u16, d5u16;
255 int16x8_t q0s16;
256 uint16x8_t q1u16, q2u16, q8u16, q9u16, q10u16, q11u16, q12u16, q13u16;
257 int32x4_t q1s32, q2s32, q14s32, q15s32;
258
259 assert(y_step_q4 == 16);
260
261 src -= src_stride * 3;
262 q0s16 = vld1q_s16(filter_y);
263 for (; w > 0; w -= 4, src += 4, dst += 4) { // loop_vert_h
264 s = src;
265 d16u32 = vld1_lane_u32((const uint32_t *)s, d16u32, 0);
266 s += src_stride;
267 d16u32 = vld1_lane_u32((const uint32_t *)s, d16u32, 1);
268 s += src_stride;
269 d18u32 = vld1_lane_u32((const uint32_t *)s, d18u32, 0);
270 s += src_stride;
271 d18u32 = vld1_lane_u32((const uint32_t *)s, d18u32, 1);
272 s += src_stride;
273 d20u32 = vld1_lane_u32((const uint32_t *)s, d20u32, 0);
274 s += src_stride;
275 d20u32 = vld1_lane_u32((const uint32_t *)s, d20u32, 1);
276 s += src_stride;
277 d22u32 = vld1_lane_u32((const uint32_t *)s, d22u32, 0);
278 s += src_stride;
279
280 q8u16 = vmovl_u8(vreinterpret_u8_u32(d16u32));
281 q9u16 = vmovl_u8(vreinterpret_u8_u32(d18u32));
282 q10u16 = vmovl_u8(vreinterpret_u8_u32(d20u32));
283 q11u16 = vmovl_u8(vreinterpret_u8_u32(d22u32));
284
285 d18s16 = vreinterpret_s16_u16(vget_low_u16(q9u16));
286 d19s16 = vreinterpret_s16_u16(vget_high_u16(q9u16));
287 d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16));
288 d = dst;
289 for (height = h; height > 0; height -= 4) { // loop_vert
290 d24u32 = vld1_lane_u32((const uint32_t *)s, d24u32, 0);
291 s += src_stride;
292 d26u32 = vld1_lane_u32((const uint32_t *)s, d26u32, 0);
293 s += src_stride;
294 d26u32 = vld1_lane_u32((const uint32_t *)s, d26u32, 1);
295 s += src_stride;
296 d24u32 = vld1_lane_u32((const uint32_t *)s, d24u32, 1);
297 s += src_stride;
298
299 q12u16 = vmovl_u8(vreinterpret_u8_u32(d24u32));
300 q13u16 = vmovl_u8(vreinterpret_u8_u32(d26u32));
301
302 d6u32 = vld1_lane_u32((const uint32_t *)d, d6u32, 0);
303 d += dst_stride;
304 d6u32 = vld1_lane_u32((const uint32_t *)d, d6u32, 1);
305 d += dst_stride;
306 d7u32 = vld1_lane_u32((const uint32_t *)d, d7u32, 0);
307 d += dst_stride;
308 d7u32 = vld1_lane_u32((const uint32_t *)d, d7u32, 1);
309 d -= dst_stride * 3;
310
311 d16s16 = vreinterpret_s16_u16(vget_low_u16(q8u16));
312 d17s16 = vreinterpret_s16_u16(vget_high_u16(q8u16));
313 d20s16 = vreinterpret_s16_u16(vget_low_u16(q10u16));
314 d21s16 = vreinterpret_s16_u16(vget_high_u16(q10u16));
315 d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16));
316 d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16));
317 d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16));
318 d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16));
319
320 __builtin_prefetch(s);
321 __builtin_prefetch(s + src_stride);
322 q1s32 = MULTIPLY_BY_Q0(d16s16, d17s16, d18s16, d19s16,
323 d20s16, d21s16, d22s16, d24s16, q0s16);
324 __builtin_prefetch(s + src_stride * 2);
325 __builtin_prefetch(s + src_stride * 3);
326 q2s32 = MULTIPLY_BY_Q0(d17s16, d18s16, d19s16, d20s16,
327 d21s16, d22s16, d24s16, d26s16, q0s16);
328 __builtin_prefetch(d);
329 __builtin_prefetch(d + dst_stride);
330 q14s32 = MULTIPLY_BY_Q0(d18s16, d19s16, d20s16, d21s16,
331 d22s16, d24s16, d26s16, d27s16, q0s16);
332 __builtin_prefetch(d + dst_stride * 2);
333 __builtin_prefetch(d + dst_stride * 3);
334 q15s32 = MULTIPLY_BY_Q0(d19s16, d20s16, d21s16, d22s16,
335 d24s16, d26s16, d27s16, d25s16, q0s16);
336
337 d2u16 = vqrshrun_n_s32(q1s32, 7);
338 d3u16 = vqrshrun_n_s32(q2s32, 7);
339 d4u16 = vqrshrun_n_s32(q14s32, 7);
340 d5u16 = vqrshrun_n_s32(q15s32, 7);
341
342 q1u16 = vcombine_u16(d2u16, d3u16);
343 q2u16 = vcombine_u16(d4u16, d5u16);
344
345 d2u8 = vqmovn_u16(q1u16);
346 d3u8 = vqmovn_u16(q2u16);
347
348 q1u8 = vcombine_u8(d2u8, d3u8);
349 q3u8 = vreinterpretq_u8_u32(vcombine_u32(d6u32, d7u32));
350
351 q1u8 = vrhaddq_u8(q1u8, q3u8);
352
353 d2u32 = vreinterpret_u32_u8(vget_low_u8(q1u8));
354 d3u32 = vreinterpret_u32_u8(vget_high_u8(q1u8));
355
356 vst1_lane_u32((uint32_t *)d, d2u32, 0);
357 d += dst_stride;
358 vst1_lane_u32((uint32_t *)d, d2u32, 1);
359 d += dst_stride;
360 vst1_lane_u32((uint32_t *)d, d3u32, 0);
361 d += dst_stride;
362 vst1_lane_u32((uint32_t *)d, d3u32, 1);
363 d += dst_stride;
364
365 q8u16 = q10u16;
366 d18s16 = d22s16;
367 d19s16 = d24s16;
368 q10u16 = q13u16;
369 d22s16 = d25s16;
370 }
371 }
372 return;
373 }
374