mmx: fix formats in commented code
[profile/ivi/pixman.git] / pixman / pixman-arm-neon-asm-bilinear.S
1 /*
2  * Copyright © 2011 SCore Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Author:  Siarhei Siamashka (siarhei.siamashka@nokia.com)
24  * Author:  Taekyun Kim (tkq.kim@samsung.com)
25  */
26
27 /*
28  * This file contains scaled bilinear scanline functions implemented
29  * using older siarhei's bilinear macro template.
30  *
31  * << General scanline function procedures >>
32  *  1. bilinear interpolate source pixels
33  *  2. load mask pixels
34  *  3. load destination pixels
35  *  4. duplicate mask to fill whole register
36  *  5. interleave source & destination pixels
37  *  6. apply mask to source pixels
38  *  7. combine source & destination pixels
39  *  8, Deinterleave final result
40  *  9. store destination pixels
41  *
42  * All registers with single number (i.e. src0, tmp0) are 64-bits registers.
43  * Registers with double numbers(src01, dst01) are 128-bits registers.
44  * All temp registers can be used freely outside the code block.
45  * Assume that symbol(register .req) OUT and MASK are defined at caller of these macro blocks.
46  *
47  * TODOs
48  *  Support 0565 pixel format
49  *  Optimization for two and last pixel cases
50  *
51  * Remarks
52  *  There can be lots of pipeline stalls inside code block and between code blocks.
53  *  Further optimizations will be done by new macro templates using head/tail_head/tail scheme.
54  */
55
56 /* Prevent the stack from becoming executable for no reason... */
57 #if defined(__linux__) && defined (__ELF__)
58 .section .note.GNU-stack,"",%progbits
59 #endif
60
61 .text
62 .fpu neon
63 .arch armv7a
64 .object_arch armv4
65 .eabi_attribute 10, 0
66 .eabi_attribute 12, 0
67 .arm
68 .altmacro
69 .p2align 2
70
71 #include "pixman-arm-neon-asm.h"
72
73 /*
74  * Bilinear macros from pixman-arm-neon-asm.S
75  */
76
77 /* Supplementary macro for setting function attributes */
78 .macro pixman_asm_function fname
79     .func fname
80     .global fname
81 #ifdef __ELF__
82     .hidden fname
83     .type fname, %function
84 #endif
85 fname:
86 .endm
87
88 /*
89  * Bilinear scaling support code which tries to provide pixel fetching, color
90  * format conversion, and interpolation as separate macros which can be used
91  * as the basic building blocks for constructing bilinear scanline functions.
92  */
93
94 .macro bilinear_load_8888 reg1, reg2, tmp
95     mov       TMP2, X, asr #16
96     add       X, X, UX
97     add       TMP1, TOP, TMP2, asl #2
98     add       TMP2, BOTTOM, TMP2, asl #2
99     vld1.32   {reg1}, [TMP1]
100     vld1.32   {reg2}, [TMP2]
101 .endm
102
103 .macro bilinear_load_0565 reg1, reg2, tmp
104     mov       TMP2, X, asr #16
105     add       X, X, UX
106     add       TMP1, TOP, TMP2, asl #1
107     add       TMP2, BOTTOM, TMP2, asl #1
108     vld1.32   {reg2[0]}, [TMP1]
109     vld1.32   {reg2[1]}, [TMP2]
110     convert_four_0565_to_x888_packed reg2, reg1, reg2, tmp
111 .endm
112
113 .macro bilinear_load_and_vertical_interpolate_two_8888 \
114                     acc1, acc2, reg1, reg2, reg3, reg4, tmp1, tmp2
115
116     bilinear_load_8888 reg1, reg2, tmp1
117     vmull.u8  acc1, reg1, d28
118     vmlal.u8  acc1, reg2, d29
119     bilinear_load_8888 reg3, reg4, tmp2
120     vmull.u8  acc2, reg3, d28
121     vmlal.u8  acc2, reg4, d29
122 .endm
123
124 .macro bilinear_load_and_vertical_interpolate_four_8888 \
125                 xacc1, xacc2, xreg1, xreg2, xreg3, xreg4, xacc2lo, xacc2hi \
126                 yacc1, yacc2, yreg1, yreg2, yreg3, yreg4, yacc2lo, yacc2hi
127
128     bilinear_load_and_vertical_interpolate_two_8888 \
129                 xacc1, xacc2, xreg1, xreg2, xreg3, xreg4, xacc2lo, xacc2hi
130     bilinear_load_and_vertical_interpolate_two_8888 \
131                 yacc1, yacc2, yreg1, yreg2, yreg3, yreg4, yacc2lo, yacc2hi
132 .endm
133
134 .macro bilinear_load_and_vertical_interpolate_two_0565 \
135                 acc1, acc2, reg1, reg2, reg3, reg4, acc2lo, acc2hi
136
137     mov       TMP2, X, asr #16
138     add       X, X, UX
139     mov       TMP4, X, asr #16
140     add       X, X, UX
141     add       TMP1, TOP, TMP2, asl #1
142     add       TMP2, BOTTOM, TMP2, asl #1
143     add       TMP3, TOP, TMP4, asl #1
144     add       TMP4, BOTTOM, TMP4, asl #1
145     vld1.32   {acc2lo[0]}, [TMP1]
146     vld1.32   {acc2hi[0]}, [TMP3]
147     vld1.32   {acc2lo[1]}, [TMP2]
148     vld1.32   {acc2hi[1]}, [TMP4]
149     convert_0565_to_x888 acc2, reg3, reg2, reg1
150     vzip.u8   reg1, reg3
151     vzip.u8   reg2, reg4
152     vzip.u8   reg3, reg4
153     vzip.u8   reg1, reg2
154     vmull.u8  acc1, reg1, d28
155     vmlal.u8  acc1, reg2, d29
156     vmull.u8  acc2, reg3, d28
157     vmlal.u8  acc2, reg4, d29
158 .endm
159
160 .macro bilinear_load_and_vertical_interpolate_four_0565 \
161                 xacc1, xacc2, xreg1, xreg2, xreg3, xreg4, xacc2lo, xacc2hi \
162                 yacc1, yacc2, yreg1, yreg2, yreg3, yreg4, yacc2lo, yacc2hi
163
164     mov       TMP2, X, asr #16
165     add       X, X, UX
166     mov       TMP4, X, asr #16
167     add       X, X, UX
168     add       TMP1, TOP, TMP2, asl #1
169     add       TMP2, BOTTOM, TMP2, asl #1
170     add       TMP3, TOP, TMP4, asl #1
171     add       TMP4, BOTTOM, TMP4, asl #1
172     vld1.32   {xacc2lo[0]}, [TMP1]
173     vld1.32   {xacc2hi[0]}, [TMP3]
174     vld1.32   {xacc2lo[1]}, [TMP2]
175     vld1.32   {xacc2hi[1]}, [TMP4]
176     convert_0565_to_x888 xacc2, xreg3, xreg2, xreg1
177     mov       TMP2, X, asr #16
178     add       X, X, UX
179     mov       TMP4, X, asr #16
180     add       X, X, UX
181     add       TMP1, TOP, TMP2, asl #1
182     add       TMP2, BOTTOM, TMP2, asl #1
183     add       TMP3, TOP, TMP4, asl #1
184     add       TMP4, BOTTOM, TMP4, asl #1
185     vld1.32   {yacc2lo[0]}, [TMP1]
186     vzip.u8   xreg1, xreg3
187     vld1.32   {yacc2hi[0]}, [TMP3]
188     vzip.u8   xreg2, xreg4
189     vld1.32   {yacc2lo[1]}, [TMP2]
190     vzip.u8   xreg3, xreg4
191     vld1.32   {yacc2hi[1]}, [TMP4]
192     vzip.u8   xreg1, xreg2
193     convert_0565_to_x888 yacc2, yreg3, yreg2, yreg1
194     vmull.u8  xacc1, xreg1, d28
195     vzip.u8   yreg1, yreg3
196     vmlal.u8  xacc1, xreg2, d29
197     vzip.u8   yreg2, yreg4
198     vmull.u8  xacc2, xreg3, d28
199     vzip.u8   yreg3, yreg4
200     vmlal.u8  xacc2, xreg4, d29
201     vzip.u8   yreg1, yreg2
202     vmull.u8  yacc1, yreg1, d28
203     vmlal.u8  yacc1, yreg2, d29
204     vmull.u8  yacc2, yreg3, d28
205     vmlal.u8  yacc2, yreg4, d29
206 .endm
207
208 .macro bilinear_store_8888 numpix, tmp1, tmp2
209 .if numpix == 4
210     vst1.32   {d0, d1}, [OUT]!
211 .elseif numpix == 2
212     vst1.32   {d0}, [OUT]!
213 .elseif numpix == 1
214     vst1.32   {d0[0]}, [OUT, :32]!
215 .else
216     .error bilinear_store_8888 numpix is unsupported
217 .endif
218 .endm
219
220 .macro bilinear_store_0565 numpix, tmp1, tmp2
221     vuzp.u8 d0, d1
222     vuzp.u8 d2, d3
223     vuzp.u8 d1, d3
224     vuzp.u8 d0, d2
225     convert_8888_to_0565 d2, d1, d0, q1, tmp1, tmp2
226 .if numpix == 4
227     vst1.16   {d2}, [OUT]!
228 .elseif numpix == 2
229     vst1.32   {d2[0]}, [OUT]!
230 .elseif numpix == 1
231     vst1.16   {d2[0]}, [OUT]!
232 .else
233     .error bilinear_store_0565 numpix is unsupported
234 .endif
235 .endm
236
237
238 /*
239  * Macros for loading mask pixels into register 'mask'.
240  * vdup must be done in somewhere else.
241  */
242 .macro bilinear_load_mask_x numpix, mask
243 .endm
244
245 .macro bilinear_load_mask_8 numpix, mask
246 .if numpix == 4
247     vld1.32     {mask[0]}, [MASK]!
248 .elseif numpix == 2
249     vld1.16     {mask[0]}, [MASK]!
250 .elseif numpix == 1
251     vld1.8      {mask[0]}, [MASK]!
252 .else
253     .error bilinear_load_mask_8 numpix is unsupported
254 .endif
255 .endm
256
257 .macro bilinear_load_mask mask_fmt, numpix, mask
258     bilinear_load_mask_&mask_fmt numpix, mask
259 .endm
260
261
262 /*
263  * Macros for loading destination pixels into register 'dst0' and 'dst1'.
264  * Interleave should be done somewhere else.
265  */
266 .macro bilinear_load_dst_0565_src numpix, dst0, dst1, dst01
267 .endm
268
269 .macro bilinear_load_dst_8888_src numpix, dst0, dst1, dst01
270 .endm
271
272 .macro bilinear_load_dst_8888 numpix, dst0, dst1, dst01
273 .if numpix == 4
274     vld1.32     {dst0, dst1}, [OUT]
275 .elseif numpix == 2
276     vld1.32     {dst0}, [OUT]
277 .elseif numpix == 1
278     vld1.32     {dst0[0]}, [OUT]
279 .else
280     .error bilinear_load_dst_8888 numpix is unsupported
281 .endif
282 .endm
283
284 .macro bilinear_load_dst_8888_over numpix, dst0, dst1, dst01
285     bilinear_load_dst_8888 numpix, dst0, dst1, dst01
286 .endm
287
288 .macro bilinear_load_dst_8888_add numpix, dst0, dst1, dst01
289     bilinear_load_dst_8888 numpix, dst0, dst1, dst01
290 .endm
291
292 .macro bilinear_load_dst dst_fmt, op, numpix, dst0, dst1, dst01
293     bilinear_load_dst_&dst_fmt&_&op numpix, dst0, dst1, dst01
294 .endm
295
296 /*
297  * Macros for duplicating partially loaded mask to fill entire register.
298  * We will apply mask to interleaved source pixels, that is
299  *  (r0, r1, r2, r3, g0, g1, g2, g3) x (m0, m1, m2, m3, m0, m1, m2, m3)
300  *  (b0, b1, b2, b3, a0, a1, a2, a3) x (m0, m1, m2, m3, m0, m1, m2, m3)
301  * So, we need to duplicate loaded mask into whole register.
302  *
303  * For two pixel case
304  *  (r0, r1, x, x, g0, g1, x, x) x (m0, m1, m0, m1, m0, m1, m0, m1)
305  *  (b0, b1, x, x, a0, a1, x, x) x (m0, m1, m0, m1, m0, m1, m0, m1)
306  * We can do some optimizations for this including one pixel cases.
307  */
308 .macro bilinear_duplicate_mask_x numpix, mask
309 .endm
310
311 .macro bilinear_duplicate_mask_8 numpix, mask
312 .if numpix == 4
313     vdup.32     mask, mask[0]
314 .elseif numpix == 2
315     vdup.16     mask, mask[0]
316 .elseif numpix == 1
317     vdup.8      mask, mask[0]
318 .else
319     .error bilinear_duplicate_mask_8 is unsupported
320 .endif
321 .endm
322
323 .macro bilinear_duplicate_mask mask_fmt, numpix, mask
324     bilinear_duplicate_mask_&mask_fmt numpix, mask
325 .endm
326
327 /*
328  * Macros for interleaving src and dst pixels to rrrr gggg bbbb aaaa form.
329  * Interleave should be done when maks is enabled or operator is 'over'.
330  */
331 .macro bilinear_interleave src0, src1, dst0, dst1
332     vuzp.8      src0, src1
333     vuzp.8      dst0, dst1
334     vuzp.8      src0, src1
335     vuzp.8      dst0, dst1
336 .endm
337
338 .macro bilinear_interleave_src_dst_x_src \
339                 numpix, src0, src1, src01, dst0, dst1, dst01
340 .endm
341
342 .macro bilinear_interleave_src_dst_x_over \
343                 numpix, src0, src1, src01, dst0, dst1, dst01
344
345     bilinear_interleave src0, src1, dst0, dst1
346 .endm
347
348 .macro bilinear_interleave_src_dst_x_add \
349                 numpix, src0, src1, src01, dst0, dst1, dst01
350 .endm
351
352 .macro bilinear_interleave_src_dst_8_src \
353                 numpix, src0, src1, src01, dst0, dst1, dst01
354
355     bilinear_interleave src0, src1, dst0, dst1
356 .endm
357
358 .macro bilinear_interleave_src_dst_8_over \
359                 numpix, src0, src1, src01, dst0, dst1, dst01
360
361     bilinear_interleave src0, src1, dst0, dst1
362 .endm
363
364 .macro bilinear_interleave_src_dst_8_add \
365                 numpix, src0, src1, src01, dst0, dst1, dst01
366
367     bilinear_interleave src0, src1, dst0, dst1
368 .endm
369
370 .macro bilinear_interleave_src_dst \
371                 mask_fmt, op, numpix, src0, src1, src01, dst0, dst1, dst01
372
373     bilinear_interleave_src_dst_&mask_fmt&_&op \
374                 numpix, src0, src1, src01, dst0, dst1, dst01
375 .endm
376
377
378 /*
379  * Macros for applying masks to src pixels. (see combine_mask_u() function)
380  * src, dst should be in interleaved form.
381  * mask register should be in form (m0, m1, m2, m3).
382  */
383 .macro bilinear_apply_mask_to_src_x \
384                 numpix, src0, src1, src01, mask, \
385                 tmp01, tmp23, tmp45, tmp67
386 .endm
387
388 .macro bilinear_apply_mask_to_src_8 \
389                 numpix, src0, src1, src01, mask, \
390                 tmp01, tmp23, tmp45, tmp67
391
392     vmull.u8        tmp01, src0, mask
393     vmull.u8        tmp23, src1, mask
394     /* bubbles */
395     vrshr.u16       tmp45, tmp01, #8
396     vrshr.u16       tmp67, tmp23, #8
397     /* bubbles */
398     vraddhn.u16     src0, tmp45, tmp01
399     vraddhn.u16     src1, tmp67, tmp23
400 .endm
401
402 .macro bilinear_apply_mask_to_src \
403                 mask_fmt, numpix, src0, src1, src01, mask, \
404                 tmp01, tmp23, tmp45, tmp67
405
406     bilinear_apply_mask_to_src_&mask_fmt \
407                 numpix, src0, src1, src01, mask, \
408                 tmp01, tmp23, tmp45, tmp67
409 .endm
410
411
412 /*
413  * Macros for combining src and destination pixels.
414  * Interleave or not is depending on operator 'op'.
415  */
416 .macro bilinear_combine_src \
417                 numpix, src0, src1, src01, dst0, dst1, dst01, \
418                 tmp01, tmp23, tmp45, tmp67, tmp8
419 .endm
420
421 .macro bilinear_combine_over \
422                 numpix, src0, src1, src01, dst0, dst1, dst01, \
423                 tmp01, tmp23, tmp45, tmp67, tmp8
424
425     vdup.32     tmp8, src1[1]
426     /* bubbles */
427     vmvn.8      tmp8, tmp8
428     /* bubbles */
429     vmull.u8    tmp01, dst0, tmp8
430     /* bubbles */
431     vmull.u8    tmp23, dst1, tmp8
432     /* bubbles */
433     vrshr.u16   tmp45, tmp01, #8
434     vrshr.u16   tmp67, tmp23, #8
435     /* bubbles */
436     vraddhn.u16 dst0, tmp45, tmp01
437     vraddhn.u16 dst1, tmp67, tmp23
438     /* bubbles */
439     vqadd.u8    src01, dst01, src01
440 .endm
441
442 .macro bilinear_combine_add \
443                 numpix, src0, src1, src01, dst0, dst1, dst01, \
444                 tmp01, tmp23, tmp45, tmp67, tmp8
445
446     vqadd.u8    src01, dst01, src01
447 .endm
448
449 .macro bilinear_combine \
450                 op, numpix, src0, src1, src01, dst0, dst1, dst01, \
451                 tmp01, tmp23, tmp45, tmp67, tmp8
452
453     bilinear_combine_&op \
454                 numpix, src0, src1, src01, dst0, dst1, dst01, \
455                 tmp01, tmp23, tmp45, tmp67, tmp8
456 .endm
457
458 /*
459  * Macros for final deinterleaving of destination pixels if needed.
460  */
461 .macro bilinear_deinterleave numpix, dst0, dst1, dst01
462     vuzp.8      dst0, dst1
463     /* bubbles */
464     vuzp.8      dst0, dst1
465 .endm
466
467 .macro bilinear_deinterleave_dst_x_src numpix, dst0, dst1, dst01
468 .endm
469
470 .macro bilinear_deinterleave_dst_x_over numpix, dst0, dst1, dst01
471     bilinear_deinterleave numpix, dst0, dst1, dst01
472 .endm
473
474 .macro bilinear_deinterleave_dst_x_add numpix, dst0, dst1, dst01
475 .endm
476
477 .macro bilinear_deinterleave_dst_8_src numpix, dst0, dst1, dst01
478     bilinear_deinterleave numpix, dst0, dst1, dst01
479 .endm
480
481 .macro bilinear_deinterleave_dst_8_over numpix, dst0, dst1, dst01
482     bilinear_deinterleave numpix, dst0, dst1, dst01
483 .endm
484
485 .macro bilinear_deinterleave_dst_8_add numpix, dst0, dst1, dst01
486     bilinear_deinterleave numpix, dst0, dst1, dst01
487 .endm
488
489 .macro bilinear_deinterleave_dst mask_fmt, op, numpix, dst0, dst1, dst01
490     bilinear_deinterleave_dst_&mask_fmt&_&op numpix, dst0, dst1, dst01
491 .endm
492
493
494 .macro bilinear_interpolate_last_pixel src_fmt, mask_fmt, dst_fmt, op
495     bilinear_load_&src_fmt d0, d1, d2
496     bilinear_load_mask mask_fmt, 1, d4
497     bilinear_load_dst dst_fmt, op, 1, d18, d19, q9
498     vmull.u8  q1, d0, d28
499     vmlal.u8  q1, d1, d29
500     vshr.u16  d30, d24, #8
501     /* 4 cycles bubble */
502     vshll.u16 q0, d2, #8
503     vmlsl.u16 q0, d2, d30
504     vmlal.u16 q0, d3, d30
505     /* 5 cycles bubble */
506     bilinear_duplicate_mask mask_fmt, 1, d4
507     vshrn.u32 d0, q0, #16
508     /* 3 cycles bubble */
509     vmovn.u16 d0, q0
510     /* 1 cycle bubble */
511     bilinear_interleave_src_dst \
512                 mask_fmt, op, 1, d0, d1, q0, d18, d19, q9
513     bilinear_apply_mask_to_src \
514                 mask_fmt, 1, d0, d1, q0, d4, \
515                 q3, q8, q10, q11
516     bilinear_combine \
517                 op, 1, d0, d1, q0, d18, d19, q9, \
518                 q3, q8, q10, q11, d5
519     bilinear_deinterleave_dst mask_fmt, op, 1, d0, d1, q0
520     bilinear_store_&dst_fmt 1, q2, q3
521 .endm
522
523 .macro bilinear_interpolate_two_pixels src_fmt, mask_fmt, dst_fmt, op
524     bilinear_load_and_vertical_interpolate_two_&src_fmt \
525                 q1, q11, d0, d1, d20, d21, d22, d23
526     bilinear_load_mask mask_fmt, 2, d4
527     bilinear_load_dst dst_fmt, op, 2, d18, d19, q9
528     vshr.u16  q15, q12, #8
529     vadd.u16  q12, q12, q13
530     vshll.u16 q0, d2, #8
531     vmlsl.u16 q0, d2, d30
532     vmlal.u16 q0, d3, d30
533     vshll.u16 q10, d22, #8
534     vmlsl.u16 q10, d22, d31
535     vmlal.u16 q10, d23, d31
536     vshrn.u32 d30, q0, #16
537     vshrn.u32 d31, q10, #16
538     bilinear_duplicate_mask mask_fmt, 2, d4
539     vmovn.u16 d0, q15
540     bilinear_interleave_src_dst \
541                 mask_fmt, op, 2, d0, d1, q0, d18, d19, q9
542     bilinear_apply_mask_to_src \
543                 mask_fmt, 2, d0, d1, q0, d4, \
544                 q3, q8, q10, q11
545     bilinear_combine \
546                 op, 2, d0, d1, q0, d18, d19, q9, \
547                 q3, q8, q10, q11, d5
548     bilinear_deinterleave_dst mask_fmt, op, 2, d0, d1, q0
549     bilinear_store_&dst_fmt 2, q2, q3
550 .endm
551
552 .macro bilinear_interpolate_four_pixels src_fmt, mask_fmt, dst_fmt, op
553     bilinear_load_and_vertical_interpolate_four_&src_fmt \
554                 q1, q11, d0, d1, d20, d21, d22, d23 \
555                 q3, q9,  d4, d5, d16, d17, d18, d19
556     pld       [TMP1, PF_OFFS]
557     vshr.u16  q15, q12, #8
558     vadd.u16  q12, q12, q13
559     vshll.u16 q0, d2, #8
560     vmlsl.u16 q0, d2, d30
561     vmlal.u16 q0, d3, d30
562     vshll.u16 q10, d22, #8
563     vmlsl.u16 q10, d22, d31
564     vmlal.u16 q10, d23, d31
565     vshr.u16  q15, q12, #8
566     vshll.u16 q2, d6, #8
567     vmlsl.u16 q2, d6, d30
568     vmlal.u16 q2, d7, d30
569     vshll.u16 q8, d18, #8
570     bilinear_load_mask mask_fmt, 4, d30
571     bilinear_load_dst dst_fmt, op, 4, d2, d3, q1
572     pld       [TMP2, PF_OFFS]
573     vmlsl.u16 q8, d18, d31
574     vmlal.u16 q8, d19, d31
575     vadd.u16  q12, q12, q13
576     vshrn.u32 d0, q0, #16
577     vshrn.u32 d1, q10, #16
578     vshrn.u32 d4, q2, #16
579     vshrn.u32 d5, q8, #16
580     bilinear_duplicate_mask mask_fmt, 4, d30
581     vmovn.u16 d0, q0
582     vmovn.u16 d1, q2
583     bilinear_interleave_src_dst \
584                 mask_fmt, op, 4, d0, d1, q0, d2, d3, q1
585     bilinear_apply_mask_to_src \
586                 mask_fmt, 4, d0, d1, q0, d30, \
587                 q3, q8, q9, q10
588     bilinear_combine \
589                 op, 4, d0, d1, q0, d2, d3, q1, \
590                 q3, q8, q9, q10, d22
591     bilinear_deinterleave_dst mask_fmt, op, 4, d0, d1, q0
592     bilinear_store_&dst_fmt 4, q2, q3
593 .endm
594
595 .macro generate_bilinear_scanline_func_src_dst \
596                 fname, src_fmt, dst_fmt, op, \
597                 bpp_shift, prefetch_distance
598
599 pixman_asm_function fname
600     OUT       .req      r0
601     TOP       .req      r1
602     BOTTOM    .req      r2
603     WT        .req      r3
604     WB        .req      r4
605     X         .req      r5
606     UX        .req      r6
607     WIDTH     .req      ip
608     TMP1      .req      r3
609     TMP2      .req      r4
610     PF_OFFS   .req      r7
611     TMP3      .req      r8
612     TMP4      .req      r9
613
614     mov       ip, sp
615     push      {r4, r5, r6, r7, r8, r9}
616     mov       PF_OFFS, #prefetch_distance
617     ldmia     ip, {WB, X, UX, WIDTH}
618     mul       PF_OFFS, PF_OFFS, UX
619
620     cmp       WIDTH, #0
621     ble       3f
622
623     vdup.u16  q12, X
624     vdup.u16  q13, UX
625     vdup.u8   d28, WT
626     vdup.u8   d29, WB
627     vadd.u16  d25, d25, d26
628     vadd.u16  q13, q13, q13
629
630     subs      WIDTH, WIDTH, #4
631     blt       1f
632     mov       PF_OFFS, PF_OFFS, asr #(16 - bpp_shift)
633 0:
634     bilinear_interpolate_four_pixels src_fmt, x, dst_fmt, op
635     subs      WIDTH, WIDTH, #4
636     bge       0b
637 1:
638     tst       WIDTH, #2
639     beq       2f
640     bilinear_interpolate_two_pixels src_fmt, x, dst_fmt, op
641 2:
642     tst       WIDTH, #1
643     beq       3f
644     bilinear_interpolate_last_pixel src_fmt, x, dst_fmt, op
645 3:
646     pop       {r4, r5, r6, r7, r8, r9}
647     bx        lr
648
649     .unreq    OUT
650     .unreq    TOP
651     .unreq    BOTTOM
652     .unreq    WT
653     .unreq    WB
654     .unreq    X
655     .unreq    UX
656     .unreq    WIDTH
657     .unreq    TMP1
658     .unreq    TMP2
659     .unreq    PF_OFFS
660     .unreq    TMP3
661     .unreq    TMP4
662 .endfunc
663
664 .endm
665
666 .macro generate_bilinear_scanline_func_src_a8_dst \
667                 fname, src_fmt, dst_fmt, op, \
668                 bpp_shift, prefetch_distance
669
670 pixman_asm_function fname
671     OUT       .req      r0
672     MASK      .req      r1
673     TOP       .req      r2
674     BOTTOM    .req      r3
675     WT        .req      r4
676     WB        .req      r5
677     X         .req      r6
678     UX        .req      r7
679     WIDTH     .req      ip
680     TMP1      .req      r4
681     TMP2      .req      r5
682     PF_OFFS   .req      r8
683     TMP3      .req      r9
684     TMP4      .req      r10
685
686     mov       ip, sp
687     push      {r4, r5, r6, r7, r8, r9, r10, ip}
688     mov       PF_OFFS, #prefetch_distance
689     ldmia     ip, {WT, WB, X, UX, WIDTH}
690     mul       PF_OFFS, PF_OFFS, UX
691
692     cmp       WIDTH, #0
693     ble       3f
694
695     vdup.u16  q12, X
696     vdup.u16  q13, UX
697     vdup.u8   d28, WT
698     vdup.u8   d29, WB
699     vadd.u16  d25, d25, d26
700     vadd.u16  q13, q13, q13
701
702     subs      WIDTH, WIDTH, #4
703     blt       1f
704     mov       PF_OFFS, PF_OFFS, asr #(16 - bpp_shift)
705 0:
706     bilinear_interpolate_four_pixels src_fmt, 8, dst_fmt, op
707     subs      WIDTH, WIDTH, #4
708     bge       0b
709 1:
710     tst       WIDTH, #2
711     beq       2f
712     bilinear_interpolate_two_pixels src_fmt, 8, dst_fmt, op
713 2:
714     tst       WIDTH, #1
715     beq       3f
716     bilinear_interpolate_last_pixel src_fmt, 8, dst_fmt, op
717 3:
718     pop       {r4, r5, r6, r7, r8, r9, r10, ip}
719     bx        lr
720
721     .unreq    OUT
722     .unreq    TOP
723     .unreq    BOTTOM
724     .unreq    WT
725     .unreq    WB
726     .unreq    X
727     .unreq    UX
728     .unreq    WIDTH
729     .unreq    MASK
730     .unreq    TMP1
731     .unreq    TMP2
732     .unreq    PF_OFFS
733     .unreq    TMP3
734     .unreq    TMP4
735 .endfunc
736
737 .endm
738
739 generate_bilinear_scanline_func_src_dst \
740     pixman_scaled_bilinear_scanline_8888_8888_OVER_asm_neon, \
741     8888, 8888, over, 2, 28
742
743 generate_bilinear_scanline_func_src_dst \
744     pixman_scaled_bilinear_scanline_8888_8888_ADD_asm_neon, \
745     8888, 8888, add, 2, 28
746
747 generate_bilinear_scanline_func_src_a8_dst \
748     pixman_scaled_bilinear_scanline_8888_8_8888_SRC_asm_neon, \
749     8888, 8888, src, 2, 28
750
751 generate_bilinear_scanline_func_src_a8_dst \
752     pixman_scaled_bilinear_scanline_8888_8_0565_SRC_asm_neon, \
753     8888, 0565, src, 2, 28
754
755 generate_bilinear_scanline_func_src_a8_dst \
756     pixman_scaled_bilinear_scanline_0565_8_x888_SRC_asm_neon, \
757     0565, 8888, src, 1, 28
758
759 generate_bilinear_scanline_func_src_a8_dst \
760     pixman_scaled_bilinear_scanline_0565_8_0565_SRC_asm_neon, \
761     0565, 0565, src, 1, 28
762
763 generate_bilinear_scanline_func_src_a8_dst \
764     pixman_scaled_bilinear_scanline_8888_8_8888_OVER_asm_neon, \
765     8888, 8888, over, 2, 28
766
767 generate_bilinear_scanline_func_src_a8_dst \
768     pixman_scaled_bilinear_scanline_8888_8_8888_ADD_asm_neon, \
769     8888, 8888, add, 2, 28