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