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 <string.h>
13#include "./vpx_config.h"
14#include "vpx_dsp/arm/mem_neon.h"
15
16static const uint8_t bifilter4_coeff[8][2] = { { 128, 0 }, { 112, 16 },
17                                               { 96, 32 }, { 80, 48 },
18                                               { 64, 64 }, { 48, 80 },
19                                               { 32, 96 }, { 16, 112 } };
20
21static INLINE uint8x8_t load_and_shift(const unsigned char *a) {
22  return vreinterpret_u8_u64(vshl_n_u64(vreinterpret_u64_u8(vld1_u8(a)), 32));
23}
24
25void vp8_bilinear_predict4x4_neon(unsigned char *src_ptr,
26                                  int src_pixels_per_line, int xoffset,
27                                  int yoffset, unsigned char *dst_ptr,
28                                  int dst_pitch) {
29  uint8x8_t e0, e1, e2;
30
31  if (xoffset == 0) {  // skip_1stpass_filter
32    uint8x8_t a0, a1, a2, a3, a4;
33
34    a0 = load_and_shift(src_ptr);
35    src_ptr += src_pixels_per_line;
36    a1 = vld1_u8(src_ptr);
37    src_ptr += src_pixels_per_line;
38    a2 = load_and_shift(src_ptr);
39    src_ptr += src_pixels_per_line;
40    a3 = vld1_u8(src_ptr);
41    src_ptr += src_pixels_per_line;
42    a4 = vld1_u8(src_ptr);
43
44    e0 = vext_u8(a0, a1, 4);
45    e1 = vext_u8(a2, a3, 4);
46    e2 = a4;
47  } else {
48    uint8x8_t a0, a1, a2, a3, a4, b4;
49    uint8x16_t a01, a23;
50    uint8x16_t b01, b23;
51    uint32x2x2_t c0, c1, c2, c3;
52    uint16x8_t d0, d1, d2;
53    const uint8x8_t filter0 = vdup_n_u8(bifilter4_coeff[xoffset][0]);
54    const uint8x8_t filter1 = vdup_n_u8(bifilter4_coeff[xoffset][1]);
55
56    a0 = vld1_u8(src_ptr);
57    src_ptr += src_pixels_per_line;
58    a1 = vld1_u8(src_ptr);
59    src_ptr += src_pixels_per_line;
60    a2 = vld1_u8(src_ptr);
61    src_ptr += src_pixels_per_line;
62    a3 = vld1_u8(src_ptr);
63    src_ptr += src_pixels_per_line;
64    a4 = vld1_u8(src_ptr);
65
66    a01 = vcombine_u8(a0, a1);
67    a23 = vcombine_u8(a2, a3);
68
69    b01 = vreinterpretq_u8_u64(vshrq_n_u64(vreinterpretq_u64_u8(a01), 8));
70    b23 = vreinterpretq_u8_u64(vshrq_n_u64(vreinterpretq_u64_u8(a23), 8));
71    b4 = vreinterpret_u8_u64(vshr_n_u64(vreinterpret_u64_u8(a4), 8));
72
73    c0 = vzip_u32(vreinterpret_u32_u8(vget_low_u8(a01)),
74                  vreinterpret_u32_u8(vget_high_u8(a01)));
75    c1 = vzip_u32(vreinterpret_u32_u8(vget_low_u8(a23)),
76                  vreinterpret_u32_u8(vget_high_u8(a23)));
77    c2 = vzip_u32(vreinterpret_u32_u8(vget_low_u8(b01)),
78                  vreinterpret_u32_u8(vget_high_u8(b01)));
79    c3 = vzip_u32(vreinterpret_u32_u8(vget_low_u8(b23)),
80                  vreinterpret_u32_u8(vget_high_u8(b23)));
81
82    d0 = vmull_u8(vreinterpret_u8_u32(c0.val[0]), filter0);
83    d1 = vmull_u8(vreinterpret_u8_u32(c1.val[0]), filter0);
84    d2 = vmull_u8(a4, filter0);
85
86    d0 = vmlal_u8(d0, vreinterpret_u8_u32(c2.val[0]), filter1);
87    d1 = vmlal_u8(d1, vreinterpret_u8_u32(c3.val[0]), filter1);
88    d2 = vmlal_u8(d2, b4, filter1);
89
90    e0 = vqrshrn_n_u16(d0, 7);
91    e1 = vqrshrn_n_u16(d1, 7);
92    e2 = vqrshrn_n_u16(d2, 7);
93  }
94
95  // secondpass_filter
96  if (yoffset == 0) {  // skip_2ndpass_filter
97    store_unaligned_u8q(dst_ptr, dst_pitch, vcombine_u8(e0, e1));
98  } else {
99    uint8x8_t f0, f1;
100    const uint8x8_t filter0 = vdup_n_u8(bifilter4_coeff[yoffset][0]);
101    const uint8x8_t filter1 = vdup_n_u8(bifilter4_coeff[yoffset][1]);
102
103    uint16x8_t b0 = vmull_u8(e0, filter0);
104    uint16x8_t b1 = vmull_u8(e1, filter0);
105
106    const uint8x8_t a0 = vext_u8(e0, e1, 4);
107    const uint8x8_t a1 = vext_u8(e1, e2, 4);
108
109    b0 = vmlal_u8(b0, a0, filter1);
110    b1 = vmlal_u8(b1, a1, filter1);
111
112    f0 = vqrshrn_n_u16(b0, 7);
113    f1 = vqrshrn_n_u16(b1, 7);
114
115    store_unaligned_u8q(dst_ptr, dst_pitch, vcombine_u8(f0, f1));
116  }
117}
118
119void vp8_bilinear_predict8x4_neon(unsigned char *src_ptr,
120                                  int src_pixels_per_line, int xoffset,
121                                  int yoffset, unsigned char *dst_ptr,
122                                  int dst_pitch) {
123  uint8x8_t d0u8, d1u8, d2u8, d3u8, d4u8, d5u8;
124  uint8x8_t d7u8, d9u8, d11u8, d22u8, d23u8, d24u8, d25u8, d26u8;
125  uint8x16_t q1u8, q2u8, q3u8, q4u8, q5u8;
126  uint16x8_t q1u16, q2u16, q3u16, q4u16;
127  uint16x8_t q6u16, q7u16, q8u16, q9u16, q10u16;
128
129  if (xoffset == 0) {  // skip_1stpass_filter
130    d22u8 = vld1_u8(src_ptr);
131    src_ptr += src_pixels_per_line;
132    d23u8 = vld1_u8(src_ptr);
133    src_ptr += src_pixels_per_line;
134    d24u8 = vld1_u8(src_ptr);
135    src_ptr += src_pixels_per_line;
136    d25u8 = vld1_u8(src_ptr);
137    src_ptr += src_pixels_per_line;
138    d26u8 = vld1_u8(src_ptr);
139  } else {
140    q1u8 = vld1q_u8(src_ptr);
141    src_ptr += src_pixels_per_line;
142    q2u8 = vld1q_u8(src_ptr);
143    src_ptr += src_pixels_per_line;
144    q3u8 = vld1q_u8(src_ptr);
145    src_ptr += src_pixels_per_line;
146    q4u8 = vld1q_u8(src_ptr);
147    src_ptr += src_pixels_per_line;
148    q5u8 = vld1q_u8(src_ptr);
149
150    d0u8 = vdup_n_u8(bifilter4_coeff[xoffset][0]);
151    d1u8 = vdup_n_u8(bifilter4_coeff[xoffset][1]);
152
153    q6u16 = vmull_u8(vget_low_u8(q1u8), d0u8);
154    q7u16 = vmull_u8(vget_low_u8(q2u8), d0u8);
155    q8u16 = vmull_u8(vget_low_u8(q3u8), d0u8);
156    q9u16 = vmull_u8(vget_low_u8(q4u8), d0u8);
157    q10u16 = vmull_u8(vget_low_u8(q5u8), d0u8);
158
159    d3u8 = vext_u8(vget_low_u8(q1u8), vget_high_u8(q1u8), 1);
160    d5u8 = vext_u8(vget_low_u8(q2u8), vget_high_u8(q2u8), 1);
161    d7u8 = vext_u8(vget_low_u8(q3u8), vget_high_u8(q3u8), 1);
162    d9u8 = vext_u8(vget_low_u8(q4u8), vget_high_u8(q4u8), 1);
163    d11u8 = vext_u8(vget_low_u8(q5u8), vget_high_u8(q5u8), 1);
164
165    q6u16 = vmlal_u8(q6u16, d3u8, d1u8);
166    q7u16 = vmlal_u8(q7u16, d5u8, d1u8);
167    q8u16 = vmlal_u8(q8u16, d7u8, d1u8);
168    q9u16 = vmlal_u8(q9u16, d9u8, d1u8);
169    q10u16 = vmlal_u8(q10u16, d11u8, d1u8);
170
171    d22u8 = vqrshrn_n_u16(q6u16, 7);
172    d23u8 = vqrshrn_n_u16(q7u16, 7);
173    d24u8 = vqrshrn_n_u16(q8u16, 7);
174    d25u8 = vqrshrn_n_u16(q9u16, 7);
175    d26u8 = vqrshrn_n_u16(q10u16, 7);
176  }
177
178  // secondpass_filter
179  if (yoffset == 0) {  // skip_2ndpass_filter
180    vst1_u8((uint8_t *)dst_ptr, d22u8);
181    dst_ptr += dst_pitch;
182    vst1_u8((uint8_t *)dst_ptr, d23u8);
183    dst_ptr += dst_pitch;
184    vst1_u8((uint8_t *)dst_ptr, d24u8);
185    dst_ptr += dst_pitch;
186    vst1_u8((uint8_t *)dst_ptr, d25u8);
187  } else {
188    d0u8 = vdup_n_u8(bifilter4_coeff[yoffset][0]);
189    d1u8 = vdup_n_u8(bifilter4_coeff[yoffset][1]);
190
191    q1u16 = vmull_u8(d22u8, d0u8);
192    q2u16 = vmull_u8(d23u8, d0u8);
193    q3u16 = vmull_u8(d24u8, d0u8);
194    q4u16 = vmull_u8(d25u8, d0u8);
195
196    q1u16 = vmlal_u8(q1u16, d23u8, d1u8);
197    q2u16 = vmlal_u8(q2u16, d24u8, d1u8);
198    q3u16 = vmlal_u8(q3u16, d25u8, d1u8);
199    q4u16 = vmlal_u8(q4u16, d26u8, d1u8);
200
201    d2u8 = vqrshrn_n_u16(q1u16, 7);
202    d3u8 = vqrshrn_n_u16(q2u16, 7);
203    d4u8 = vqrshrn_n_u16(q3u16, 7);
204    d5u8 = vqrshrn_n_u16(q4u16, 7);
205
206    vst1_u8((uint8_t *)dst_ptr, d2u8);
207    dst_ptr += dst_pitch;
208    vst1_u8((uint8_t *)dst_ptr, d3u8);
209    dst_ptr += dst_pitch;
210    vst1_u8((uint8_t *)dst_ptr, d4u8);
211    dst_ptr += dst_pitch;
212    vst1_u8((uint8_t *)dst_ptr, d5u8);
213  }
214  return;
215}
216
217void vp8_bilinear_predict8x8_neon(unsigned char *src_ptr,
218                                  int src_pixels_per_line, int xoffset,
219                                  int yoffset, unsigned char *dst_ptr,
220                                  int dst_pitch) {
221  uint8x8_t d0u8, d1u8, d2u8, d3u8, d4u8, d5u8, d6u8, d7u8, d8u8, d9u8, d11u8;
222  uint8x8_t d22u8, d23u8, d24u8, d25u8, d26u8, d27u8, d28u8, d29u8, d30u8;
223  uint8x16_t q1u8, q2u8, q3u8, q4u8, q5u8;
224  uint16x8_t q1u16, q2u16, q3u16, q4u16, q5u16;
225  uint16x8_t q6u16, q7u16, q8u16, q9u16, q10u16;
226
227  if (xoffset == 0) {  // skip_1stpass_filter
228    d22u8 = vld1_u8(src_ptr);
229    src_ptr += src_pixels_per_line;
230    d23u8 = vld1_u8(src_ptr);
231    src_ptr += src_pixels_per_line;
232    d24u8 = vld1_u8(src_ptr);
233    src_ptr += src_pixels_per_line;
234    d25u8 = vld1_u8(src_ptr);
235    src_ptr += src_pixels_per_line;
236    d26u8 = vld1_u8(src_ptr);
237    src_ptr += src_pixels_per_line;
238    d27u8 = vld1_u8(src_ptr);
239    src_ptr += src_pixels_per_line;
240    d28u8 = vld1_u8(src_ptr);
241    src_ptr += src_pixels_per_line;
242    d29u8 = vld1_u8(src_ptr);
243    src_ptr += src_pixels_per_line;
244    d30u8 = vld1_u8(src_ptr);
245  } else {
246    q1u8 = vld1q_u8(src_ptr);
247    src_ptr += src_pixels_per_line;
248    q2u8 = vld1q_u8(src_ptr);
249    src_ptr += src_pixels_per_line;
250    q3u8 = vld1q_u8(src_ptr);
251    src_ptr += src_pixels_per_line;
252    q4u8 = vld1q_u8(src_ptr);
253    src_ptr += src_pixels_per_line;
254
255    d0u8 = vdup_n_u8(bifilter4_coeff[xoffset][0]);
256    d1u8 = vdup_n_u8(bifilter4_coeff[xoffset][1]);
257
258    q6u16 = vmull_u8(vget_low_u8(q1u8), d0u8);
259    q7u16 = vmull_u8(vget_low_u8(q2u8), d0u8);
260    q8u16 = vmull_u8(vget_low_u8(q3u8), d0u8);
261    q9u16 = vmull_u8(vget_low_u8(q4u8), d0u8);
262
263    d3u8 = vext_u8(vget_low_u8(q1u8), vget_high_u8(q1u8), 1);
264    d5u8 = vext_u8(vget_low_u8(q2u8), vget_high_u8(q2u8), 1);
265    d7u8 = vext_u8(vget_low_u8(q3u8), vget_high_u8(q3u8), 1);
266    d9u8 = vext_u8(vget_low_u8(q4u8), vget_high_u8(q4u8), 1);
267
268    q6u16 = vmlal_u8(q6u16, d3u8, d1u8);
269    q7u16 = vmlal_u8(q7u16, d5u8, d1u8);
270    q8u16 = vmlal_u8(q8u16, d7u8, d1u8);
271    q9u16 = vmlal_u8(q9u16, d9u8, d1u8);
272
273    d22u8 = vqrshrn_n_u16(q6u16, 7);
274    d23u8 = vqrshrn_n_u16(q7u16, 7);
275    d24u8 = vqrshrn_n_u16(q8u16, 7);
276    d25u8 = vqrshrn_n_u16(q9u16, 7);
277
278    // first_pass filtering on the rest 5-line data
279    q1u8 = vld1q_u8(src_ptr);
280    src_ptr += src_pixels_per_line;
281    q2u8 = vld1q_u8(src_ptr);
282    src_ptr += src_pixels_per_line;
283    q3u8 = vld1q_u8(src_ptr);
284    src_ptr += src_pixels_per_line;
285    q4u8 = vld1q_u8(src_ptr);
286    src_ptr += src_pixels_per_line;
287    q5u8 = vld1q_u8(src_ptr);
288
289    q6u16 = vmull_u8(vget_low_u8(q1u8), d0u8);
290    q7u16 = vmull_u8(vget_low_u8(q2u8), d0u8);
291    q8u16 = vmull_u8(vget_low_u8(q3u8), d0u8);
292    q9u16 = vmull_u8(vget_low_u8(q4u8), d0u8);
293    q10u16 = vmull_u8(vget_low_u8(q5u8), d0u8);
294
295    d3u8 = vext_u8(vget_low_u8(q1u8), vget_high_u8(q1u8), 1);
296    d5u8 = vext_u8(vget_low_u8(q2u8), vget_high_u8(q2u8), 1);
297    d7u8 = vext_u8(vget_low_u8(q3u8), vget_high_u8(q3u8), 1);
298    d9u8 = vext_u8(vget_low_u8(q4u8), vget_high_u8(q4u8), 1);
299    d11u8 = vext_u8(vget_low_u8(q5u8), vget_high_u8(q5u8), 1);
300
301    q6u16 = vmlal_u8(q6u16, d3u8, d1u8);
302    q7u16 = vmlal_u8(q7u16, d5u8, d1u8);
303    q8u16 = vmlal_u8(q8u16, d7u8, d1u8);
304    q9u16 = vmlal_u8(q9u16, d9u8, d1u8);
305    q10u16 = vmlal_u8(q10u16, d11u8, d1u8);
306
307    d26u8 = vqrshrn_n_u16(q6u16, 7);
308    d27u8 = vqrshrn_n_u16(q7u16, 7);
309    d28u8 = vqrshrn_n_u16(q8u16, 7);
310    d29u8 = vqrshrn_n_u16(q9u16, 7);
311    d30u8 = vqrshrn_n_u16(q10u16, 7);
312  }
313
314  // secondpass_filter
315  if (yoffset == 0) {  // skip_2ndpass_filter
316    vst1_u8((uint8_t *)dst_ptr, d22u8);
317    dst_ptr += dst_pitch;
318    vst1_u8((uint8_t *)dst_ptr, d23u8);
319    dst_ptr += dst_pitch;
320    vst1_u8((uint8_t *)dst_ptr, d24u8);
321    dst_ptr += dst_pitch;
322    vst1_u8((uint8_t *)dst_ptr, d25u8);
323    dst_ptr += dst_pitch;
324    vst1_u8((uint8_t *)dst_ptr, d26u8);
325    dst_ptr += dst_pitch;
326    vst1_u8((uint8_t *)dst_ptr, d27u8);
327    dst_ptr += dst_pitch;
328    vst1_u8((uint8_t *)dst_ptr, d28u8);
329    dst_ptr += dst_pitch;
330    vst1_u8((uint8_t *)dst_ptr, d29u8);
331  } else {
332    d0u8 = vdup_n_u8(bifilter4_coeff[yoffset][0]);
333    d1u8 = vdup_n_u8(bifilter4_coeff[yoffset][1]);
334
335    q1u16 = vmull_u8(d22u8, d0u8);
336    q2u16 = vmull_u8(d23u8, d0u8);
337    q3u16 = vmull_u8(d24u8, d0u8);
338    q4u16 = vmull_u8(d25u8, d0u8);
339    q5u16 = vmull_u8(d26u8, d0u8);
340    q6u16 = vmull_u8(d27u8, d0u8);
341    q7u16 = vmull_u8(d28u8, d0u8);
342    q8u16 = vmull_u8(d29u8, d0u8);
343
344    q1u16 = vmlal_u8(q1u16, d23u8, d1u8);
345    q2u16 = vmlal_u8(q2u16, d24u8, d1u8);
346    q3u16 = vmlal_u8(q3u16, d25u8, d1u8);
347    q4u16 = vmlal_u8(q4u16, d26u8, d1u8);
348    q5u16 = vmlal_u8(q5u16, d27u8, d1u8);
349    q6u16 = vmlal_u8(q6u16, d28u8, d1u8);
350    q7u16 = vmlal_u8(q7u16, d29u8, d1u8);
351    q8u16 = vmlal_u8(q8u16, d30u8, d1u8);
352
353    d2u8 = vqrshrn_n_u16(q1u16, 7);
354    d3u8 = vqrshrn_n_u16(q2u16, 7);
355    d4u8 = vqrshrn_n_u16(q3u16, 7);
356    d5u8 = vqrshrn_n_u16(q4u16, 7);
357    d6u8 = vqrshrn_n_u16(q5u16, 7);
358    d7u8 = vqrshrn_n_u16(q6u16, 7);
359    d8u8 = vqrshrn_n_u16(q7u16, 7);
360    d9u8 = vqrshrn_n_u16(q8u16, 7);
361
362    vst1_u8((uint8_t *)dst_ptr, d2u8);
363    dst_ptr += dst_pitch;
364    vst1_u8((uint8_t *)dst_ptr, d3u8);
365    dst_ptr += dst_pitch;
366    vst1_u8((uint8_t *)dst_ptr, d4u8);
367    dst_ptr += dst_pitch;
368    vst1_u8((uint8_t *)dst_ptr, d5u8);
369    dst_ptr += dst_pitch;
370    vst1_u8((uint8_t *)dst_ptr, d6u8);
371    dst_ptr += dst_pitch;
372    vst1_u8((uint8_t *)dst_ptr, d7u8);
373    dst_ptr += dst_pitch;
374    vst1_u8((uint8_t *)dst_ptr, d8u8);
375    dst_ptr += dst_pitch;
376    vst1_u8((uint8_t *)dst_ptr, d9u8);
377  }
378  return;
379}
380
381void vp8_bilinear_predict16x16_neon(unsigned char *src_ptr,
382                                    int src_pixels_per_line, int xoffset,
383                                    int yoffset, unsigned char *dst_ptr,
384                                    int dst_pitch) {
385  int i;
386  unsigned char tmp[272];
387  unsigned char *tmpp;
388  uint8x8_t d0u8, d1u8, d2u8, d3u8, d4u8, d5u8, d6u8, d7u8, d8u8, d9u8;
389  uint8x8_t d10u8, d11u8, d12u8, d13u8, d14u8, d15u8, d16u8, d17u8, d18u8;
390  uint8x8_t d19u8, d20u8, d21u8;
391  uint8x16_t q1u8, q2u8, q3u8, q4u8, q5u8, q6u8, q7u8, q8u8, q9u8, q10u8;
392  uint8x16_t q11u8, q12u8, q13u8, q14u8, q15u8;
393  uint16x8_t q1u16, q2u16, q3u16, q4u16, q5u16, q6u16, q7u16, q8u16;
394  uint16x8_t q9u16, q10u16, q11u16, q12u16, q13u16, q14u16;
395
396  if (xoffset == 0) {  // secondpass_bfilter16x16_only
397    d0u8 = vdup_n_u8(bifilter4_coeff[yoffset][0]);
398    d1u8 = vdup_n_u8(bifilter4_coeff[yoffset][1]);
399
400    q11u8 = vld1q_u8(src_ptr);
401    src_ptr += src_pixels_per_line;
402    for (i = 4; i > 0; i--) {
403      q12u8 = vld1q_u8(src_ptr);
404      src_ptr += src_pixels_per_line;
405      q13u8 = vld1q_u8(src_ptr);
406      src_ptr += src_pixels_per_line;
407      q14u8 = vld1q_u8(src_ptr);
408      src_ptr += src_pixels_per_line;
409      q15u8 = vld1q_u8(src_ptr);
410      src_ptr += src_pixels_per_line;
411
412      q1u16 = vmull_u8(vget_low_u8(q11u8), d0u8);
413      q2u16 = vmull_u8(vget_high_u8(q11u8), d0u8);
414      q3u16 = vmull_u8(vget_low_u8(q12u8), d0u8);
415      q4u16 = vmull_u8(vget_high_u8(q12u8), d0u8);
416      q5u16 = vmull_u8(vget_low_u8(q13u8), d0u8);
417      q6u16 = vmull_u8(vget_high_u8(q13u8), d0u8);
418      q7u16 = vmull_u8(vget_low_u8(q14u8), d0u8);
419      q8u16 = vmull_u8(vget_high_u8(q14u8), d0u8);
420
421      q1u16 = vmlal_u8(q1u16, vget_low_u8(q12u8), d1u8);
422      q2u16 = vmlal_u8(q2u16, vget_high_u8(q12u8), d1u8);
423      q3u16 = vmlal_u8(q3u16, vget_low_u8(q13u8), d1u8);
424      q4u16 = vmlal_u8(q4u16, vget_high_u8(q13u8), d1u8);
425      q5u16 = vmlal_u8(q5u16, vget_low_u8(q14u8), d1u8);
426      q6u16 = vmlal_u8(q6u16, vget_high_u8(q14u8), d1u8);
427      q7u16 = vmlal_u8(q7u16, vget_low_u8(q15u8), d1u8);
428      q8u16 = vmlal_u8(q8u16, vget_high_u8(q15u8), d1u8);
429
430      d2u8 = vqrshrn_n_u16(q1u16, 7);
431      d3u8 = vqrshrn_n_u16(q2u16, 7);
432      d4u8 = vqrshrn_n_u16(q3u16, 7);
433      d5u8 = vqrshrn_n_u16(q4u16, 7);
434      d6u8 = vqrshrn_n_u16(q5u16, 7);
435      d7u8 = vqrshrn_n_u16(q6u16, 7);
436      d8u8 = vqrshrn_n_u16(q7u16, 7);
437      d9u8 = vqrshrn_n_u16(q8u16, 7);
438
439      q1u8 = vcombine_u8(d2u8, d3u8);
440      q2u8 = vcombine_u8(d4u8, d5u8);
441      q3u8 = vcombine_u8(d6u8, d7u8);
442      q4u8 = vcombine_u8(d8u8, d9u8);
443
444      q11u8 = q15u8;
445
446      vst1q_u8((uint8_t *)dst_ptr, q1u8);
447      dst_ptr += dst_pitch;
448      vst1q_u8((uint8_t *)dst_ptr, q2u8);
449      dst_ptr += dst_pitch;
450      vst1q_u8((uint8_t *)dst_ptr, q3u8);
451      dst_ptr += dst_pitch;
452      vst1q_u8((uint8_t *)dst_ptr, q4u8);
453      dst_ptr += dst_pitch;
454    }
455    return;
456  }
457
458  if (yoffset == 0) {  // firstpass_bfilter16x16_only
459    d0u8 = vdup_n_u8(bifilter4_coeff[xoffset][0]);
460    d1u8 = vdup_n_u8(bifilter4_coeff[xoffset][1]);
461
462    for (i = 4; i > 0; i--) {
463      d2u8 = vld1_u8(src_ptr);
464      d3u8 = vld1_u8(src_ptr + 8);
465      d4u8 = vld1_u8(src_ptr + 16);
466      src_ptr += src_pixels_per_line;
467      d5u8 = vld1_u8(src_ptr);
468      d6u8 = vld1_u8(src_ptr + 8);
469      d7u8 = vld1_u8(src_ptr + 16);
470      src_ptr += src_pixels_per_line;
471      d8u8 = vld1_u8(src_ptr);
472      d9u8 = vld1_u8(src_ptr + 8);
473      d10u8 = vld1_u8(src_ptr + 16);
474      src_ptr += src_pixels_per_line;
475      d11u8 = vld1_u8(src_ptr);
476      d12u8 = vld1_u8(src_ptr + 8);
477      d13u8 = vld1_u8(src_ptr + 16);
478      src_ptr += src_pixels_per_line;
479
480      q7u16 = vmull_u8(d2u8, d0u8);
481      q8u16 = vmull_u8(d3u8, d0u8);
482      q9u16 = vmull_u8(d5u8, d0u8);
483      q10u16 = vmull_u8(d6u8, d0u8);
484      q11u16 = vmull_u8(d8u8, d0u8);
485      q12u16 = vmull_u8(d9u8, d0u8);
486      q13u16 = vmull_u8(d11u8, d0u8);
487      q14u16 = vmull_u8(d12u8, d0u8);
488
489      d2u8 = vext_u8(d2u8, d3u8, 1);
490      d5u8 = vext_u8(d5u8, d6u8, 1);
491      d8u8 = vext_u8(d8u8, d9u8, 1);
492      d11u8 = vext_u8(d11u8, d12u8, 1);
493
494      q7u16 = vmlal_u8(q7u16, d2u8, d1u8);
495      q9u16 = vmlal_u8(q9u16, d5u8, d1u8);
496      q11u16 = vmlal_u8(q11u16, d8u8, d1u8);
497      q13u16 = vmlal_u8(q13u16, d11u8, d1u8);
498
499      d3u8 = vext_u8(d3u8, d4u8, 1);
500      d6u8 = vext_u8(d6u8, d7u8, 1);
501      d9u8 = vext_u8(d9u8, d10u8, 1);
502      d12u8 = vext_u8(d12u8, d13u8, 1);
503
504      q8u16 = vmlal_u8(q8u16, d3u8, d1u8);
505      q10u16 = vmlal_u8(q10u16, d6u8, d1u8);
506      q12u16 = vmlal_u8(q12u16, d9u8, d1u8);
507      q14u16 = vmlal_u8(q14u16, d12u8, d1u8);
508
509      d14u8 = vqrshrn_n_u16(q7u16, 7);
510      d15u8 = vqrshrn_n_u16(q8u16, 7);
511      d16u8 = vqrshrn_n_u16(q9u16, 7);
512      d17u8 = vqrshrn_n_u16(q10u16, 7);
513      d18u8 = vqrshrn_n_u16(q11u16, 7);
514      d19u8 = vqrshrn_n_u16(q12u16, 7);
515      d20u8 = vqrshrn_n_u16(q13u16, 7);
516      d21u8 = vqrshrn_n_u16(q14u16, 7);
517
518      q7u8 = vcombine_u8(d14u8, d15u8);
519      q8u8 = vcombine_u8(d16u8, d17u8);
520      q9u8 = vcombine_u8(d18u8, d19u8);
521      q10u8 = vcombine_u8(d20u8, d21u8);
522
523      vst1q_u8((uint8_t *)dst_ptr, q7u8);
524      dst_ptr += dst_pitch;
525      vst1q_u8((uint8_t *)dst_ptr, q8u8);
526      dst_ptr += dst_pitch;
527      vst1q_u8((uint8_t *)dst_ptr, q9u8);
528      dst_ptr += dst_pitch;
529      vst1q_u8((uint8_t *)dst_ptr, q10u8);
530      dst_ptr += dst_pitch;
531    }
532    return;
533  }
534
535  d0u8 = vdup_n_u8(bifilter4_coeff[xoffset][0]);
536  d1u8 = vdup_n_u8(bifilter4_coeff[xoffset][1]);
537
538  d2u8 = vld1_u8(src_ptr);
539  d3u8 = vld1_u8(src_ptr + 8);
540  d4u8 = vld1_u8(src_ptr + 16);
541  src_ptr += src_pixels_per_line;
542  d5u8 = vld1_u8(src_ptr);
543  d6u8 = vld1_u8(src_ptr + 8);
544  d7u8 = vld1_u8(src_ptr + 16);
545  src_ptr += src_pixels_per_line;
546  d8u8 = vld1_u8(src_ptr);
547  d9u8 = vld1_u8(src_ptr + 8);
548  d10u8 = vld1_u8(src_ptr + 16);
549  src_ptr += src_pixels_per_line;
550  d11u8 = vld1_u8(src_ptr);
551  d12u8 = vld1_u8(src_ptr + 8);
552  d13u8 = vld1_u8(src_ptr + 16);
553  src_ptr += src_pixels_per_line;
554
555  // First Pass: output_height lines x output_width columns (17x16)
556  tmpp = tmp;
557  for (i = 3; i > 0; i--) {
558    q7u16 = vmull_u8(d2u8, d0u8);
559    q8u16 = vmull_u8(d3u8, d0u8);
560    q9u16 = vmull_u8(d5u8, d0u8);
561    q10u16 = vmull_u8(d6u8, d0u8);
562    q11u16 = vmull_u8(d8u8, d0u8);
563    q12u16 = vmull_u8(d9u8, d0u8);
564    q13u16 = vmull_u8(d11u8, d0u8);
565    q14u16 = vmull_u8(d12u8, d0u8);
566
567    d2u8 = vext_u8(d2u8, d3u8, 1);
568    d5u8 = vext_u8(d5u8, d6u8, 1);
569    d8u8 = vext_u8(d8u8, d9u8, 1);
570    d11u8 = vext_u8(d11u8, d12u8, 1);
571
572    q7u16 = vmlal_u8(q7u16, d2u8, d1u8);
573    q9u16 = vmlal_u8(q9u16, d5u8, d1u8);
574    q11u16 = vmlal_u8(q11u16, d8u8, d1u8);
575    q13u16 = vmlal_u8(q13u16, d11u8, d1u8);
576
577    d3u8 = vext_u8(d3u8, d4u8, 1);
578    d6u8 = vext_u8(d6u8, d7u8, 1);
579    d9u8 = vext_u8(d9u8, d10u8, 1);
580    d12u8 = vext_u8(d12u8, d13u8, 1);
581
582    q8u16 = vmlal_u8(q8u16, d3u8, d1u8);
583    q10u16 = vmlal_u8(q10u16, d6u8, d1u8);
584    q12u16 = vmlal_u8(q12u16, d9u8, d1u8);
585    q14u16 = vmlal_u8(q14u16, d12u8, d1u8);
586
587    d14u8 = vqrshrn_n_u16(q7u16, 7);
588    d15u8 = vqrshrn_n_u16(q8u16, 7);
589    d16u8 = vqrshrn_n_u16(q9u16, 7);
590    d17u8 = vqrshrn_n_u16(q10u16, 7);
591    d18u8 = vqrshrn_n_u16(q11u16, 7);
592    d19u8 = vqrshrn_n_u16(q12u16, 7);
593    d20u8 = vqrshrn_n_u16(q13u16, 7);
594    d21u8 = vqrshrn_n_u16(q14u16, 7);
595
596    d2u8 = vld1_u8(src_ptr);
597    d3u8 = vld1_u8(src_ptr + 8);
598    d4u8 = vld1_u8(src_ptr + 16);
599    src_ptr += src_pixels_per_line;
600    d5u8 = vld1_u8(src_ptr);
601    d6u8 = vld1_u8(src_ptr + 8);
602    d7u8 = vld1_u8(src_ptr + 16);
603    src_ptr += src_pixels_per_line;
604    d8u8 = vld1_u8(src_ptr);
605    d9u8 = vld1_u8(src_ptr + 8);
606    d10u8 = vld1_u8(src_ptr + 16);
607    src_ptr += src_pixels_per_line;
608    d11u8 = vld1_u8(src_ptr);
609    d12u8 = vld1_u8(src_ptr + 8);
610    d13u8 = vld1_u8(src_ptr + 16);
611    src_ptr += src_pixels_per_line;
612
613    q7u8 = vcombine_u8(d14u8, d15u8);
614    q8u8 = vcombine_u8(d16u8, d17u8);
615    q9u8 = vcombine_u8(d18u8, d19u8);
616    q10u8 = vcombine_u8(d20u8, d21u8);
617
618    vst1q_u8((uint8_t *)tmpp, q7u8);
619    tmpp += 16;
620    vst1q_u8((uint8_t *)tmpp, q8u8);
621    tmpp += 16;
622    vst1q_u8((uint8_t *)tmpp, q9u8);
623    tmpp += 16;
624    vst1q_u8((uint8_t *)tmpp, q10u8);
625    tmpp += 16;
626  }
627
628  // First-pass filtering for rest 5 lines
629  d14u8 = vld1_u8(src_ptr);
630  d15u8 = vld1_u8(src_ptr + 8);
631  d16u8 = vld1_u8(src_ptr + 16);
632  src_ptr += src_pixels_per_line;
633
634  q9u16 = vmull_u8(d2u8, d0u8);
635  q10u16 = vmull_u8(d3u8, d0u8);
636  q11u16 = vmull_u8(d5u8, d0u8);
637  q12u16 = vmull_u8(d6u8, d0u8);
638  q13u16 = vmull_u8(d8u8, d0u8);
639  q14u16 = vmull_u8(d9u8, d0u8);
640
641  d2u8 = vext_u8(d2u8, d3u8, 1);
642  d5u8 = vext_u8(d5u8, d6u8, 1);
643  d8u8 = vext_u8(d8u8, d9u8, 1);
644
645  q9u16 = vmlal_u8(q9u16, d2u8, d1u8);
646  q11u16 = vmlal_u8(q11u16, d5u8, d1u8);
647  q13u16 = vmlal_u8(q13u16, d8u8, d1u8);
648
649  d3u8 = vext_u8(d3u8, d4u8, 1);
650  d6u8 = vext_u8(d6u8, d7u8, 1);
651  d9u8 = vext_u8(d9u8, d10u8, 1);
652
653  q10u16 = vmlal_u8(q10u16, d3u8, d1u8);
654  q12u16 = vmlal_u8(q12u16, d6u8, d1u8);
655  q14u16 = vmlal_u8(q14u16, d9u8, d1u8);
656
657  q1u16 = vmull_u8(d11u8, d0u8);
658  q2u16 = vmull_u8(d12u8, d0u8);
659  q3u16 = vmull_u8(d14u8, d0u8);
660  q4u16 = vmull_u8(d15u8, d0u8);
661
662  d11u8 = vext_u8(d11u8, d12u8, 1);
663  d14u8 = vext_u8(d14u8, d15u8, 1);
664
665  q1u16 = vmlal_u8(q1u16, d11u8, d1u8);
666  q3u16 = vmlal_u8(q3u16, d14u8, d1u8);
667
668  d12u8 = vext_u8(d12u8, d13u8, 1);
669  d15u8 = vext_u8(d15u8, d16u8, 1);
670
671  q2u16 = vmlal_u8(q2u16, d12u8, d1u8);
672  q4u16 = vmlal_u8(q4u16, d15u8, d1u8);
673
674  d10u8 = vqrshrn_n_u16(q9u16, 7);
675  d11u8 = vqrshrn_n_u16(q10u16, 7);
676  d12u8 = vqrshrn_n_u16(q11u16, 7);
677  d13u8 = vqrshrn_n_u16(q12u16, 7);
678  d14u8 = vqrshrn_n_u16(q13u16, 7);
679  d15u8 = vqrshrn_n_u16(q14u16, 7);
680  d16u8 = vqrshrn_n_u16(q1u16, 7);
681  d17u8 = vqrshrn_n_u16(q2u16, 7);
682  d18u8 = vqrshrn_n_u16(q3u16, 7);
683  d19u8 = vqrshrn_n_u16(q4u16, 7);
684
685  q5u8 = vcombine_u8(d10u8, d11u8);
686  q6u8 = vcombine_u8(d12u8, d13u8);
687  q7u8 = vcombine_u8(d14u8, d15u8);
688  q8u8 = vcombine_u8(d16u8, d17u8);
689  q9u8 = vcombine_u8(d18u8, d19u8);
690
691  vst1q_u8((uint8_t *)tmpp, q5u8);
692  tmpp += 16;
693  vst1q_u8((uint8_t *)tmpp, q6u8);
694  tmpp += 16;
695  vst1q_u8((uint8_t *)tmpp, q7u8);
696  tmpp += 16;
697  vst1q_u8((uint8_t *)tmpp, q8u8);
698  tmpp += 16;
699  vst1q_u8((uint8_t *)tmpp, q9u8);
700
701  // secondpass_filter
702  d0u8 = vdup_n_u8(bifilter4_coeff[yoffset][0]);
703  d1u8 = vdup_n_u8(bifilter4_coeff[yoffset][1]);
704
705  tmpp = tmp;
706  q11u8 = vld1q_u8(tmpp);
707  tmpp += 16;
708  for (i = 4; i > 0; i--) {
709    q12u8 = vld1q_u8(tmpp);
710    tmpp += 16;
711    q13u8 = vld1q_u8(tmpp);
712    tmpp += 16;
713    q14u8 = vld1q_u8(tmpp);
714    tmpp += 16;
715    q15u8 = vld1q_u8(tmpp);
716    tmpp += 16;
717
718    q1u16 = vmull_u8(vget_low_u8(q11u8), d0u8);
719    q2u16 = vmull_u8(vget_high_u8(q11u8), d0u8);
720    q3u16 = vmull_u8(vget_low_u8(q12u8), d0u8);
721    q4u16 = vmull_u8(vget_high_u8(q12u8), d0u8);
722    q5u16 = vmull_u8(vget_low_u8(q13u8), d0u8);
723    q6u16 = vmull_u8(vget_high_u8(q13u8), d0u8);
724    q7u16 = vmull_u8(vget_low_u8(q14u8), d0u8);
725    q8u16 = vmull_u8(vget_high_u8(q14u8), d0u8);
726
727    q1u16 = vmlal_u8(q1u16, vget_low_u8(q12u8), d1u8);
728    q2u16 = vmlal_u8(q2u16, vget_high_u8(q12u8), d1u8);
729    q3u16 = vmlal_u8(q3u16, vget_low_u8(q13u8), d1u8);
730    q4u16 = vmlal_u8(q4u16, vget_high_u8(q13u8), d1u8);
731    q5u16 = vmlal_u8(q5u16, vget_low_u8(q14u8), d1u8);
732    q6u16 = vmlal_u8(q6u16, vget_high_u8(q14u8), d1u8);
733    q7u16 = vmlal_u8(q7u16, vget_low_u8(q15u8), d1u8);
734    q8u16 = vmlal_u8(q8u16, vget_high_u8(q15u8), d1u8);
735
736    d2u8 = vqrshrn_n_u16(q1u16, 7);
737    d3u8 = vqrshrn_n_u16(q2u16, 7);
738    d4u8 = vqrshrn_n_u16(q3u16, 7);
739    d5u8 = vqrshrn_n_u16(q4u16, 7);
740    d6u8 = vqrshrn_n_u16(q5u16, 7);
741    d7u8 = vqrshrn_n_u16(q6u16, 7);
742    d8u8 = vqrshrn_n_u16(q7u16, 7);
743    d9u8 = vqrshrn_n_u16(q8u16, 7);
744
745    q1u8 = vcombine_u8(d2u8, d3u8);
746    q2u8 = vcombine_u8(d4u8, d5u8);
747    q3u8 = vcombine_u8(d6u8, d7u8);
748    q4u8 = vcombine_u8(d8u8, d9u8);
749
750    q11u8 = q15u8;
751
752    vst1q_u8((uint8_t *)dst_ptr, q1u8);
753    dst_ptr += dst_pitch;
754    vst1q_u8((uint8_t *)dst_ptr, q2u8);
755    dst_ptr += dst_pitch;
756    vst1q_u8((uint8_t *)dst_ptr, q3u8);
757    dst_ptr += dst_pitch;
758    vst1q_u8((uint8_t *)dst_ptr, q4u8);
759    dst_ptr += dst_pitch;
760  }
761  return;
762}
763