• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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