• 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_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_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, *psrc;
59   uint8_t *d, *pdst;
60   uint8x8_t d2u8, d3u8, d24u8, d25u8, d26u8, d27u8, d28u8, d29u8;
61   uint32x2_t d2u32, d3u32, d28u32, d29u32, d30u32, d31u32;
62   uint8x16_t 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,
81     src += src_stride * 4,
82     dst += dst_stride * 4) {  // loop_horiz_v
83     s = src;
84     d24u8 = vld1_u8(s);
85     s += src_stride;
86     d25u8 = vld1_u8(s);
87     s += src_stride;
88     d26u8 = vld1_u8(s);
89     s += src_stride;
90     d27u8 = vld1_u8(s);
91 
92     q12u8 = vcombine_u8(d24u8, d25u8);
93     q13u8 = vcombine_u8(d26u8, d27u8);
94 
95     q0x2u16 = vtrnq_u16(vreinterpretq_u16_u8(q12u8),
96                         vreinterpretq_u16_u8(q13u8));
97     d24u8 = vreinterpret_u8_u16(vget_low_u16(q0x2u16.val[0]));
98     d25u8 = vreinterpret_u8_u16(vget_high_u16(q0x2u16.val[0]));
99     d26u8 = vreinterpret_u8_u16(vget_low_u16(q0x2u16.val[1]));
100     d27u8 = vreinterpret_u8_u16(vget_high_u16(q0x2u16.val[1]));
101     d0x2u8 = vtrn_u8(d24u8, d25u8);
102     d1x2u8 = vtrn_u8(d26u8, d27u8);
103 
104     __builtin_prefetch(src + src_stride * 4);
105     __builtin_prefetch(src + src_stride * 5);
106     __builtin_prefetch(src + src_stride * 6);
107 
108     q8u16  = vmovl_u8(d0x2u8.val[0]);
109     q9u16  = vmovl_u8(d0x2u8.val[1]);
110     q10u16 = vmovl_u8(d1x2u8.val[0]);
111     q11u16 = vmovl_u8(d1x2u8.val[1]);
112 
113     d16u16 = vget_low_u16(q8u16);
114     d17u16 = vget_high_u16(q8u16);
115     d18u16 = vget_low_u16(q9u16);
116     d19u16 = vget_high_u16(q9u16);
117     q8u16 = vcombine_u16(d16u16, d18u16);  // vswp 17 18
118     q9u16 = vcombine_u16(d17u16, d19u16);
119 
120     d20s16 = vreinterpret_s16_u16(vget_low_u16(q10u16));
121     d23s16 = vreinterpret_s16_u16(vget_high_u16(q10u16));  // vmov 23 21
122     for (width = w, psrc = src + 7, pdst = dst;
123          width > 0;
124          width -= 4, psrc += 4, pdst += 4) {  // loop_horiz
125       s = psrc;
126       d28u32 = vld1_dup_u32((const uint32_t *)s);
127       s += src_stride;
128       d29u32 = vld1_dup_u32((const uint32_t *)s);
129       s += src_stride;
130       d31u32 = vld1_dup_u32((const uint32_t *)s);
131       s += src_stride;
132       d30u32 = vld1_dup_u32((const uint32_t *)s);
133 
134       __builtin_prefetch(psrc + 64);
135 
136       d0x2u16 = vtrn_u16(vreinterpret_u16_u32(d28u32),
137                          vreinterpret_u16_u32(d31u32));
138       d1x2u16 = vtrn_u16(vreinterpret_u16_u32(d29u32),
139                          vreinterpret_u16_u32(d30u32));
140       d0x2u8 = vtrn_u8(vreinterpret_u8_u16(d0x2u16.val[0]),   // d28
141                        vreinterpret_u8_u16(d1x2u16.val[0]));  // d29
142       d1x2u8 = vtrn_u8(vreinterpret_u8_u16(d0x2u16.val[1]),   // d31
143                        vreinterpret_u8_u16(d1x2u16.val[1]));  // d30
144 
145       __builtin_prefetch(psrc + 64 + src_stride);
146 
147       q14u8 = vcombine_u8(d0x2u8.val[0], d0x2u8.val[1]);
148       q15u8 = vcombine_u8(d1x2u8.val[1], d1x2u8.val[0]);
149       q0x2u32 = vtrnq_u32(vreinterpretq_u32_u8(q14u8),
150                           vreinterpretq_u32_u8(q15u8));
151 
152       d28u8 = vreinterpret_u8_u32(vget_low_u32(q0x2u32.val[0]));
153       d29u8 = vreinterpret_u8_u32(vget_high_u32(q0x2u32.val[0]));
154       q12u16 = vmovl_u8(d28u8);
155       q13u16 = vmovl_u8(d29u8);
156 
157       __builtin_prefetch(psrc + 64 + src_stride * 2);
158 
159       d16s16 = vreinterpret_s16_u16(vget_low_u16(q8u16));
160       d17s16 = vreinterpret_s16_u16(vget_high_u16(q8u16));
161       d18s16 = vreinterpret_s16_u16(vget_low_u16(q9u16));
162       d19s16 = vreinterpret_s16_u16(vget_high_u16(q9u16));
163       d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16));
164       d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16));
165       d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16));
166       d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16));
167       d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16));
168 
169       q1s32  = MULTIPLY_BY_Q0(d16s16, d17s16, d20s16, d22s16,
170                               d18s16, d19s16, d23s16, d24s16, q0s16);
171       q2s32  = MULTIPLY_BY_Q0(d17s16, d20s16, d22s16, d18s16,
172                               d19s16, d23s16, d24s16, d26s16, q0s16);
173       q14s32 = MULTIPLY_BY_Q0(d20s16, d22s16, d18s16, d19s16,
174                               d23s16, d24s16, d26s16, d27s16, q0s16);
175       q15s32 = MULTIPLY_BY_Q0(d22s16, d18s16, d19s16, d23s16,
176                               d24s16, d26s16, d27s16, d25s16, q0s16);
177 
178       __builtin_prefetch(psrc + 60 + src_stride * 3);
179 
180       d2u16 = vqrshrun_n_s32(q1s32, 7);
181       d3u16 = vqrshrun_n_s32(q2s32, 7);
182       d4u16 = vqrshrun_n_s32(q14s32, 7);
183       d5u16 = vqrshrun_n_s32(q15s32, 7);
184 
185       q1u16 = vcombine_u16(d2u16, d3u16);
186       q2u16 = vcombine_u16(d4u16, d5u16);
187 
188       d2u8 = vqmovn_u16(q1u16);
189       d3u8 = vqmovn_u16(q2u16);
190 
191       d0x2u16 = vtrn_u16(vreinterpret_u16_u8(d2u8),
192                          vreinterpret_u16_u8(d3u8));
193       d0x2u32 = vtrn_u32(vreinterpret_u32_u16(d0x2u16.val[0]),
194                          vreinterpret_u32_u16(d0x2u16.val[1]));
195       d0x2u8 = vtrn_u8(vreinterpret_u8_u32(d0x2u32.val[0]),
196                        vreinterpret_u8_u32(d0x2u32.val[1]));
197 
198       d2u32 = vreinterpret_u32_u8(d0x2u8.val[0]);
199       d3u32 = vreinterpret_u32_u8(d0x2u8.val[1]);
200 
201       d = pdst;
202       vst1_lane_u32((uint32_t *)d, d2u32, 0);
203       d += dst_stride;
204       vst1_lane_u32((uint32_t *)d, d3u32, 0);
205       d += dst_stride;
206       vst1_lane_u32((uint32_t *)d, d2u32, 1);
207       d += dst_stride;
208       vst1_lane_u32((uint32_t *)d, d3u32, 1);
209 
210       q8u16 = q9u16;
211       d20s16 = d23s16;
212       q11u16 = q12u16;
213       q9u16 = q13u16;
214       d23s16 = vreinterpret_s16_u16(vget_high_u16(q11u16));
215     }
216   }
217   return;
218 }
219 
vpx_convolve8_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)220 void vpx_convolve8_vert_neon(
221     const uint8_t *src,
222     ptrdiff_t src_stride,
223     uint8_t *dst,
224     ptrdiff_t dst_stride,
225     const int16_t *filter_x,  // unused
226     int x_step_q4,            // unused
227     const int16_t *filter_y,
228     int y_step_q4,
229     int w,
230     int h) {
231   int height;
232   const uint8_t *s;
233   uint8_t *d;
234   uint32x2_t d2u32, d3u32;
235   uint32x2_t d16u32, d18u32, d20u32, d22u32, d24u32, d26u32;
236   int16x4_t d16s16, d17s16, d18s16, d19s16, d20s16, d21s16, d22s16;
237   int16x4_t d24s16, d25s16, d26s16, d27s16;
238   uint16x4_t d2u16, d3u16, d4u16, d5u16;
239   int16x8_t q0s16;
240   uint16x8_t q1u16, q2u16, q8u16, q9u16, q10u16, q11u16, q12u16, q13u16;
241   int32x4_t q1s32, q2s32, q14s32, q15s32;
242 
243   assert(y_step_q4 == 16);
244 
245   src -= src_stride * 3;
246   q0s16 = vld1q_s16(filter_y);
247   for (; w > 0; w -= 4, src += 4, dst += 4) {  // loop_vert_h
248     s = src;
249     d16u32 = vld1_lane_u32((const uint32_t *)s, d16u32, 0);
250     s += src_stride;
251     d16u32 = vld1_lane_u32((const uint32_t *)s, d16u32, 1);
252     s += src_stride;
253     d18u32 = vld1_lane_u32((const uint32_t *)s, d18u32, 0);
254     s += src_stride;
255     d18u32 = vld1_lane_u32((const uint32_t *)s, d18u32, 1);
256     s += src_stride;
257     d20u32 = vld1_lane_u32((const uint32_t *)s, d20u32, 0);
258     s += src_stride;
259     d20u32 = vld1_lane_u32((const uint32_t *)s, d20u32, 1);
260     s += src_stride;
261     d22u32 = vld1_lane_u32((const uint32_t *)s, d22u32, 0);
262     s += src_stride;
263 
264     q8u16  = vmovl_u8(vreinterpret_u8_u32(d16u32));
265     q9u16  = vmovl_u8(vreinterpret_u8_u32(d18u32));
266     q10u16 = vmovl_u8(vreinterpret_u8_u32(d20u32));
267     q11u16 = vmovl_u8(vreinterpret_u8_u32(d22u32));
268 
269     d18s16 = vreinterpret_s16_u16(vget_low_u16(q9u16));
270     d19s16 = vreinterpret_s16_u16(vget_high_u16(q9u16));
271     d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16));
272     d = dst;
273     for (height = h; height > 0; height -= 4) {  // loop_vert
274       d24u32 = vld1_lane_u32((const uint32_t *)s, d24u32, 0);
275       s += src_stride;
276       d26u32 = vld1_lane_u32((const uint32_t *)s, d26u32, 0);
277       s += src_stride;
278       d26u32 = vld1_lane_u32((const uint32_t *)s, d26u32, 1);
279       s += src_stride;
280       d24u32 = vld1_lane_u32((const uint32_t *)s, d24u32, 1);
281       s += src_stride;
282 
283       q12u16 = vmovl_u8(vreinterpret_u8_u32(d24u32));
284       q13u16 = vmovl_u8(vreinterpret_u8_u32(d26u32));
285 
286       d16s16 = vreinterpret_s16_u16(vget_low_u16(q8u16));
287       d17s16 = vreinterpret_s16_u16(vget_high_u16(q8u16));
288       d20s16 = vreinterpret_s16_u16(vget_low_u16(q10u16));
289       d21s16 = vreinterpret_s16_u16(vget_high_u16(q10u16));
290       d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16));
291       d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16));
292       d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16));
293       d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16));
294 
295       __builtin_prefetch(d);
296       __builtin_prefetch(d + dst_stride);
297       q1s32  = MULTIPLY_BY_Q0(d16s16, d17s16, d18s16, d19s16,
298                               d20s16, d21s16, d22s16, d24s16, q0s16);
299       __builtin_prefetch(d + dst_stride * 2);
300       __builtin_prefetch(d + dst_stride * 3);
301       q2s32  = MULTIPLY_BY_Q0(d17s16, d18s16, d19s16, d20s16,
302                               d21s16, d22s16, d24s16, d26s16, q0s16);
303       __builtin_prefetch(s);
304       __builtin_prefetch(s + src_stride);
305       q14s32 = MULTIPLY_BY_Q0(d18s16, d19s16, d20s16, d21s16,
306                               d22s16, d24s16, d26s16, d27s16, q0s16);
307       __builtin_prefetch(s + src_stride * 2);
308       __builtin_prefetch(s + src_stride * 3);
309       q15s32 = MULTIPLY_BY_Q0(d19s16, d20s16, d21s16, d22s16,
310                               d24s16, d26s16, d27s16, d25s16, q0s16);
311 
312       d2u16 = vqrshrun_n_s32(q1s32, 7);
313       d3u16 = vqrshrun_n_s32(q2s32, 7);
314       d4u16 = vqrshrun_n_s32(q14s32, 7);
315       d5u16 = vqrshrun_n_s32(q15s32, 7);
316 
317       q1u16 = vcombine_u16(d2u16, d3u16);
318       q2u16 = vcombine_u16(d4u16, d5u16);
319 
320       d2u32 = vreinterpret_u32_u8(vqmovn_u16(q1u16));
321       d3u32 = vreinterpret_u32_u8(vqmovn_u16(q2u16));
322 
323       vst1_lane_u32((uint32_t *)d, d2u32, 0);
324       d += dst_stride;
325       vst1_lane_u32((uint32_t *)d, d2u32, 1);
326       d += dst_stride;
327       vst1_lane_u32((uint32_t *)d, d3u32, 0);
328       d += dst_stride;
329       vst1_lane_u32((uint32_t *)d, d3u32, 1);
330       d += dst_stride;
331 
332       q8u16 = q10u16;
333       d18s16 = d22s16;
334       d19s16 = d24s16;
335       q10u16 = q13u16;
336       d22s16 = d25s16;
337     }
338   }
339   return;
340 }
341