vpx_convolve8_neon.c revision 7ce0a1d1337c01056ba24006efab21f00e179e04
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
19static 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
46void 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
220void 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