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