Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / libyuv / source / row_neon.cc
1 /*
2  *  Copyright 2011 The LibYuv 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 "libyuv/row.h"
12
13 #ifdef __cplusplus
14 namespace libyuv {
15 extern "C" {
16 #endif
17
18 // This module is for GCC Neon
19 #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) && \
20     !defined(__aarch64__)
21
22 // Read 8 Y, 4 U and 4 V from 422
23 #define READYUV422                                                             \
24     MEMACCESS(0)                                                               \
25     "vld1.8     {d0}, [%0]!                    \n"                             \
26     MEMACCESS(1)                                                               \
27     "vld1.32    {d2[0]}, [%1]!                 \n"                             \
28     MEMACCESS(2)                                                               \
29     "vld1.32    {d2[1]}, [%2]!                 \n"
30
31 // Read 8 Y, 2 U and 2 V from 422
32 #define READYUV411                                                             \
33     MEMACCESS(0)                                                               \
34     "vld1.8     {d0}, [%0]!                    \n"                             \
35     MEMACCESS(1)                                                               \
36     "vld1.16    {d2[0]}, [%1]!                 \n"                             \
37     MEMACCESS(2)                                                               \
38     "vld1.16    {d2[1]}, [%2]!                 \n"                             \
39     "vmov.u8    d3, d2                         \n"                             \
40     "vzip.u8    d2, d3                         \n"
41
42 // Read 8 Y, 8 U and 8 V from 444
43 #define READYUV444                                                             \
44     MEMACCESS(0)                                                               \
45     "vld1.8     {d0}, [%0]!                    \n"                             \
46     MEMACCESS(1)                                                               \
47     "vld1.8     {d2}, [%1]!                    \n"                             \
48     MEMACCESS(2)                                                               \
49     "vld1.8     {d3}, [%2]!                    \n"                             \
50     "vpaddl.u8  q1, q1                         \n"                             \
51     "vrshrn.u16 d2, q1, #1                     \n"
52
53 // Read 8 Y, and set 4 U and 4 V to 128
54 #define READYUV400                                                             \
55     MEMACCESS(0)                                                               \
56     "vld1.8     {d0}, [%0]!                    \n"                             \
57     "vmov.u8    d2, #128                       \n"
58
59 // Read 8 Y and 4 UV from NV12
60 #define READNV12                                                               \
61     MEMACCESS(0)                                                               \
62     "vld1.8     {d0}, [%0]!                    \n"                             \
63     MEMACCESS(1)                                                               \
64     "vld1.8     {d2}, [%1]!                    \n"                             \
65     "vmov.u8    d3, d2                         \n"/* split odd/even uv apart */\
66     "vuzp.u8    d2, d3                         \n"                             \
67     "vtrn.u32   d2, d3                         \n"
68
69 // Read 8 Y and 4 VU from NV21
70 #define READNV21                                                               \
71     MEMACCESS(0)                                                               \
72     "vld1.8     {d0}, [%0]!                    \n"                             \
73     MEMACCESS(1)                                                               \
74     "vld1.8     {d2}, [%1]!                    \n"                             \
75     "vmov.u8    d3, d2                         \n"/* split odd/even uv apart */\
76     "vuzp.u8    d3, d2                         \n"                             \
77     "vtrn.u32   d2, d3                         \n"
78
79 // Read 8 YUY2
80 #define READYUY2                                                               \
81     MEMACCESS(0)                                                               \
82     "vld2.8     {d0, d2}, [%0]!                \n"                             \
83     "vmov.u8    d3, d2                         \n"                             \
84     "vuzp.u8    d2, d3                         \n"                             \
85     "vtrn.u32   d2, d3                         \n"
86
87 // Read 8 UYVY
88 #define READUYVY                                                               \
89     MEMACCESS(0)                                                               \
90     "vld2.8     {d2, d3}, [%0]!                \n"                             \
91     "vmov.u8    d0, d3                         \n"                             \
92     "vmov.u8    d3, d2                         \n"                             \
93     "vuzp.u8    d2, d3                         \n"                             \
94     "vtrn.u32   d2, d3                         \n"
95
96 #define YUV422TORGB                                                            \
97     "veor.u8    d2, d26                        \n"/*subtract 128 from u and v*/\
98     "vmull.s8   q8, d2, d24                    \n"/*  u/v B/R component      */\
99     "vmull.s8   q9, d2, d25                    \n"/*  u/v G component        */\
100     "vmov.u8    d1, #0                         \n"/*  split odd/even y apart */\
101     "vtrn.u8    d0, d1                         \n"                             \
102     "vsub.s16   q0, q0, q15                    \n"/*  offset y               */\
103     "vmul.s16   q0, q0, q14                    \n"                             \
104     "vadd.s16   d18, d19                       \n"                             \
105     "vqadd.s16  d20, d0, d16                   \n" /* B */                     \
106     "vqadd.s16  d21, d1, d16                   \n"                             \
107     "vqadd.s16  d22, d0, d17                   \n" /* R */                     \
108     "vqadd.s16  d23, d1, d17                   \n"                             \
109     "vqadd.s16  d16, d0, d18                   \n" /* G */                     \
110     "vqadd.s16  d17, d1, d18                   \n"                             \
111     "vqshrun.s16 d0, q10, #6                   \n" /* B */                     \
112     "vqshrun.s16 d1, q11, #6                   \n" /* G */                     \
113     "vqshrun.s16 d2, q8, #6                    \n" /* R */                     \
114     "vmovl.u8   q10, d0                        \n"/*  set up for reinterleave*/\
115     "vmovl.u8   q11, d1                        \n"                             \
116     "vmovl.u8   q8, d2                         \n"                             \
117     "vtrn.u8    d20, d21                       \n"                             \
118     "vtrn.u8    d22, d23                       \n"                             \
119     "vtrn.u8    d16, d17                       \n"                             \
120     "vmov.u8    d21, d16                       \n"
121
122 static vec8 kUVToRB  = { 127, 127, 127, 127, 102, 102, 102, 102,
123                          0, 0, 0, 0, 0, 0, 0, 0 };
124 static vec8 kUVToG = { -25, -25, -25, -25, -52, -52, -52, -52,
125                        0, 0, 0, 0, 0, 0, 0, 0 };
126
127 void I444ToARGBRow_NEON(const uint8* src_y,
128                         const uint8* src_u,
129                         const uint8* src_v,
130                         uint8* dst_argb,
131                         int width) {
132   asm volatile (
133     MEMACCESS(5)
134     "vld1.8     {d24}, [%5]                    \n"
135     MEMACCESS(6)
136     "vld1.8     {d25}, [%6]                    \n"
137     "vmov.u8    d26, #128                      \n"
138     "vmov.u16   q14, #74                       \n"
139     "vmov.u16   q15, #16                       \n"
140     ".p2align   2                              \n"
141   "1:                                          \n"
142     READYUV444
143     YUV422TORGB
144     "subs       %4, %4, #8                     \n"
145     "vmov.u8    d23, #255                      \n"
146     MEMACCESS(3)
147     "vst4.8     {d20, d21, d22, d23}, [%3]!    \n"
148     "bgt        1b                             \n"
149     : "+r"(src_y),     // %0
150       "+r"(src_u),     // %1
151       "+r"(src_v),     // %2
152       "+r"(dst_argb),  // %3
153       "+r"(width)      // %4
154     : "r"(&kUVToRB),   // %5
155       "r"(&kUVToG)     // %6
156     : "cc", "memory", "q0", "q1", "q2", "q3",
157       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
158   );
159 }
160
161 void I422ToARGBRow_NEON(const uint8* src_y,
162                         const uint8* src_u,
163                         const uint8* src_v,
164                         uint8* dst_argb,
165                         int width) {
166   asm volatile (
167     MEMACCESS(5)
168     "vld1.8     {d24}, [%5]                    \n"
169     MEMACCESS(6)
170     "vld1.8     {d25}, [%6]                    \n"
171     "vmov.u8    d26, #128                      \n"
172     "vmov.u16   q14, #74                       \n"
173     "vmov.u16   q15, #16                       \n"
174     ".p2align   2                              \n"
175   "1:                                          \n"
176     READYUV422
177     YUV422TORGB
178     "subs       %4, %4, #8                     \n"
179     "vmov.u8    d23, #255                      \n"
180     MEMACCESS(3)
181     "vst4.8     {d20, d21, d22, d23}, [%3]!    \n"
182     "bgt        1b                             \n"
183     : "+r"(src_y),     // %0
184       "+r"(src_u),     // %1
185       "+r"(src_v),     // %2
186       "+r"(dst_argb),  // %3
187       "+r"(width)      // %4
188     : "r"(&kUVToRB),   // %5
189       "r"(&kUVToG)     // %6
190     : "cc", "memory", "q0", "q1", "q2", "q3",
191       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
192   );
193 }
194
195 void I411ToARGBRow_NEON(const uint8* src_y,
196                         const uint8* src_u,
197                         const uint8* src_v,
198                         uint8* dst_argb,
199                         int width) {
200   asm volatile (
201     MEMACCESS(5)
202     "vld1.8     {d24}, [%5]                    \n"
203     MEMACCESS(6)
204     "vld1.8     {d25}, [%6]                    \n"
205     "vmov.u8    d26, #128                      \n"
206     "vmov.u16   q14, #74                       \n"
207     "vmov.u16   q15, #16                       \n"
208     ".p2align   2                              \n"
209   "1:                                          \n"
210     READYUV411
211     YUV422TORGB
212     "subs       %4, %4, #8                     \n"
213     "vmov.u8    d23, #255                      \n"
214     MEMACCESS(3)
215     "vst4.8     {d20, d21, d22, d23}, [%3]!    \n"
216     "bgt        1b                             \n"
217     : "+r"(src_y),     // %0
218       "+r"(src_u),     // %1
219       "+r"(src_v),     // %2
220       "+r"(dst_argb),  // %3
221       "+r"(width)      // %4
222     : "r"(&kUVToRB),   // %5
223       "r"(&kUVToG)     // %6
224     : "cc", "memory", "q0", "q1", "q2", "q3",
225       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
226   );
227 }
228
229 void I422ToBGRARow_NEON(const uint8* src_y,
230                         const uint8* src_u,
231                         const uint8* src_v,
232                         uint8* dst_bgra,
233                         int width) {
234   asm volatile (
235     MEMACCESS(5)
236     "vld1.8     {d24}, [%5]                    \n"
237     MEMACCESS(6)
238     "vld1.8     {d25}, [%6]                    \n"
239     "vmov.u8    d26, #128                      \n"
240     "vmov.u16   q14, #74                       \n"
241     "vmov.u16   q15, #16                       \n"
242     ".p2align   2                              \n"
243   "1:                                          \n"
244     READYUV422
245     YUV422TORGB
246     "subs       %4, %4, #8                     \n"
247     "vswp.u8    d20, d22                       \n"
248     "vmov.u8    d19, #255                      \n"
249     MEMACCESS(3)
250     "vst4.8     {d19, d20, d21, d22}, [%3]!    \n"
251     "bgt        1b                             \n"
252     : "+r"(src_y),     // %0
253       "+r"(src_u),     // %1
254       "+r"(src_v),     // %2
255       "+r"(dst_bgra),  // %3
256       "+r"(width)      // %4
257     : "r"(&kUVToRB),   // %5
258       "r"(&kUVToG)     // %6
259     : "cc", "memory", "q0", "q1", "q2", "q3",
260       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
261   );
262 }
263
264 void I422ToABGRRow_NEON(const uint8* src_y,
265                         const uint8* src_u,
266                         const uint8* src_v,
267                         uint8* dst_abgr,
268                         int width) {
269   asm volatile (
270     MEMACCESS(5)
271     "vld1.8     {d24}, [%5]                    \n"
272     MEMACCESS(6)
273     "vld1.8     {d25}, [%6]                    \n"
274     "vmov.u8    d26, #128                      \n"
275     "vmov.u16   q14, #74                       \n"
276     "vmov.u16   q15, #16                       \n"
277     ".p2align   2                              \n"
278   "1:                                          \n"
279     READYUV422
280     YUV422TORGB
281     "subs       %4, %4, #8                     \n"
282     "vswp.u8    d20, d22                       \n"
283     "vmov.u8    d23, #255                      \n"
284     MEMACCESS(3)
285     "vst4.8     {d20, d21, d22, d23}, [%3]!    \n"
286     "bgt        1b                             \n"
287     : "+r"(src_y),     // %0
288       "+r"(src_u),     // %1
289       "+r"(src_v),     // %2
290       "+r"(dst_abgr),  // %3
291       "+r"(width)      // %4
292     : "r"(&kUVToRB),   // %5
293       "r"(&kUVToG)     // %6
294     : "cc", "memory", "q0", "q1", "q2", "q3",
295       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
296   );
297 }
298
299 void I422ToRGBARow_NEON(const uint8* src_y,
300                         const uint8* src_u,
301                         const uint8* src_v,
302                         uint8* dst_rgba,
303                         int width) {
304   asm volatile (
305     MEMACCESS(5)
306     "vld1.8     {d24}, [%5]                    \n"
307     MEMACCESS(6)
308     "vld1.8     {d25}, [%6]                    \n"
309     "vmov.u8    d26, #128                      \n"
310     "vmov.u16   q14, #74                       \n"
311     "vmov.u16   q15, #16                       \n"
312     ".p2align   2                              \n"
313   "1:                                          \n"
314     READYUV422
315     YUV422TORGB
316     "subs       %4, %4, #8                     \n"
317     "vmov.u8    d19, #255                      \n"
318     MEMACCESS(3)
319     "vst4.8     {d19, d20, d21, d22}, [%3]!    \n"
320     "bgt        1b                             \n"
321     : "+r"(src_y),     // %0
322       "+r"(src_u),     // %1
323       "+r"(src_v),     // %2
324       "+r"(dst_rgba),  // %3
325       "+r"(width)      // %4
326     : "r"(&kUVToRB),   // %5
327       "r"(&kUVToG)     // %6
328     : "cc", "memory", "q0", "q1", "q2", "q3",
329       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
330   );
331 }
332
333 void I422ToRGB24Row_NEON(const uint8* src_y,
334                          const uint8* src_u,
335                          const uint8* src_v,
336                          uint8* dst_rgb24,
337                          int width) {
338   asm volatile (
339     MEMACCESS(5)
340     "vld1.8     {d24}, [%5]                    \n"
341     MEMACCESS(6)
342     "vld1.8     {d25}, [%6]                    \n"
343     "vmov.u8    d26, #128                      \n"
344     "vmov.u16   q14, #74                       \n"
345     "vmov.u16   q15, #16                       \n"
346     ".p2align   2                              \n"
347   "1:                                          \n"
348     READYUV422
349     YUV422TORGB
350     "subs       %4, %4, #8                     \n"
351     MEMACCESS(3)
352     "vst3.8     {d20, d21, d22}, [%3]!         \n"
353     "bgt        1b                             \n"
354     : "+r"(src_y),      // %0
355       "+r"(src_u),      // %1
356       "+r"(src_v),      // %2
357       "+r"(dst_rgb24),  // %3
358       "+r"(width)       // %4
359     : "r"(&kUVToRB),    // %5
360       "r"(&kUVToG)      // %6
361     : "cc", "memory", "q0", "q1", "q2", "q3",
362       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
363   );
364 }
365
366 void I422ToRAWRow_NEON(const uint8* src_y,
367                        const uint8* src_u,
368                        const uint8* src_v,
369                        uint8* dst_raw,
370                        int width) {
371   asm volatile (
372     MEMACCESS(5)
373     "vld1.8     {d24}, [%5]                    \n"
374     MEMACCESS(6)
375     "vld1.8     {d25}, [%6]                    \n"
376     "vmov.u8    d26, #128                      \n"
377     "vmov.u16   q14, #74                       \n"
378     "vmov.u16   q15, #16                       \n"
379     ".p2align   2                              \n"
380   "1:                                          \n"
381     READYUV422
382     YUV422TORGB
383     "subs       %4, %4, #8                     \n"
384     "vswp.u8    d20, d22                       \n"
385     MEMACCESS(3)
386     "vst3.8     {d20, d21, d22}, [%3]!         \n"
387     "bgt        1b                             \n"
388     : "+r"(src_y),    // %0
389       "+r"(src_u),    // %1
390       "+r"(src_v),    // %2
391       "+r"(dst_raw),  // %3
392       "+r"(width)     // %4
393     : "r"(&kUVToRB),  // %5
394       "r"(&kUVToG)    // %6
395     : "cc", "memory", "q0", "q1", "q2", "q3",
396       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
397   );
398 }
399
400 #define ARGBTORGB565                                                           \
401     "vshr.u8    d20, d20, #3                   \n"  /* B                    */ \
402     "vshr.u8    d21, d21, #2                   \n"  /* G                    */ \
403     "vshr.u8    d22, d22, #3                   \n"  /* R                    */ \
404     "vmovl.u8   q8, d20                        \n"  /* B                    */ \
405     "vmovl.u8   q9, d21                        \n"  /* G                    */ \
406     "vmovl.u8   q10, d22                       \n"  /* R                    */ \
407     "vshl.u16   q9, q9, #5                     \n"  /* G                    */ \
408     "vshl.u16   q10, q10, #11                  \n"  /* R                    */ \
409     "vorr       q0, q8, q9                     \n"  /* BG                   */ \
410     "vorr       q0, q0, q10                    \n"  /* BGR                  */
411
412 void I422ToRGB565Row_NEON(const uint8* src_y,
413                           const uint8* src_u,
414                           const uint8* src_v,
415                           uint8* dst_rgb565,
416                           int width) {
417   asm volatile (
418     MEMACCESS(5)
419     "vld1.8     {d24}, [%5]                    \n"
420     MEMACCESS(6)
421     "vld1.8     {d25}, [%6]                    \n"
422     "vmov.u8    d26, #128                      \n"
423     "vmov.u16   q14, #74                       \n"
424     "vmov.u16   q15, #16                       \n"
425     ".p2align   2                              \n"
426   "1:                                          \n"
427     READYUV422
428     YUV422TORGB
429     "subs       %4, %4, #8                     \n"
430     ARGBTORGB565
431     MEMACCESS(3)
432     "vst1.8     {q0}, [%3]!                    \n"  // store 8 pixels RGB565.
433     "bgt        1b                             \n"
434     : "+r"(src_y),    // %0
435       "+r"(src_u),    // %1
436       "+r"(src_v),    // %2
437       "+r"(dst_rgb565),  // %3
438       "+r"(width)     // %4
439     : "r"(&kUVToRB),  // %5
440       "r"(&kUVToG)    // %6
441     : "cc", "memory", "q0", "q1", "q2", "q3",
442       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
443   );
444 }
445
446 #define ARGBTOARGB1555                                                         \
447     "vshr.u8    q10, q10, #3                   \n"  /* B                    */ \
448     "vshr.u8    d22, d22, #3                   \n"  /* R                    */ \
449     "vshr.u8    d23, d23, #7                   \n"  /* A                    */ \
450     "vmovl.u8   q8, d20                        \n"  /* B                    */ \
451     "vmovl.u8   q9, d21                        \n"  /* G                    */ \
452     "vmovl.u8   q10, d22                       \n"  /* R                    */ \
453     "vmovl.u8   q11, d23                       \n"  /* A                    */ \
454     "vshl.u16   q9, q9, #5                     \n"  /* G                    */ \
455     "vshl.u16   q10, q10, #10                  \n"  /* R                    */ \
456     "vshl.u16   q11, q11, #15                  \n"  /* A                    */ \
457     "vorr       q0, q8, q9                     \n"  /* BG                   */ \
458     "vorr       q1, q10, q11                   \n"  /* RA                   */ \
459     "vorr       q0, q0, q1                     \n"  /* BGRA                 */
460
461 void I422ToARGB1555Row_NEON(const uint8* src_y,
462                             const uint8* src_u,
463                             const uint8* src_v,
464                             uint8* dst_argb1555,
465                             int width) {
466   asm volatile (
467     MEMACCESS(5)
468     "vld1.8     {d24}, [%5]                    \n"
469     MEMACCESS(6)
470     "vld1.8     {d25}, [%6]                    \n"
471     "vmov.u8    d26, #128                      \n"
472     "vmov.u16   q14, #74                       \n"
473     "vmov.u16   q15, #16                       \n"
474     ".p2align   2                              \n"
475   "1:                                          \n"
476     READYUV422
477     YUV422TORGB
478     "subs       %4, %4, #8                     \n"
479     "vmov.u8    d23, #255                      \n"
480     ARGBTOARGB1555
481     MEMACCESS(3)
482     "vst1.8     {q0}, [%3]!                    \n"  // store 8 pixels ARGB1555.
483     "bgt        1b                             \n"
484     : "+r"(src_y),    // %0
485       "+r"(src_u),    // %1
486       "+r"(src_v),    // %2
487       "+r"(dst_argb1555),  // %3
488       "+r"(width)     // %4
489     : "r"(&kUVToRB),  // %5
490       "r"(&kUVToG)    // %6
491     : "cc", "memory", "q0", "q1", "q2", "q3",
492       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
493   );
494 }
495
496 #define ARGBTOARGB4444                                                         \
497     "vshr.u8    d20, d20, #4                   \n"  /* B                    */ \
498     "vbic.32    d21, d21, d4                   \n"  /* G                    */ \
499     "vshr.u8    d22, d22, #4                   \n"  /* R                    */ \
500     "vbic.32    d23, d23, d4                   \n"  /* A                    */ \
501     "vorr       d0, d20, d21                   \n"  /* BG                   */ \
502     "vorr       d1, d22, d23                   \n"  /* RA                   */ \
503     "vzip.u8    d0, d1                         \n"  /* BGRA                 */
504
505 void I422ToARGB4444Row_NEON(const uint8* src_y,
506                             const uint8* src_u,
507                             const uint8* src_v,
508                             uint8* dst_argb4444,
509                             int width) {
510   asm volatile (
511     MEMACCESS(5)
512     "vld1.8     {d24}, [%5]                    \n"
513     MEMACCESS(6)
514     "vld1.8     {d25}, [%6]                    \n"
515     "vmov.u8    d26, #128                      \n"
516     "vmov.u16   q14, #74                       \n"
517     "vmov.u16   q15, #16                       \n"
518     "vmov.u8    d4, #0x0f                      \n"  // bits to clear with vbic.
519     ".p2align   2                              \n"
520   "1:                                          \n"
521     READYUV422
522     YUV422TORGB
523     "subs       %4, %4, #8                     \n"
524     "vmov.u8    d23, #255                      \n"
525     ARGBTOARGB4444
526     MEMACCESS(3)
527     "vst1.8     {q0}, [%3]!                    \n"  // store 8 pixels ARGB4444.
528     "bgt        1b                             \n"
529     : "+r"(src_y),    // %0
530       "+r"(src_u),    // %1
531       "+r"(src_v),    // %2
532       "+r"(dst_argb4444),  // %3
533       "+r"(width)     // %4
534     : "r"(&kUVToRB),  // %5
535       "r"(&kUVToG)    // %6
536     : "cc", "memory", "q0", "q1", "q2", "q3",
537       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
538   );
539 }
540
541 void YToARGBRow_NEON(const uint8* src_y,
542                      uint8* dst_argb,
543                      int width) {
544   asm volatile (
545     MEMACCESS(3)
546     "vld1.8     {d24}, [%3]                    \n"
547     MEMACCESS(4)
548     "vld1.8     {d25}, [%4]                    \n"
549     "vmov.u8    d26, #128                      \n"
550     "vmov.u16   q14, #74                       \n"
551     "vmov.u16   q15, #16                       \n"
552     ".p2align   2                              \n"
553   "1:                                          \n"
554     READYUV400
555     YUV422TORGB
556     "subs       %2, %2, #8                     \n"
557     "vmov.u8    d23, #255                      \n"
558     MEMACCESS(1)
559     "vst4.8     {d20, d21, d22, d23}, [%1]!    \n"
560     "bgt        1b                             \n"
561     : "+r"(src_y),     // %0
562       "+r"(dst_argb),  // %1
563       "+r"(width)      // %2
564     : "r"(&kUVToRB),   // %3
565       "r"(&kUVToG)     // %4
566     : "cc", "memory", "q0", "q1", "q2", "q3",
567       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
568   );
569 }
570
571 void I400ToARGBRow_NEON(const uint8* src_y,
572                         uint8* dst_argb,
573                         int width) {
574   asm volatile (
575     ".p2align   2                              \n"
576     "vmov.u8    d23, #255                      \n"
577   "1:                                          \n"
578     MEMACCESS(0)
579     "vld1.8     {d20}, [%0]!                   \n"
580     "vmov       d21, d20                       \n"
581     "vmov       d22, d20                       \n"
582     "subs       %2, %2, #8                     \n"
583     MEMACCESS(1)
584     "vst4.8     {d20, d21, d22, d23}, [%1]!    \n"
585     "bgt        1b                             \n"
586     : "+r"(src_y),     // %0
587       "+r"(dst_argb),  // %1
588       "+r"(width)      // %2
589     :
590     : "cc", "memory", "d20", "d21", "d22", "d23"
591   );
592 }
593
594 void NV12ToARGBRow_NEON(const uint8* src_y,
595                         const uint8* src_uv,
596                         uint8* dst_argb,
597                         int width) {
598   asm volatile (
599     MEMACCESS(4)
600     "vld1.8     {d24}, [%4]                    \n"
601     MEMACCESS(5)
602     "vld1.8     {d25}, [%5]                    \n"
603     "vmov.u8    d26, #128                      \n"
604     "vmov.u16   q14, #74                       \n"
605     "vmov.u16   q15, #16                       \n"
606     ".p2align   2                              \n"
607   "1:                                          \n"
608     READNV12
609     YUV422TORGB
610     "subs       %3, %3, #8                     \n"
611     "vmov.u8    d23, #255                      \n"
612     MEMACCESS(2)
613     "vst4.8     {d20, d21, d22, d23}, [%2]!    \n"
614     "bgt        1b                             \n"
615     : "+r"(src_y),     // %0
616       "+r"(src_uv),    // %1
617       "+r"(dst_argb),  // %2
618       "+r"(width)      // %3
619     : "r"(&kUVToRB),   // %4
620       "r"(&kUVToG)     // %5
621     : "cc", "memory", "q0", "q1", "q2", "q3",
622       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
623   );
624 }
625
626 void NV21ToARGBRow_NEON(const uint8* src_y,
627                         const uint8* src_uv,
628                         uint8* dst_argb,
629                         int width) {
630   asm volatile (
631     MEMACCESS(4)
632     "vld1.8     {d24}, [%4]                    \n"
633     MEMACCESS(5)
634     "vld1.8     {d25}, [%5]                    \n"
635     "vmov.u8    d26, #128                      \n"
636     "vmov.u16   q14, #74                       \n"
637     "vmov.u16   q15, #16                       \n"
638     ".p2align   2                              \n"
639   "1:                                          \n"
640     READNV21
641     YUV422TORGB
642     "subs       %3, %3, #8                     \n"
643     "vmov.u8    d23, #255                      \n"
644     MEMACCESS(2)
645     "vst4.8     {d20, d21, d22, d23}, [%2]!    \n"
646     "bgt        1b                             \n"
647     : "+r"(src_y),     // %0
648       "+r"(src_uv),    // %1
649       "+r"(dst_argb),  // %2
650       "+r"(width)      // %3
651     : "r"(&kUVToRB),   // %4
652       "r"(&kUVToG)     // %5
653     : "cc", "memory", "q0", "q1", "q2", "q3",
654       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
655   );
656 }
657
658 void NV12ToRGB565Row_NEON(const uint8* src_y,
659                           const uint8* src_uv,
660                           uint8* dst_rgb565,
661                           int width) {
662   asm volatile (
663     MEMACCESS(4)
664     "vld1.8     {d24}, [%4]                    \n"
665     MEMACCESS(5)
666     "vld1.8     {d25}, [%5]                    \n"
667     "vmov.u8    d26, #128                      \n"
668     "vmov.u16   q14, #74                       \n"
669     "vmov.u16   q15, #16                       \n"
670     ".p2align   2                              \n"
671   "1:                                          \n"
672     READNV12
673     YUV422TORGB
674     "subs       %3, %3, #8                     \n"
675     ARGBTORGB565
676     MEMACCESS(2)
677     "vst1.8     {q0}, [%2]!                    \n"  // store 8 pixels RGB565.
678     "bgt        1b                             \n"
679     : "+r"(src_y),     // %0
680       "+r"(src_uv),    // %1
681       "+r"(dst_rgb565),  // %2
682       "+r"(width)      // %3
683     : "r"(&kUVToRB),   // %4
684       "r"(&kUVToG)     // %5
685     : "cc", "memory", "q0", "q1", "q2", "q3",
686       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
687   );
688 }
689
690 void NV21ToRGB565Row_NEON(const uint8* src_y,
691                           const uint8* src_uv,
692                           uint8* dst_rgb565,
693                           int width) {
694   asm volatile (
695     MEMACCESS(4)
696     "vld1.8     {d24}, [%4]                    \n"
697     MEMACCESS(5)
698     "vld1.8     {d25}, [%5]                    \n"
699     "vmov.u8    d26, #128                      \n"
700     "vmov.u16   q14, #74                       \n"
701     "vmov.u16   q15, #16                       \n"
702     ".p2align   2                              \n"
703   "1:                                          \n"
704     READNV21
705     YUV422TORGB
706     "subs       %3, %3, #8                     \n"
707     ARGBTORGB565
708     MEMACCESS(2)
709     "vst1.8     {q0}, [%2]!                    \n"  // store 8 pixels RGB565.
710     "bgt        1b                             \n"
711     : "+r"(src_y),     // %0
712       "+r"(src_uv),    // %1
713       "+r"(dst_rgb565),  // %2
714       "+r"(width)      // %3
715     : "r"(&kUVToRB),   // %4
716       "r"(&kUVToG)     // %5
717     : "cc", "memory", "q0", "q1", "q2", "q3",
718       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
719   );
720 }
721
722 void YUY2ToARGBRow_NEON(const uint8* src_yuy2,
723                         uint8* dst_argb,
724                         int width) {
725   asm volatile (
726     MEMACCESS(3)
727     "vld1.8     {d24}, [%3]                    \n"
728     MEMACCESS(4)
729     "vld1.8     {d25}, [%4]                    \n"
730     "vmov.u8    d26, #128                      \n"
731     "vmov.u16   q14, #74                       \n"
732     "vmov.u16   q15, #16                       \n"
733     ".p2align   2                              \n"
734   "1:                                          \n"
735     READYUY2
736     YUV422TORGB
737     "subs       %2, %2, #8                     \n"
738     "vmov.u8    d23, #255                      \n"
739     MEMACCESS(1)
740     "vst4.8     {d20, d21, d22, d23}, [%1]!    \n"
741     "bgt        1b                             \n"
742     : "+r"(src_yuy2),  // %0
743       "+r"(dst_argb),  // %1
744       "+r"(width)      // %2
745     : "r"(&kUVToRB),   // %3
746       "r"(&kUVToG)     // %4
747     : "cc", "memory", "q0", "q1", "q2", "q3",
748       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
749   );
750 }
751
752 void UYVYToARGBRow_NEON(const uint8* src_uyvy,
753                         uint8* dst_argb,
754                         int width) {
755   asm volatile (
756     MEMACCESS(3)
757     "vld1.8     {d24}, [%3]                    \n"
758     MEMACCESS(4)
759     "vld1.8     {d25}, [%4]                    \n"
760     "vmov.u8    d26, #128                      \n"
761     "vmov.u16   q14, #74                       \n"
762     "vmov.u16   q15, #16                       \n"
763     ".p2align   2                              \n"
764   "1:                                          \n"
765     READUYVY
766     YUV422TORGB
767     "subs       %2, %2, #8                     \n"
768     "vmov.u8    d23, #255                      \n"
769     MEMACCESS(1)
770     "vst4.8     {d20, d21, d22, d23}, [%1]!    \n"
771     "bgt        1b                             \n"
772     : "+r"(src_uyvy),  // %0
773       "+r"(dst_argb),  // %1
774       "+r"(width)      // %2
775     : "r"(&kUVToRB),   // %3
776       "r"(&kUVToG)     // %4
777     : "cc", "memory", "q0", "q1", "q2", "q3",
778       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
779   );
780 }
781
782 // Reads 16 pairs of UV and write even values to dst_u and odd to dst_v.
783 void SplitUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
784                      int width) {
785   asm volatile (
786     ".p2align   2                              \n"
787   "1:                                          \n"
788     MEMACCESS(0)
789     "vld2.8     {q0, q1}, [%0]!                \n"  // load 16 pairs of UV
790     "subs       %3, %3, #16                    \n"  // 16 processed per loop
791     MEMACCESS(1)
792     "vst1.8     {q0}, [%1]!                    \n"  // store U
793     MEMACCESS(2)
794     "vst1.8     {q1}, [%2]!                    \n"  // store V
795     "bgt        1b                             \n"
796     : "+r"(src_uv),  // %0
797       "+r"(dst_u),   // %1
798       "+r"(dst_v),   // %2
799       "+r"(width)    // %3  // Output registers
800     :                       // Input registers
801     : "cc", "memory", "q0", "q1"  // Clobber List
802   );
803 }
804
805 // Reads 16 U's and V's and writes out 16 pairs of UV.
806 void MergeUVRow_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
807                      int width) {
808   asm volatile (
809     ".p2align   2                              \n"
810   "1:                                          \n"
811     MEMACCESS(0)
812     "vld1.8     {q0}, [%0]!                    \n"  // load U
813     MEMACCESS(1)
814     "vld1.8     {q1}, [%1]!                    \n"  // load V
815     "subs       %3, %3, #16                    \n"  // 16 processed per loop
816     MEMACCESS(2)
817     "vst2.u8    {q0, q1}, [%2]!                \n"  // store 16 pairs of UV
818     "bgt        1b                             \n"
819     :
820       "+r"(src_u),   // %0
821       "+r"(src_v),   // %1
822       "+r"(dst_uv),  // %2
823       "+r"(width)    // %3  // Output registers
824     :                       // Input registers
825     : "cc", "memory", "q0", "q1"  // Clobber List
826   );
827 }
828
829 // Copy multiple of 32.  vld4.8  allow unaligned and is fastest on a15.
830 void CopyRow_NEON(const uint8* src, uint8* dst, int count) {
831   asm volatile (
832     ".p2align   2                              \n"
833   "1:                                          \n"
834     MEMACCESS(0)
835     "vld1.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 32
836     "subs       %2, %2, #32                    \n"  // 32 processed per loop
837     MEMACCESS(1)
838     "vst1.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 32
839     "bgt        1b                             \n"
840   : "+r"(src),   // %0
841     "+r"(dst),   // %1
842     "+r"(count)  // %2  // Output registers
843   :                     // Input registers
844   : "cc", "memory", "q0", "q1"  // Clobber List
845   );
846 }
847
848 // SetRow8 writes 'count' bytes using a 32 bit value repeated.
849 void SetRow_NEON(uint8* dst, uint32 v32, int count) {
850   asm volatile (
851     "vdup.u32  q0, %2                          \n"  // duplicate 4 ints
852     "1:                                        \n"
853     "subs      %1, %1, #16                     \n"  // 16 bytes per loop
854     MEMACCESS(0)
855     "vst1.8    {q0}, [%0]!                     \n"  // store
856     "bgt       1b                              \n"
857   : "+r"(dst),   // %0
858     "+r"(count)  // %1
859   : "r"(v32)     // %2
860   : "cc", "memory", "q0"
861   );
862 }
863
864 // TODO(fbarchard): Make fully assembler
865 // SetRow32 writes 'count' words using a 32 bit value repeated.
866 void ARGBSetRows_NEON(uint8* dst, uint32 v32, int width,
867                       int dst_stride, int height) {
868   for (int y = 0; y < height; ++y) {
869     SetRow_NEON(dst, v32, width << 2);
870     dst += dst_stride;
871   }
872 }
873
874 void MirrorRow_NEON(const uint8* src, uint8* dst, int width) {
875   asm volatile (
876     // Start at end of source row.
877     "mov        r3, #-16                       \n"
878     "add        %0, %0, %2                     \n"
879     "sub        %0, #16                        \n"
880
881     ".p2align   2                              \n"
882   "1:                                          \n"
883     MEMACCESS(0)
884     "vld1.8     {q0}, [%0], r3                 \n"  // src -= 16
885     "subs       %2, #16                        \n"  // 16 pixels per loop.
886     "vrev64.8   q0, q0                         \n"
887     MEMACCESS(1)
888     "vst1.8     {d1}, [%1]!                    \n"  // dst += 16
889     MEMACCESS(1)
890     "vst1.8     {d0}, [%1]!                    \n"
891     "bgt        1b                             \n"
892   : "+r"(src),   // %0
893     "+r"(dst),   // %1
894     "+r"(width)  // %2
895   :
896   : "cc", "memory", "r3", "q0"
897   );
898 }
899
900 void MirrorUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
901                       int width) {
902   asm volatile (
903     // Start at end of source row.
904     "mov        r12, #-16                      \n"
905     "add        %0, %0, %3, lsl #1             \n"
906     "sub        %0, #16                        \n"
907
908     ".p2align   2                              \n"
909   "1:                                          \n"
910     MEMACCESS(0)
911     "vld2.8     {d0, d1}, [%0], r12            \n"  // src -= 16
912     "subs       %3, #8                         \n"  // 8 pixels per loop.
913     "vrev64.8   q0, q0                         \n"
914     MEMACCESS(1)
915     "vst1.8     {d0}, [%1]!                    \n"  // dst += 8
916     MEMACCESS(2)
917     "vst1.8     {d1}, [%2]!                    \n"
918     "bgt        1b                             \n"
919   : "+r"(src_uv),  // %0
920     "+r"(dst_u),   // %1
921     "+r"(dst_v),   // %2
922     "+r"(width)    // %3
923   :
924   : "cc", "memory", "r12", "q0"
925   );
926 }
927
928 void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) {
929   asm volatile (
930     // Start at end of source row.
931     "mov        r3, #-16                       \n"
932     "add        %0, %0, %2, lsl #2             \n"
933     "sub        %0, #16                        \n"
934
935     ".p2align   2                              \n"
936   "1:                                          \n"
937     MEMACCESS(0)
938     "vld1.8     {q0}, [%0], r3                 \n"  // src -= 16
939     "subs       %2, #4                         \n"  // 4 pixels per loop.
940     "vrev64.32  q0, q0                         \n"
941     MEMACCESS(1)
942     "vst1.8     {d1}, [%1]!                    \n"  // dst += 16
943     MEMACCESS(1)
944     "vst1.8     {d0}, [%1]!                    \n"
945     "bgt        1b                             \n"
946   : "+r"(src),   // %0
947     "+r"(dst),   // %1
948     "+r"(width)  // %2
949   :
950   : "cc", "memory", "r3", "q0"
951   );
952 }
953
954 void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix) {
955   asm volatile (
956     "vmov.u8    d4, #255                       \n"  // Alpha
957     ".p2align   2                              \n"
958   "1:                                          \n"
959     MEMACCESS(0)
960     "vld3.8     {d1, d2, d3}, [%0]!            \n"  // load 8 pixels of RGB24.
961     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
962     MEMACCESS(1)
963     "vst4.8     {d1, d2, d3, d4}, [%1]!        \n"  // store 8 pixels of ARGB.
964     "bgt        1b                             \n"
965   : "+r"(src_rgb24),  // %0
966     "+r"(dst_argb),   // %1
967     "+r"(pix)         // %2
968   :
969   : "cc", "memory", "d1", "d2", "d3", "d4"  // Clobber List
970   );
971 }
972
973 void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int pix) {
974   asm volatile (
975     "vmov.u8    d4, #255                       \n"  // Alpha
976     ".p2align   2                              \n"
977   "1:                                          \n"
978     MEMACCESS(0)
979     "vld3.8     {d1, d2, d3}, [%0]!            \n"  // load 8 pixels of RAW.
980     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
981     "vswp.u8    d1, d3                         \n"  // swap R, B
982     MEMACCESS(1)
983     "vst4.8     {d1, d2, d3, d4}, [%1]!        \n"  // store 8 pixels of ARGB.
984     "bgt        1b                             \n"
985   : "+r"(src_raw),   // %0
986     "+r"(dst_argb),  // %1
987     "+r"(pix)        // %2
988   :
989   : "cc", "memory", "d1", "d2", "d3", "d4"  // Clobber List
990   );
991 }
992
993 #define RGB565TOARGB                                                           \
994     "vshrn.u16  d6, q0, #5                     \n"  /* G xxGGGGGG           */ \
995     "vuzp.u8    d0, d1                         \n"  /* d0 xxxBBBBB RRRRRxxx */ \
996     "vshl.u8    d6, d6, #2                     \n"  /* G GGGGGG00 upper 6   */ \
997     "vshr.u8    d1, d1, #3                     \n"  /* R 000RRRRR lower 5   */ \
998     "vshl.u8    q0, q0, #3                     \n"  /* B,R BBBBB000 upper 5 */ \
999     "vshr.u8    q2, q0, #5                     \n"  /* B,R 00000BBB lower 3 */ \
1000     "vorr.u8    d0, d0, d4                     \n"  /* B                    */ \
1001     "vshr.u8    d4, d6, #6                     \n"  /* G 000000GG lower 2   */ \
1002     "vorr.u8    d2, d1, d5                     \n"  /* R                    */ \
1003     "vorr.u8    d1, d4, d6                     \n"  /* G                    */
1004
1005 void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int pix) {
1006   asm volatile (
1007     "vmov.u8    d3, #255                       \n"  // Alpha
1008     ".p2align   2                              \n"
1009   "1:                                          \n"
1010     MEMACCESS(0)
1011     "vld1.8     {q0}, [%0]!                    \n"  // load 8 RGB565 pixels.
1012     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1013     RGB565TOARGB
1014     MEMACCESS(1)
1015     "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 pixels of ARGB.
1016     "bgt        1b                             \n"
1017   : "+r"(src_rgb565),  // %0
1018     "+r"(dst_argb),    // %1
1019     "+r"(pix)          // %2
1020   :
1021   : "cc", "memory", "q0", "q1", "q2", "q3"  // Clobber List
1022   );
1023 }
1024
1025 #define ARGB1555TOARGB                                                         \
1026     "vshrn.u16  d7, q0, #8                     \n"  /* A Arrrrrxx           */ \
1027     "vshr.u8    d6, d7, #2                     \n"  /* R xxxRRRRR           */ \
1028     "vshrn.u16  d5, q0, #5                     \n"  /* G xxxGGGGG           */ \
1029     "vmovn.u16  d4, q0                         \n"  /* B xxxBBBBB           */ \
1030     "vshr.u8    d7, d7, #7                     \n"  /* A 0000000A           */ \
1031     "vneg.s8    d7, d7                         \n"  /* A AAAAAAAA upper 8   */ \
1032     "vshl.u8    d6, d6, #3                     \n"  /* R RRRRR000 upper 5   */ \
1033     "vshr.u8    q1, q3, #5                     \n"  /* R,A 00000RRR lower 3 */ \
1034     "vshl.u8    q0, q2, #3                     \n"  /* B,G BBBBB000 upper 5 */ \
1035     "vshr.u8    q2, q0, #5                     \n"  /* B,G 00000BBB lower 3 */ \
1036     "vorr.u8    q1, q1, q3                     \n"  /* R,A                  */ \
1037     "vorr.u8    q0, q0, q2                     \n"  /* B,G                  */ \
1038
1039 // RGB555TOARGB is same as ARGB1555TOARGB but ignores alpha.
1040 #define RGB555TOARGB                                                           \
1041     "vshrn.u16  d6, q0, #5                     \n"  /* G xxxGGGGG           */ \
1042     "vuzp.u8    d0, d1                         \n"  /* d0 xxxBBBBB xRRRRRxx */ \
1043     "vshl.u8    d6, d6, #3                     \n"  /* G GGGGG000 upper 5   */ \
1044     "vshr.u8    d1, d1, #2                     \n"  /* R 00xRRRRR lower 5   */ \
1045     "vshl.u8    q0, q0, #3                     \n"  /* B,R BBBBB000 upper 5 */ \
1046     "vshr.u8    q2, q0, #5                     \n"  /* B,R 00000BBB lower 3 */ \
1047     "vorr.u8    d0, d0, d4                     \n"  /* B                    */ \
1048     "vshr.u8    d4, d6, #5                     \n"  /* G 00000GGG lower 3   */ \
1049     "vorr.u8    d2, d1, d5                     \n"  /* R                    */ \
1050     "vorr.u8    d1, d4, d6                     \n"  /* G                    */
1051
1052 void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, uint8* dst_argb,
1053                             int pix) {
1054   asm volatile (
1055     "vmov.u8    d3, #255                       \n"  // Alpha
1056     ".p2align   2                              \n"
1057   "1:                                          \n"
1058     MEMACCESS(0)
1059     "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB1555 pixels.
1060     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1061     ARGB1555TOARGB
1062     MEMACCESS(1)
1063     "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 pixels of ARGB.
1064     "bgt        1b                             \n"
1065   : "+r"(src_argb1555),  // %0
1066     "+r"(dst_argb),    // %1
1067     "+r"(pix)          // %2
1068   :
1069   : "cc", "memory", "q0", "q1", "q2", "q3"  // Clobber List
1070   );
1071 }
1072
1073 #define ARGB4444TOARGB                                                         \
1074     "vuzp.u8    d0, d1                         \n"  /* d0 BG, d1 RA         */ \
1075     "vshl.u8    q2, q0, #4                     \n"  /* B,R BBBB0000         */ \
1076     "vshr.u8    q1, q0, #4                     \n"  /* G,A 0000GGGG         */ \
1077     "vshr.u8    q0, q2, #4                     \n"  /* B,R 0000BBBB         */ \
1078     "vorr.u8    q0, q0, q2                     \n"  /* B,R BBBBBBBB         */ \
1079     "vshl.u8    q2, q1, #4                     \n"  /* G,A GGGG0000         */ \
1080     "vorr.u8    q1, q1, q2                     \n"  /* G,A GGGGGGGG         */ \
1081     "vswp.u8    d1, d2                         \n"  /* B,R,G,A -> B,G,R,A   */
1082
1083 void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, uint8* dst_argb,
1084                             int pix) {
1085   asm volatile (
1086     "vmov.u8    d3, #255                       \n"  // Alpha
1087     ".p2align   2                              \n"
1088   "1:                                          \n"
1089     MEMACCESS(0)
1090     "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB4444 pixels.
1091     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1092     ARGB4444TOARGB
1093     MEMACCESS(1)
1094     "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 pixels of ARGB.
1095     "bgt        1b                             \n"
1096   : "+r"(src_argb4444),  // %0
1097     "+r"(dst_argb),    // %1
1098     "+r"(pix)          // %2
1099   :
1100   : "cc", "memory", "q0", "q1", "q2"  // Clobber List
1101   );
1102 }
1103
1104 void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int pix) {
1105   asm volatile (
1106     ".p2align   2                              \n"
1107   "1:                                          \n"
1108     MEMACCESS(0)
1109     "vld4.8     {d1, d2, d3, d4}, [%0]!        \n"  // load 8 pixels of ARGB.
1110     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1111     MEMACCESS(1)
1112     "vst3.8     {d1, d2, d3}, [%1]!            \n"  // store 8 pixels of RGB24.
1113     "bgt        1b                             \n"
1114   : "+r"(src_argb),   // %0
1115     "+r"(dst_rgb24),  // %1
1116     "+r"(pix)         // %2
1117   :
1118   : "cc", "memory", "d1", "d2", "d3", "d4"  // Clobber List
1119   );
1120 }
1121
1122 void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int pix) {
1123   asm volatile (
1124     ".p2align   2                              \n"
1125   "1:                                          \n"
1126     MEMACCESS(0)
1127     "vld4.8     {d1, d2, d3, d4}, [%0]!        \n"  // load 8 pixels of ARGB.
1128     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1129     "vswp.u8    d1, d3                         \n"  // swap R, B
1130     MEMACCESS(1)
1131     "vst3.8     {d1, d2, d3}, [%1]!            \n"  // store 8 pixels of RAW.
1132     "bgt        1b                             \n"
1133   : "+r"(src_argb),  // %0
1134     "+r"(dst_raw),   // %1
1135     "+r"(pix)        // %2
1136   :
1137   : "cc", "memory", "d1", "d2", "d3", "d4"  // Clobber List
1138   );
1139 }
1140
1141 void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int pix) {
1142   asm volatile (
1143     ".p2align   2                              \n"
1144   "1:                                          \n"
1145     MEMACCESS(0)
1146     "vld2.8     {q0, q1}, [%0]!                \n"  // load 16 pixels of YUY2.
1147     "subs       %2, %2, #16                    \n"  // 16 processed per loop.
1148     MEMACCESS(1)
1149     "vst1.8     {q0}, [%1]!                    \n"  // store 16 pixels of Y.
1150     "bgt        1b                             \n"
1151   : "+r"(src_yuy2),  // %0
1152     "+r"(dst_y),     // %1
1153     "+r"(pix)        // %2
1154   :
1155   : "cc", "memory", "q0", "q1"  // Clobber List
1156   );
1157 }
1158
1159 void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int pix) {
1160   asm volatile (
1161     ".p2align   2                              \n"
1162   "1:                                          \n"
1163     MEMACCESS(0)
1164     "vld2.8     {q0, q1}, [%0]!                \n"  // load 16 pixels of UYVY.
1165     "subs       %2, %2, #16                    \n"  // 16 processed per loop.
1166     MEMACCESS(1)
1167     "vst1.8     {q1}, [%1]!                    \n"  // store 16 pixels of Y.
1168     "bgt        1b                             \n"
1169   : "+r"(src_uyvy),  // %0
1170     "+r"(dst_y),     // %1
1171     "+r"(pix)        // %2
1172   :
1173   : "cc", "memory", "q0", "q1"  // Clobber List
1174   );
1175 }
1176
1177 void YUY2ToUV422Row_NEON(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
1178                          int pix) {
1179   asm volatile (
1180     ".p2align   2                              \n"
1181   "1:                                          \n"
1182     MEMACCESS(0)
1183     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 16 pixels of YUY2.
1184     "subs       %3, %3, #16                    \n"  // 16 pixels = 8 UVs.
1185     MEMACCESS(1)
1186     "vst1.8     {d1}, [%1]!                    \n"  // store 8 U.
1187     MEMACCESS(2)
1188     "vst1.8     {d3}, [%2]!                    \n"  // store 8 V.
1189     "bgt        1b                             \n"
1190   : "+r"(src_yuy2),  // %0
1191     "+r"(dst_u),     // %1
1192     "+r"(dst_v),     // %2
1193     "+r"(pix)        // %3
1194   :
1195   : "cc", "memory", "d0", "d1", "d2", "d3"  // Clobber List
1196   );
1197 }
1198
1199 void UYVYToUV422Row_NEON(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v,
1200                          int pix) {
1201   asm volatile (
1202     ".p2align   2                              \n"
1203   "1:                                          \n"
1204     MEMACCESS(0)
1205     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 16 pixels of UYVY.
1206     "subs       %3, %3, #16                    \n"  // 16 pixels = 8 UVs.
1207     MEMACCESS(1)
1208     "vst1.8     {d0}, [%1]!                    \n"  // store 8 U.
1209     MEMACCESS(2)
1210     "vst1.8     {d2}, [%2]!                    \n"  // store 8 V.
1211     "bgt        1b                             \n"
1212   : "+r"(src_uyvy),  // %0
1213     "+r"(dst_u),     // %1
1214     "+r"(dst_v),     // %2
1215     "+r"(pix)        // %3
1216   :
1217   : "cc", "memory", "d0", "d1", "d2", "d3"  // Clobber List
1218   );
1219 }
1220
1221 void YUY2ToUVRow_NEON(const uint8* src_yuy2, int stride_yuy2,
1222                       uint8* dst_u, uint8* dst_v, int pix) {
1223   asm volatile (
1224     "add        %1, %0, %1                     \n"  // stride + src_yuy2
1225     ".p2align   2                              \n"
1226   "1:                                          \n"
1227     MEMACCESS(0)
1228     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 16 pixels of YUY2.
1229     "subs       %4, %4, #16                    \n"  // 16 pixels = 8 UVs.
1230     MEMACCESS(1)
1231     "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load next row YUY2.
1232     "vrhadd.u8  d1, d1, d5                     \n"  // average rows of U
1233     "vrhadd.u8  d3, d3, d7                     \n"  // average rows of V
1234     MEMACCESS(2)
1235     "vst1.8     {d1}, [%2]!                    \n"  // store 8 U.
1236     MEMACCESS(3)
1237     "vst1.8     {d3}, [%3]!                    \n"  // store 8 V.
1238     "bgt        1b                             \n"
1239   : "+r"(src_yuy2),     // %0
1240     "+r"(stride_yuy2),  // %1
1241     "+r"(dst_u),        // %2
1242     "+r"(dst_v),        // %3
1243     "+r"(pix)           // %4
1244   :
1245   : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"  // Clobber List
1246   );
1247 }
1248
1249 void UYVYToUVRow_NEON(const uint8* src_uyvy, int stride_uyvy,
1250                       uint8* dst_u, uint8* dst_v, int pix) {
1251   asm volatile (
1252     "add        %1, %0, %1                     \n"  // stride + src_uyvy
1253     ".p2align   2                              \n"
1254   "1:                                          \n"
1255     MEMACCESS(0)
1256     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 16 pixels of UYVY.
1257     "subs       %4, %4, #16                    \n"  // 16 pixels = 8 UVs.
1258     MEMACCESS(1)
1259     "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load next row UYVY.
1260     "vrhadd.u8  d0, d0, d4                     \n"  // average rows of U
1261     "vrhadd.u8  d2, d2, d6                     \n"  // average rows of V
1262     MEMACCESS(2)
1263     "vst1.8     {d0}, [%2]!                    \n"  // store 8 U.
1264     MEMACCESS(3)
1265     "vst1.8     {d2}, [%3]!                    \n"  // store 8 V.
1266     "bgt        1b                             \n"
1267   : "+r"(src_uyvy),     // %0
1268     "+r"(stride_uyvy),  // %1
1269     "+r"(dst_u),        // %2
1270     "+r"(dst_v),        // %3
1271     "+r"(pix)           // %4
1272   :
1273   : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"  // Clobber List
1274   );
1275 }
1276
1277 // Select 2 channels from ARGB on alternating pixels.  e.g.  BGBGBGBG
1278 void ARGBToBayerRow_NEON(const uint8* src_argb, uint8* dst_bayer,
1279                          uint32 selector, int pix) {
1280   asm volatile (
1281     "vmov.u32   d6[0], %3                      \n"  // selector
1282   "1:                                          \n"
1283     MEMACCESS(0)
1284     "vld1.8     {q0, q1}, [%0]!                \n"  // load row 8 pixels.
1285     "subs       %2, %2, #8                     \n"  // 8 processed per loop
1286     "vtbl.8     d4, {d0, d1}, d6               \n"  // look up 4 pixels
1287     "vtbl.8     d5, {d2, d3}, d6               \n"  // look up 4 pixels
1288     "vtrn.u32   d4, d5                         \n"  // combine 8 pixels
1289     MEMACCESS(1)
1290     "vst1.8     {d4}, [%1]!                    \n"  // store 8.
1291     "bgt        1b                             \n"
1292   : "+r"(src_argb),   // %0
1293     "+r"(dst_bayer),  // %1
1294     "+r"(pix)         // %2
1295   : "r"(selector)     // %3
1296   : "cc", "memory", "q0", "q1", "q2", "q3"  // Clobber List
1297   );
1298 }
1299
1300 // Select G channels from ARGB.  e.g.  GGGGGGGG
1301 void ARGBToBayerGGRow_NEON(const uint8* src_argb, uint8* dst_bayer,
1302                            uint32 /*selector*/, int pix) {
1303   asm volatile (
1304   "1:                                          \n"
1305     MEMACCESS(0)
1306     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load row 8 pixels.
1307     "subs       %2, %2, #8                     \n"  // 8 processed per loop
1308     MEMACCESS(1)
1309     "vst1.8     {d1}, [%1]!                    \n"  // store 8 G's.
1310     "bgt        1b                             \n"
1311   : "+r"(src_argb),   // %0
1312     "+r"(dst_bayer),  // %1
1313     "+r"(pix)         // %2
1314   :
1315   : "cc", "memory", "q0", "q1"  // Clobber List
1316   );
1317 }
1318
1319 // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA.
1320 void ARGBShuffleRow_NEON(const uint8* src_argb, uint8* dst_argb,
1321                          const uint8* shuffler, int pix) {
1322   asm volatile (
1323     MEMACCESS(3)
1324     "vld1.8     {q2}, [%3]                     \n"  // shuffler
1325   "1:                                          \n"
1326     MEMACCESS(0)
1327     "vld1.8     {q0}, [%0]!                    \n"  // load 4 pixels.
1328     "subs       %2, %2, #4                     \n"  // 4 processed per loop
1329     "vtbl.8     d2, {d0, d1}, d4               \n"  // look up 2 first pixels
1330     "vtbl.8     d3, {d0, d1}, d5               \n"  // look up 2 next pixels
1331     MEMACCESS(1)
1332     "vst1.8     {q1}, [%1]!                    \n"  // store 4.
1333     "bgt        1b                             \n"
1334   : "+r"(src_argb),  // %0
1335     "+r"(dst_argb),  // %1
1336     "+r"(pix)        // %2
1337   : "r"(shuffler)    // %3
1338   : "cc", "memory", "q0", "q1", "q2"  // Clobber List
1339   );
1340 }
1341
1342 void I422ToYUY2Row_NEON(const uint8* src_y,
1343                         const uint8* src_u,
1344                         const uint8* src_v,
1345                         uint8* dst_yuy2, int width) {
1346   asm volatile (
1347     ".p2align   2                              \n"
1348   "1:                                          \n"
1349     MEMACCESS(0)
1350     "vld2.8     {d0, d2}, [%0]!                \n"  // load 16 Ys
1351     MEMACCESS(1)
1352     "vld1.8     {d1}, [%1]!                    \n"  // load 8 Us
1353     MEMACCESS(2)
1354     "vld1.8     {d3}, [%2]!                    \n"  // load 8 Vs
1355     "subs       %4, %4, #16                    \n"  // 16 pixels
1356     MEMACCESS(3)
1357     "vst4.8     {d0, d1, d2, d3}, [%3]!        \n"  // Store 8 YUY2/16 pixels.
1358     "bgt        1b                             \n"
1359   : "+r"(src_y),     // %0
1360     "+r"(src_u),     // %1
1361     "+r"(src_v),     // %2
1362     "+r"(dst_yuy2),  // %3
1363     "+r"(width)      // %4
1364   :
1365   : "cc", "memory", "d0", "d1", "d2", "d3"
1366   );
1367 }
1368
1369 void I422ToUYVYRow_NEON(const uint8* src_y,
1370                         const uint8* src_u,
1371                         const uint8* src_v,
1372                         uint8* dst_uyvy, int width) {
1373   asm volatile (
1374     ".p2align   2                              \n"
1375   "1:                                          \n"
1376     MEMACCESS(0)
1377     "vld2.8     {d1, d3}, [%0]!                \n"  // load 16 Ys
1378     MEMACCESS(1)
1379     "vld1.8     {d0}, [%1]!                    \n"  // load 8 Us
1380     MEMACCESS(2)
1381     "vld1.8     {d2}, [%2]!                    \n"  // load 8 Vs
1382     "subs       %4, %4, #16                    \n"  // 16 pixels
1383     MEMACCESS(3)
1384     "vst4.8     {d0, d1, d2, d3}, [%3]!        \n"  // Store 8 UYVY/16 pixels.
1385     "bgt        1b                             \n"
1386   : "+r"(src_y),     // %0
1387     "+r"(src_u),     // %1
1388     "+r"(src_v),     // %2
1389     "+r"(dst_uyvy),  // %3
1390     "+r"(width)      // %4
1391   :
1392   : "cc", "memory", "d0", "d1", "d2", "d3"
1393   );
1394 }
1395
1396 void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int pix) {
1397   asm volatile (
1398     ".p2align   2                              \n"
1399   "1:                                          \n"
1400     MEMACCESS(0)
1401     "vld4.8     {d20, d21, d22, d23}, [%0]!    \n"  // load 8 pixels of ARGB.
1402     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1403     ARGBTORGB565
1404     MEMACCESS(1)
1405     "vst1.8     {q0}, [%1]!                    \n"  // store 8 pixels RGB565.
1406     "bgt        1b                             \n"
1407   : "+r"(src_argb),  // %0
1408     "+r"(dst_rgb565),  // %1
1409     "+r"(pix)        // %2
1410   :
1411   : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
1412   );
1413 }
1414
1415 void ARGBToARGB1555Row_NEON(const uint8* src_argb, uint8* dst_argb1555,
1416                             int pix) {
1417   asm volatile (
1418     ".p2align   2                              \n"
1419   "1:                                          \n"
1420     MEMACCESS(0)
1421     "vld4.8     {d20, d21, d22, d23}, [%0]!    \n"  // load 8 pixels of ARGB.
1422     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1423     ARGBTOARGB1555
1424     MEMACCESS(1)
1425     "vst1.8     {q0}, [%1]!                    \n"  // store 8 pixels ARGB1555.
1426     "bgt        1b                             \n"
1427   : "+r"(src_argb),  // %0
1428     "+r"(dst_argb1555),  // %1
1429     "+r"(pix)        // %2
1430   :
1431   : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
1432   );
1433 }
1434
1435 void ARGBToARGB4444Row_NEON(const uint8* src_argb, uint8* dst_argb4444,
1436                             int pix) {
1437   asm volatile (
1438     "vmov.u8    d4, #0x0f                      \n"  // bits to clear with vbic.
1439     ".p2align   2                              \n"
1440   "1:                                          \n"
1441     MEMACCESS(0)
1442     "vld4.8     {d20, d21, d22, d23}, [%0]!    \n"  // load 8 pixels of ARGB.
1443     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1444     ARGBTOARGB4444
1445     MEMACCESS(1)
1446     "vst1.8     {q0}, [%1]!                    \n"  // store 8 pixels ARGB4444.
1447     "bgt        1b                             \n"
1448   : "+r"(src_argb),      // %0
1449     "+r"(dst_argb4444),  // %1
1450     "+r"(pix)            // %2
1451   :
1452   : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
1453   );
1454 }
1455
1456 void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) {
1457   asm volatile (
1458     "vmov.u8    d24, #13                       \n"  // B * 0.1016 coefficient
1459     "vmov.u8    d25, #65                       \n"  // G * 0.5078 coefficient
1460     "vmov.u8    d26, #33                       \n"  // R * 0.2578 coefficient
1461     "vmov.u8    d27, #16                       \n"  // Add 16 constant
1462     ".p2align   2                              \n"
1463   "1:                                          \n"
1464     MEMACCESS(0)
1465     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
1466     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1467     "vmull.u8   q2, d0, d24                    \n"  // B
1468     "vmlal.u8   q2, d1, d25                    \n"  // G
1469     "vmlal.u8   q2, d2, d26                    \n"  // R
1470     "vqrshrun.s16 d0, q2, #7                   \n"  // 16 bit to 8 bit Y
1471     "vqadd.u8   d0, d27                        \n"
1472     MEMACCESS(1)
1473     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
1474     "bgt        1b                             \n"
1475   : "+r"(src_argb),  // %0
1476     "+r"(dst_y),     // %1
1477     "+r"(pix)        // %2
1478   :
1479   : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
1480   );
1481 }
1482
1483 void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) {
1484   asm volatile (
1485     "vmov.u8    d24, #15                       \n"  // B * 0.11400 coefficient
1486     "vmov.u8    d25, #75                       \n"  // G * 0.58700 coefficient
1487     "vmov.u8    d26, #38                       \n"  // R * 0.29900 coefficient
1488     ".p2align   2                              \n"
1489   "1:                                          \n"
1490     MEMACCESS(0)
1491     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
1492     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
1493     "vmull.u8   q2, d0, d24                    \n"  // B
1494     "vmlal.u8   q2, d1, d25                    \n"  // G
1495     "vmlal.u8   q2, d2, d26                    \n"  // R
1496     "vqrshrun.s16 d0, q2, #7                   \n"  // 15 bit to 8 bit Y
1497     MEMACCESS(1)
1498     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
1499     "bgt        1b                             \n"
1500   : "+r"(src_argb),  // %0
1501     "+r"(dst_y),     // %1
1502     "+r"(pix)        // %2
1503   :
1504   : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
1505   );
1506 }
1507
1508 // 8x1 pixels.
1509 void ARGBToUV444Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
1510                          int pix) {
1511   asm volatile (
1512     "vmov.u8    d24, #112                      \n"  // UB / VR 0.875 coefficient
1513     "vmov.u8    d25, #74                       \n"  // UG -0.5781 coefficient
1514     "vmov.u8    d26, #38                       \n"  // UR -0.2969 coefficient
1515     "vmov.u8    d27, #18                       \n"  // VB -0.1406 coefficient
1516     "vmov.u8    d28, #94                       \n"  // VG -0.7344 coefficient
1517     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1518     ".p2align   2                              \n"
1519   "1:                                          \n"
1520     MEMACCESS(0)
1521     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
1522     "subs       %3, %3, #8                     \n"  // 8 processed per loop.
1523     "vmull.u8   q2, d0, d24                    \n"  // B
1524     "vmlsl.u8   q2, d1, d25                    \n"  // G
1525     "vmlsl.u8   q2, d2, d26                    \n"  // R
1526     "vadd.u16   q2, q2, q15                    \n"  // +128 -> unsigned
1527
1528     "vmull.u8   q3, d2, d24                    \n"  // R
1529     "vmlsl.u8   q3, d1, d28                    \n"  // G
1530     "vmlsl.u8   q3, d0, d27                    \n"  // B
1531     "vadd.u16   q3, q3, q15                    \n"  // +128 -> unsigned
1532
1533     "vqshrn.u16  d0, q2, #8                    \n"  // 16 bit to 8 bit U
1534     "vqshrn.u16  d1, q3, #8                    \n"  // 16 bit to 8 bit V
1535
1536     MEMACCESS(1)
1537     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels U.
1538     MEMACCESS(2)
1539     "vst1.8     {d1}, [%2]!                    \n"  // store 8 pixels V.
1540     "bgt        1b                             \n"
1541   : "+r"(src_argb),  // %0
1542     "+r"(dst_u),     // %1
1543     "+r"(dst_v),     // %2
1544     "+r"(pix)        // %3
1545   :
1546   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q12", "q13", "q14", "q15"
1547   );
1548 }
1549
1550 // 16x1 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
1551 void ARGBToUV422Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
1552                          int pix) {
1553   asm volatile (
1554     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
1555     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
1556     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
1557     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
1558     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
1559     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1560     ".p2align   2                              \n"
1561   "1:                                          \n"
1562     MEMACCESS(0)
1563     "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
1564     MEMACCESS(0)
1565     "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ARGB pixels.
1566
1567     "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
1568     "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
1569     "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
1570
1571     "subs       %3, %3, #16                    \n"  // 16 processed per loop.
1572     "vmul.s16   q8, q0, q10                    \n"  // B
1573     "vmls.s16   q8, q1, q11                    \n"  // G
1574     "vmls.s16   q8, q2, q12                    \n"  // R
1575     "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
1576
1577     "vmul.s16   q9, q2, q10                    \n"  // R
1578     "vmls.s16   q9, q1, q14                    \n"  // G
1579     "vmls.s16   q9, q0, q13                    \n"  // B
1580     "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
1581
1582     "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
1583     "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
1584
1585     MEMACCESS(1)
1586     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels U.
1587     MEMACCESS(2)
1588     "vst1.8     {d1}, [%2]!                    \n"  // store 8 pixels V.
1589     "bgt        1b                             \n"
1590   : "+r"(src_argb),  // %0
1591     "+r"(dst_u),     // %1
1592     "+r"(dst_v),     // %2
1593     "+r"(pix)        // %3
1594   :
1595   : "cc", "memory", "q0", "q1", "q2", "q3",
1596     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1597   );
1598 }
1599
1600 // 32x1 pixels -> 8x1.  pix is number of argb pixels. e.g. 32.
1601 void ARGBToUV411Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
1602                          int pix) {
1603   asm volatile (
1604     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
1605     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
1606     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
1607     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
1608     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
1609     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1610     ".p2align   2                              \n"
1611   "1:                                          \n"
1612     MEMACCESS(0)
1613     "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
1614     MEMACCESS(0)
1615     "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ARGB pixels.
1616     "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
1617     "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
1618     "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
1619     MEMACCESS(0)
1620     "vld4.8     {d8, d10, d12, d14}, [%0]!     \n"  // load 8 more ARGB pixels.
1621     MEMACCESS(0)
1622     "vld4.8     {d9, d11, d13, d15}, [%0]!     \n"  // load last 8 ARGB pixels.
1623     "vpaddl.u8  q4, q4                         \n"  // B 16 bytes -> 8 shorts.
1624     "vpaddl.u8  q5, q5                         \n"  // G 16 bytes -> 8 shorts.
1625     "vpaddl.u8  q6, q6                         \n"  // R 16 bytes -> 8 shorts.
1626
1627     "vpadd.u16  d0, d0, d1                     \n"  // B 16 shorts -> 8 shorts.
1628     "vpadd.u16  d1, d8, d9                     \n"  // B
1629     "vpadd.u16  d2, d2, d3                     \n"  // G 16 shorts -> 8 shorts.
1630     "vpadd.u16  d3, d10, d11                   \n"  // G
1631     "vpadd.u16  d4, d4, d5                     \n"  // R 16 shorts -> 8 shorts.
1632     "vpadd.u16  d5, d12, d13                   \n"  // R
1633
1634     "vrshr.u16  q0, q0, #1                     \n"  // 2x average
1635     "vrshr.u16  q1, q1, #1                     \n"
1636     "vrshr.u16  q2, q2, #1                     \n"
1637
1638     "subs       %3, %3, #32                    \n"  // 32 processed per loop.
1639     "vmul.s16   q8, q0, q10                    \n"  // B
1640     "vmls.s16   q8, q1, q11                    \n"  // G
1641     "vmls.s16   q8, q2, q12                    \n"  // R
1642     "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
1643     "vmul.s16   q9, q2, q10                    \n"  // R
1644     "vmls.s16   q9, q1, q14                    \n"  // G
1645     "vmls.s16   q9, q0, q13                    \n"  // B
1646     "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
1647     "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
1648     "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
1649     MEMACCESS(1)
1650     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels U.
1651     MEMACCESS(2)
1652     "vst1.8     {d1}, [%2]!                    \n"  // store 8 pixels V.
1653     "bgt        1b                             \n"
1654   : "+r"(src_argb),  // %0
1655     "+r"(dst_u),     // %1
1656     "+r"(dst_v),     // %2
1657     "+r"(pix)        // %3
1658   :
1659   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1660     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1661   );
1662 }
1663
1664 // 16x2 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
1665 #define RGBTOUV(QB, QG, QR) \
1666     "vmul.s16   q8, " #QB ", q10               \n"  /* B                    */ \
1667     "vmls.s16   q8, " #QG ", q11               \n"  /* G                    */ \
1668     "vmls.s16   q8, " #QR ", q12               \n"  /* R                    */ \
1669     "vadd.u16   q8, q8, q15                    \n"  /* +128 -> unsigned     */ \
1670     "vmul.s16   q9, " #QR ", q10               \n"  /* R                    */ \
1671     "vmls.s16   q9, " #QG ", q14               \n"  /* G                    */ \
1672     "vmls.s16   q9, " #QB ", q13               \n"  /* B                    */ \
1673     "vadd.u16   q9, q9, q15                    \n"  /* +128 -> unsigned     */ \
1674     "vqshrn.u16  d0, q8, #8                    \n"  /* 16 bit to 8 bit U    */ \
1675     "vqshrn.u16  d1, q9, #8                    \n"  /* 16 bit to 8 bit V    */
1676
1677 // TODO(fbarchard): Consider vhadd vertical, then vpaddl horizontal, avoid shr.
1678 void ARGBToUVRow_NEON(const uint8* src_argb, int src_stride_argb,
1679                       uint8* dst_u, uint8* dst_v, int pix) {
1680   asm volatile (
1681     "add        %1, %0, %1                     \n"  // src_stride + src_argb
1682     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
1683     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
1684     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
1685     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
1686     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
1687     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1688     ".p2align   2                              \n"
1689   "1:                                          \n"
1690     MEMACCESS(0)
1691     "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
1692     MEMACCESS(0)
1693     "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ARGB pixels.
1694     "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
1695     "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
1696     "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
1697     MEMACCESS(1)
1698     "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more ARGB pixels.
1699     MEMACCESS(1)
1700     "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 ARGB pixels.
1701     "vpadal.u8  q0, q4                         \n"  // B 16 bytes -> 8 shorts.
1702     "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
1703     "vpadal.u8  q2, q6                         \n"  // R 16 bytes -> 8 shorts.
1704
1705     "vrshr.u16  q0, q0, #1                     \n"  // 2x average
1706     "vrshr.u16  q1, q1, #1                     \n"
1707     "vrshr.u16  q2, q2, #1                     \n"
1708
1709     "subs       %4, %4, #16                    \n"  // 32 processed per loop.
1710     RGBTOUV(q0, q1, q2)
1711     MEMACCESS(2)
1712     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
1713     MEMACCESS(3)
1714     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
1715     "bgt        1b                             \n"
1716   : "+r"(src_argb),  // %0
1717     "+r"(src_stride_argb),  // %1
1718     "+r"(dst_u),     // %2
1719     "+r"(dst_v),     // %3
1720     "+r"(pix)        // %4
1721   :
1722   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1723     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1724   );
1725 }
1726
1727 // TODO(fbarchard): Subsample match C code.
1728 void ARGBToUVJRow_NEON(const uint8* src_argb, int src_stride_argb,
1729                        uint8* dst_u, uint8* dst_v, int pix) {
1730   asm volatile (
1731     "add        %1, %0, %1                     \n"  // src_stride + src_argb
1732     "vmov.s16   q10, #127 / 2                  \n"  // UB / VR 0.500 coefficient
1733     "vmov.s16   q11, #84 / 2                   \n"  // UG -0.33126 coefficient
1734     "vmov.s16   q12, #43 / 2                   \n"  // UR -0.16874 coefficient
1735     "vmov.s16   q13, #20 / 2                   \n"  // VB -0.08131 coefficient
1736     "vmov.s16   q14, #107 / 2                  \n"  // VG -0.41869 coefficient
1737     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1738     ".p2align   2                              \n"
1739   "1:                                          \n"
1740     MEMACCESS(0)
1741     "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
1742     MEMACCESS(0)
1743     "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ARGB pixels.
1744     "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
1745     "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
1746     "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
1747     MEMACCESS(1)
1748     "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more ARGB pixels.
1749     MEMACCESS(1)
1750     "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 ARGB pixels.
1751     "vpadal.u8  q0, q4                         \n"  // B 16 bytes -> 8 shorts.
1752     "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
1753     "vpadal.u8  q2, q6                         \n"  // R 16 bytes -> 8 shorts.
1754
1755     "vrshr.u16  q0, q0, #1                     \n"  // 2x average
1756     "vrshr.u16  q1, q1, #1                     \n"
1757     "vrshr.u16  q2, q2, #1                     \n"
1758
1759     "subs       %4, %4, #16                    \n"  // 32 processed per loop.
1760     RGBTOUV(q0, q1, q2)
1761     MEMACCESS(2)
1762     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
1763     MEMACCESS(3)
1764     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
1765     "bgt        1b                             \n"
1766   : "+r"(src_argb),  // %0
1767     "+r"(src_stride_argb),  // %1
1768     "+r"(dst_u),     // %2
1769     "+r"(dst_v),     // %3
1770     "+r"(pix)        // %4
1771   :
1772   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1773     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1774   );
1775 }
1776
1777 void BGRAToUVRow_NEON(const uint8* src_bgra, int src_stride_bgra,
1778                       uint8* dst_u, uint8* dst_v, int pix) {
1779   asm volatile (
1780     "add        %1, %0, %1                     \n"  // src_stride + src_bgra
1781     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
1782     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
1783     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
1784     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
1785     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
1786     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1787     ".p2align   2                              \n"
1788   "1:                                          \n"
1789     MEMACCESS(0)
1790     "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 BGRA pixels.
1791     MEMACCESS(0)
1792     "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 BGRA pixels.
1793     "vpaddl.u8  q3, q3                         \n"  // B 16 bytes -> 8 shorts.
1794     "vpaddl.u8  q2, q2                         \n"  // G 16 bytes -> 8 shorts.
1795     "vpaddl.u8  q1, q1                         \n"  // R 16 bytes -> 8 shorts.
1796     MEMACCESS(1)
1797     "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more BGRA pixels.
1798     MEMACCESS(1)
1799     "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 BGRA pixels.
1800     "vpadal.u8  q3, q7                         \n"  // B 16 bytes -> 8 shorts.
1801     "vpadal.u8  q2, q6                         \n"  // G 16 bytes -> 8 shorts.
1802     "vpadal.u8  q1, q5                         \n"  // R 16 bytes -> 8 shorts.
1803
1804     "vrshr.u16  q1, q1, #1                     \n"  // 2x average
1805     "vrshr.u16  q2, q2, #1                     \n"
1806     "vrshr.u16  q3, q3, #1                     \n"
1807
1808     "subs       %4, %4, #16                    \n"  // 32 processed per loop.
1809     RGBTOUV(q3, q2, q1)
1810     MEMACCESS(2)
1811     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
1812     MEMACCESS(3)
1813     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
1814     "bgt        1b                             \n"
1815   : "+r"(src_bgra),  // %0
1816     "+r"(src_stride_bgra),  // %1
1817     "+r"(dst_u),     // %2
1818     "+r"(dst_v),     // %3
1819     "+r"(pix)        // %4
1820   :
1821   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1822     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1823   );
1824 }
1825
1826 void ABGRToUVRow_NEON(const uint8* src_abgr, int src_stride_abgr,
1827                       uint8* dst_u, uint8* dst_v, int pix) {
1828   asm volatile (
1829     "add        %1, %0, %1                     \n"  // src_stride + src_abgr
1830     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
1831     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
1832     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
1833     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
1834     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
1835     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1836     ".p2align   2                              \n"
1837   "1:                                          \n"
1838     MEMACCESS(0)
1839     "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ABGR pixels.
1840     MEMACCESS(0)
1841     "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ABGR pixels.
1842     "vpaddl.u8  q2, q2                         \n"  // B 16 bytes -> 8 shorts.
1843     "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
1844     "vpaddl.u8  q0, q0                         \n"  // R 16 bytes -> 8 shorts.
1845     MEMACCESS(1)
1846     "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more ABGR pixels.
1847     MEMACCESS(1)
1848     "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 ABGR pixels.
1849     "vpadal.u8  q2, q6                         \n"  // B 16 bytes -> 8 shorts.
1850     "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
1851     "vpadal.u8  q0, q4                         \n"  // R 16 bytes -> 8 shorts.
1852
1853     "vrshr.u16  q0, q0, #1                     \n"  // 2x average
1854     "vrshr.u16  q1, q1, #1                     \n"
1855     "vrshr.u16  q2, q2, #1                     \n"
1856
1857     "subs       %4, %4, #16                    \n"  // 32 processed per loop.
1858     RGBTOUV(q2, q1, q0)
1859     MEMACCESS(2)
1860     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
1861     MEMACCESS(3)
1862     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
1863     "bgt        1b                             \n"
1864   : "+r"(src_abgr),  // %0
1865     "+r"(src_stride_abgr),  // %1
1866     "+r"(dst_u),     // %2
1867     "+r"(dst_v),     // %3
1868     "+r"(pix)        // %4
1869   :
1870   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1871     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1872   );
1873 }
1874
1875 void RGBAToUVRow_NEON(const uint8* src_rgba, int src_stride_rgba,
1876                       uint8* dst_u, uint8* dst_v, int pix) {
1877   asm volatile (
1878     "add        %1, %0, %1                     \n"  // src_stride + src_rgba
1879     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
1880     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
1881     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
1882     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
1883     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
1884     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1885     ".p2align   2                              \n"
1886   "1:                                          \n"
1887     MEMACCESS(0)
1888     "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 RGBA pixels.
1889     MEMACCESS(0)
1890     "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 RGBA pixels.
1891     "vpaddl.u8  q0, q1                         \n"  // B 16 bytes -> 8 shorts.
1892     "vpaddl.u8  q1, q2                         \n"  // G 16 bytes -> 8 shorts.
1893     "vpaddl.u8  q2, q3                         \n"  // R 16 bytes -> 8 shorts.
1894     MEMACCESS(1)
1895     "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more RGBA pixels.
1896     MEMACCESS(1)
1897     "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 RGBA pixels.
1898     "vpadal.u8  q0, q5                         \n"  // B 16 bytes -> 8 shorts.
1899     "vpadal.u8  q1, q6                         \n"  // G 16 bytes -> 8 shorts.
1900     "vpadal.u8  q2, q7                         \n"  // R 16 bytes -> 8 shorts.
1901
1902     "vrshr.u16  q0, q0, #1                     \n"  // 2x average
1903     "vrshr.u16  q1, q1, #1                     \n"
1904     "vrshr.u16  q2, q2, #1                     \n"
1905
1906     "subs       %4, %4, #16                    \n"  // 32 processed per loop.
1907     RGBTOUV(q0, q1, q2)
1908     MEMACCESS(2)
1909     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
1910     MEMACCESS(3)
1911     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
1912     "bgt        1b                             \n"
1913   : "+r"(src_rgba),  // %0
1914     "+r"(src_stride_rgba),  // %1
1915     "+r"(dst_u),     // %2
1916     "+r"(dst_v),     // %3
1917     "+r"(pix)        // %4
1918   :
1919   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1920     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1921   );
1922 }
1923
1924 void RGB24ToUVRow_NEON(const uint8* src_rgb24, int src_stride_rgb24,
1925                        uint8* dst_u, uint8* dst_v, int pix) {
1926   asm volatile (
1927     "add        %1, %0, %1                     \n"  // src_stride + src_rgb24
1928     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
1929     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
1930     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
1931     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
1932     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
1933     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1934     ".p2align   2                              \n"
1935   "1:                                          \n"
1936     MEMACCESS(0)
1937     "vld3.8     {d0, d2, d4}, [%0]!            \n"  // load 8 RGB24 pixels.
1938     MEMACCESS(0)
1939     "vld3.8     {d1, d3, d5}, [%0]!            \n"  // load next 8 RGB24 pixels.
1940     "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
1941     "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
1942     "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
1943     MEMACCESS(1)
1944     "vld3.8     {d8, d10, d12}, [%1]!          \n"  // load 8 more RGB24 pixels.
1945     MEMACCESS(1)
1946     "vld3.8     {d9, d11, d13}, [%1]!          \n"  // load last 8 RGB24 pixels.
1947     "vpadal.u8  q0, q4                         \n"  // B 16 bytes -> 8 shorts.
1948     "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
1949     "vpadal.u8  q2, q6                         \n"  // R 16 bytes -> 8 shorts.
1950
1951     "vrshr.u16  q0, q0, #1                     \n"  // 2x average
1952     "vrshr.u16  q1, q1, #1                     \n"
1953     "vrshr.u16  q2, q2, #1                     \n"
1954
1955     "subs       %4, %4, #16                    \n"  // 32 processed per loop.
1956     RGBTOUV(q0, q1, q2)
1957     MEMACCESS(2)
1958     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
1959     MEMACCESS(3)
1960     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
1961     "bgt        1b                             \n"
1962   : "+r"(src_rgb24),  // %0
1963     "+r"(src_stride_rgb24),  // %1
1964     "+r"(dst_u),     // %2
1965     "+r"(dst_v),     // %3
1966     "+r"(pix)        // %4
1967   :
1968   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1969     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1970   );
1971 }
1972
1973 void RAWToUVRow_NEON(const uint8* src_raw, int src_stride_raw,
1974                      uint8* dst_u, uint8* dst_v, int pix) {
1975   asm volatile (
1976     "add        %1, %0, %1                     \n"  // src_stride + src_raw
1977     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
1978     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
1979     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
1980     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
1981     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
1982     "vmov.u16   q15, #0x8080                   \n"  // 128.5
1983     ".p2align   2                              \n"
1984   "1:                                          \n"
1985     MEMACCESS(0)
1986     "vld3.8     {d0, d2, d4}, [%0]!            \n"  // load 8 RAW pixels.
1987     MEMACCESS(0)
1988     "vld3.8     {d1, d3, d5}, [%0]!            \n"  // load next 8 RAW pixels.
1989     "vpaddl.u8  q2, q2                         \n"  // B 16 bytes -> 8 shorts.
1990     "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
1991     "vpaddl.u8  q0, q0                         \n"  // R 16 bytes -> 8 shorts.
1992     MEMACCESS(1)
1993     "vld3.8     {d8, d10, d12}, [%1]!          \n"  // load 8 more RAW pixels.
1994     MEMACCESS(1)
1995     "vld3.8     {d9, d11, d13}, [%1]!          \n"  // load last 8 RAW pixels.
1996     "vpadal.u8  q2, q6                         \n"  // B 16 bytes -> 8 shorts.
1997     "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
1998     "vpadal.u8  q0, q4                         \n"  // R 16 bytes -> 8 shorts.
1999
2000     "vrshr.u16  q0, q0, #1                     \n"  // 2x average
2001     "vrshr.u16  q1, q1, #1                     \n"
2002     "vrshr.u16  q2, q2, #1                     \n"
2003
2004     "subs       %4, %4, #16                    \n"  // 32 processed per loop.
2005     RGBTOUV(q2, q1, q0)
2006     MEMACCESS(2)
2007     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
2008     MEMACCESS(3)
2009     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
2010     "bgt        1b                             \n"
2011   : "+r"(src_raw),  // %0
2012     "+r"(src_stride_raw),  // %1
2013     "+r"(dst_u),     // %2
2014     "+r"(dst_v),     // %3
2015     "+r"(pix)        // %4
2016   :
2017   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
2018     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
2019   );
2020 }
2021
2022 // 16x2 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
2023 void RGB565ToUVRow_NEON(const uint8* src_rgb565, int src_stride_rgb565,
2024                         uint8* dst_u, uint8* dst_v, int pix) {
2025   asm volatile (
2026     "add        %1, %0, %1                     \n"  // src_stride + src_argb
2027     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
2028     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
2029     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
2030     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
2031     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
2032     "vmov.u16   q15, #0x8080                   \n"  // 128.5
2033     ".p2align   2                              \n"
2034   "1:                                          \n"
2035     MEMACCESS(0)
2036     "vld1.8     {q0}, [%0]!                    \n"  // load 8 RGB565 pixels.
2037     RGB565TOARGB
2038     "vpaddl.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
2039     "vpaddl.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
2040     "vpaddl.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
2041     MEMACCESS(0)
2042     "vld1.8     {q0}, [%0]!                    \n"  // next 8 RGB565 pixels.
2043     RGB565TOARGB
2044     "vpaddl.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
2045     "vpaddl.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
2046     "vpaddl.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
2047
2048     MEMACCESS(1)
2049     "vld1.8     {q0}, [%1]!                    \n"  // load 8 RGB565 pixels.
2050     RGB565TOARGB
2051     "vpadal.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
2052     "vpadal.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
2053     "vpadal.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
2054     MEMACCESS(1)
2055     "vld1.8     {q0}, [%1]!                    \n"  // next 8 RGB565 pixels.
2056     RGB565TOARGB
2057     "vpadal.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
2058     "vpadal.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
2059     "vpadal.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
2060
2061     "vrshr.u16  q4, q4, #1                     \n"  // 2x average
2062     "vrshr.u16  q5, q5, #1                     \n"
2063     "vrshr.u16  q6, q6, #1                     \n"
2064
2065     "subs       %4, %4, #16                    \n"  // 16 processed per loop.
2066     "vmul.s16   q8, q4, q10                    \n"  // B
2067     "vmls.s16   q8, q5, q11                    \n"  // G
2068     "vmls.s16   q8, q6, q12                    \n"  // R
2069     "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
2070     "vmul.s16   q9, q6, q10                    \n"  // R
2071     "vmls.s16   q9, q5, q14                    \n"  // G
2072     "vmls.s16   q9, q4, q13                    \n"  // B
2073     "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
2074     "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
2075     "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
2076     MEMACCESS(2)
2077     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
2078     MEMACCESS(3)
2079     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
2080     "bgt        1b                             \n"
2081   : "+r"(src_rgb565),  // %0
2082     "+r"(src_stride_rgb565),  // %1
2083     "+r"(dst_u),     // %2
2084     "+r"(dst_v),     // %3
2085     "+r"(pix)        // %4
2086   :
2087   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
2088     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
2089   );
2090 }
2091
2092 // 16x2 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
2093 void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, int src_stride_argb1555,
2094                         uint8* dst_u, uint8* dst_v, int pix) {
2095   asm volatile (
2096     "add        %1, %0, %1                     \n"  // src_stride + src_argb
2097     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
2098     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
2099     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
2100     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
2101     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
2102     "vmov.u16   q15, #0x8080                   \n"  // 128.5
2103     ".p2align   2                              \n"
2104   "1:                                          \n"
2105     MEMACCESS(0)
2106     "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB1555 pixels.
2107     RGB555TOARGB
2108     "vpaddl.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
2109     "vpaddl.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
2110     "vpaddl.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
2111     MEMACCESS(0)
2112     "vld1.8     {q0}, [%0]!                    \n"  // next 8 ARGB1555 pixels.
2113     RGB555TOARGB
2114     "vpaddl.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
2115     "vpaddl.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
2116     "vpaddl.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
2117
2118     MEMACCESS(1)
2119     "vld1.8     {q0}, [%1]!                    \n"  // load 8 ARGB1555 pixels.
2120     RGB555TOARGB
2121     "vpadal.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
2122     "vpadal.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
2123     "vpadal.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
2124     MEMACCESS(1)
2125     "vld1.8     {q0}, [%1]!                    \n"  // next 8 ARGB1555 pixels.
2126     RGB555TOARGB
2127     "vpadal.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
2128     "vpadal.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
2129     "vpadal.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
2130
2131     "vrshr.u16  q4, q4, #1                     \n"  // 2x average
2132     "vrshr.u16  q5, q5, #1                     \n"
2133     "vrshr.u16  q6, q6, #1                     \n"
2134
2135     "subs       %4, %4, #16                    \n"  // 16 processed per loop.
2136     "vmul.s16   q8, q4, q10                    \n"  // B
2137     "vmls.s16   q8, q5, q11                    \n"  // G
2138     "vmls.s16   q8, q6, q12                    \n"  // R
2139     "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
2140     "vmul.s16   q9, q6, q10                    \n"  // R
2141     "vmls.s16   q9, q5, q14                    \n"  // G
2142     "vmls.s16   q9, q4, q13                    \n"  // B
2143     "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
2144     "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
2145     "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
2146     MEMACCESS(2)
2147     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
2148     MEMACCESS(3)
2149     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
2150     "bgt        1b                             \n"
2151   : "+r"(src_argb1555),  // %0
2152     "+r"(src_stride_argb1555),  // %1
2153     "+r"(dst_u),     // %2
2154     "+r"(dst_v),     // %3
2155     "+r"(pix)        // %4
2156   :
2157   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
2158     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
2159   );
2160 }
2161
2162 // 16x2 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
2163 void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, int src_stride_argb4444,
2164                           uint8* dst_u, uint8* dst_v, int pix) {
2165   asm volatile (
2166     "add        %1, %0, %1                     \n"  // src_stride + src_argb
2167     "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
2168     "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
2169     "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
2170     "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
2171     "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
2172     "vmov.u16   q15, #0x8080                   \n"  // 128.5
2173     ".p2align   2                              \n"
2174   "1:                                          \n"
2175     MEMACCESS(0)
2176     "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB4444 pixels.
2177     ARGB4444TOARGB
2178     "vpaddl.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
2179     "vpaddl.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
2180     "vpaddl.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
2181     MEMACCESS(0)
2182     "vld1.8     {q0}, [%0]!                    \n"  // next 8 ARGB4444 pixels.
2183     ARGB4444TOARGB
2184     "vpaddl.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
2185     "vpaddl.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
2186     "vpaddl.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
2187
2188     MEMACCESS(1)
2189     "vld1.8     {q0}, [%1]!                    \n"  // load 8 ARGB4444 pixels.
2190     ARGB4444TOARGB
2191     "vpadal.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
2192     "vpadal.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
2193     "vpadal.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
2194     MEMACCESS(1)
2195     "vld1.8     {q0}, [%1]!                    \n"  // next 8 ARGB4444 pixels.
2196     ARGB4444TOARGB
2197     "vpadal.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
2198     "vpadal.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
2199     "vpadal.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
2200
2201     "vrshr.u16  q4, q4, #1                     \n"  // 2x average
2202     "vrshr.u16  q5, q5, #1                     \n"
2203     "vrshr.u16  q6, q6, #1                     \n"
2204
2205     "subs       %4, %4, #16                    \n"  // 16 processed per loop.
2206     "vmul.s16   q8, q4, q10                    \n"  // B
2207     "vmls.s16   q8, q5, q11                    \n"  // G
2208     "vmls.s16   q8, q6, q12                    \n"  // R
2209     "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
2210     "vmul.s16   q9, q6, q10                    \n"  // R
2211     "vmls.s16   q9, q5, q14                    \n"  // G
2212     "vmls.s16   q9, q4, q13                    \n"  // B
2213     "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
2214     "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
2215     "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
2216     MEMACCESS(2)
2217     "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
2218     MEMACCESS(3)
2219     "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
2220     "bgt        1b                             \n"
2221   : "+r"(src_argb4444),  // %0
2222     "+r"(src_stride_argb4444),  // %1
2223     "+r"(dst_u),     // %2
2224     "+r"(dst_v),     // %3
2225     "+r"(pix)        // %4
2226   :
2227   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
2228     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
2229   );
2230 }
2231
2232 void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int pix) {
2233   asm volatile (
2234     "vmov.u8    d24, #13                       \n"  // B * 0.1016 coefficient
2235     "vmov.u8    d25, #65                       \n"  // G * 0.5078 coefficient
2236     "vmov.u8    d26, #33                       \n"  // R * 0.2578 coefficient
2237     "vmov.u8    d27, #16                       \n"  // Add 16 constant
2238     ".p2align   2                              \n"
2239   "1:                                          \n"
2240     MEMACCESS(0)
2241     "vld1.8     {q0}, [%0]!                    \n"  // load 8 RGB565 pixels.
2242     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2243     RGB565TOARGB
2244     "vmull.u8   q2, d0, d24                    \n"  // B
2245     "vmlal.u8   q2, d1, d25                    \n"  // G
2246     "vmlal.u8   q2, d2, d26                    \n"  // R
2247     "vqrshrun.s16 d0, q2, #7                   \n"  // 16 bit to 8 bit Y
2248     "vqadd.u8   d0, d27                        \n"
2249     MEMACCESS(1)
2250     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
2251     "bgt        1b                             \n"
2252   : "+r"(src_rgb565),  // %0
2253     "+r"(dst_y),       // %1
2254     "+r"(pix)          // %2
2255   :
2256   : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
2257   );
2258 }
2259
2260 void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int pix) {
2261   asm volatile (
2262     "vmov.u8    d24, #13                       \n"  // B * 0.1016 coefficient
2263     "vmov.u8    d25, #65                       \n"  // G * 0.5078 coefficient
2264     "vmov.u8    d26, #33                       \n"  // R * 0.2578 coefficient
2265     "vmov.u8    d27, #16                       \n"  // Add 16 constant
2266     ".p2align   2                              \n"
2267   "1:                                          \n"
2268     MEMACCESS(0)
2269     "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB1555 pixels.
2270     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2271     ARGB1555TOARGB
2272     "vmull.u8   q2, d0, d24                    \n"  // B
2273     "vmlal.u8   q2, d1, d25                    \n"  // G
2274     "vmlal.u8   q2, d2, d26                    \n"  // R
2275     "vqrshrun.s16 d0, q2, #7                   \n"  // 16 bit to 8 bit Y
2276     "vqadd.u8   d0, d27                        \n"
2277     MEMACCESS(1)
2278     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
2279     "bgt        1b                             \n"
2280   : "+r"(src_argb1555),  // %0
2281     "+r"(dst_y),         // %1
2282     "+r"(pix)            // %2
2283   :
2284   : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
2285   );
2286 }
2287
2288 void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int pix) {
2289   asm volatile (
2290     "vmov.u8    d24, #13                       \n"  // B * 0.1016 coefficient
2291     "vmov.u8    d25, #65                       \n"  // G * 0.5078 coefficient
2292     "vmov.u8    d26, #33                       \n"  // R * 0.2578 coefficient
2293     "vmov.u8    d27, #16                       \n"  // Add 16 constant
2294     ".p2align   2                              \n"
2295   "1:                                          \n"
2296     MEMACCESS(0)
2297     "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB4444 pixels.
2298     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2299     ARGB4444TOARGB
2300     "vmull.u8   q2, d0, d24                    \n"  // B
2301     "vmlal.u8   q2, d1, d25                    \n"  // G
2302     "vmlal.u8   q2, d2, d26                    \n"  // R
2303     "vqrshrun.s16 d0, q2, #7                   \n"  // 16 bit to 8 bit Y
2304     "vqadd.u8   d0, d27                        \n"
2305     MEMACCESS(1)
2306     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
2307     "bgt        1b                             \n"
2308   : "+r"(src_argb4444),  // %0
2309     "+r"(dst_y),         // %1
2310     "+r"(pix)            // %2
2311   :
2312   : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
2313   );
2314 }
2315
2316 void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int pix) {
2317   asm volatile (
2318     "vmov.u8    d4, #33                        \n"  // R * 0.2578 coefficient
2319     "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
2320     "vmov.u8    d6, #13                        \n"  // B * 0.1016 coefficient
2321     "vmov.u8    d7, #16                        \n"  // Add 16 constant
2322     ".p2align   2                              \n"
2323   "1:                                          \n"
2324     MEMACCESS(0)
2325     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of BGRA.
2326     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2327     "vmull.u8   q8, d1, d4                     \n"  // R
2328     "vmlal.u8   q8, d2, d5                     \n"  // G
2329     "vmlal.u8   q8, d3, d6                     \n"  // B
2330     "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
2331     "vqadd.u8   d0, d7                         \n"
2332     MEMACCESS(1)
2333     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
2334     "bgt        1b                             \n"
2335   : "+r"(src_bgra),  // %0
2336     "+r"(dst_y),     // %1
2337     "+r"(pix)        // %2
2338   :
2339   : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2340   );
2341 }
2342
2343 void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int pix) {
2344   asm volatile (
2345     "vmov.u8    d4, #33                        \n"  // R * 0.2578 coefficient
2346     "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
2347     "vmov.u8    d6, #13                        \n"  // B * 0.1016 coefficient
2348     "vmov.u8    d7, #16                        \n"  // Add 16 constant
2349     ".p2align   2                              \n"
2350   "1:                                          \n"
2351     MEMACCESS(0)
2352     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of ABGR.
2353     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2354     "vmull.u8   q8, d0, d4                     \n"  // R
2355     "vmlal.u8   q8, d1, d5                     \n"  // G
2356     "vmlal.u8   q8, d2, d6                     \n"  // B
2357     "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
2358     "vqadd.u8   d0, d7                         \n"
2359     MEMACCESS(1)
2360     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
2361     "bgt        1b                             \n"
2362   : "+r"(src_abgr),  // %0
2363     "+r"(dst_y),  // %1
2364     "+r"(pix)        // %2
2365   :
2366   : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2367   );
2368 }
2369
2370 void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int pix) {
2371   asm volatile (
2372     "vmov.u8    d4, #13                        \n"  // B * 0.1016 coefficient
2373     "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
2374     "vmov.u8    d6, #33                        \n"  // R * 0.2578 coefficient
2375     "vmov.u8    d7, #16                        \n"  // Add 16 constant
2376     ".p2align   2                              \n"
2377   "1:                                          \n"
2378     MEMACCESS(0)
2379     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of RGBA.
2380     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2381     "vmull.u8   q8, d1, d4                     \n"  // B
2382     "vmlal.u8   q8, d2, d5                     \n"  // G
2383     "vmlal.u8   q8, d3, d6                     \n"  // R
2384     "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
2385     "vqadd.u8   d0, d7                         \n"
2386     MEMACCESS(1)
2387     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
2388     "bgt        1b                             \n"
2389   : "+r"(src_rgba),  // %0
2390     "+r"(dst_y),  // %1
2391     "+r"(pix)        // %2
2392   :
2393   : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2394   );
2395 }
2396
2397 void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int pix) {
2398   asm volatile (
2399     "vmov.u8    d4, #13                        \n"  // B * 0.1016 coefficient
2400     "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
2401     "vmov.u8    d6, #33                        \n"  // R * 0.2578 coefficient
2402     "vmov.u8    d7, #16                        \n"  // Add 16 constant
2403     ".p2align   2                              \n"
2404   "1:                                          \n"
2405     MEMACCESS(0)
2406     "vld3.8     {d0, d1, d2}, [%0]!            \n"  // load 8 pixels of RGB24.
2407     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2408     "vmull.u8   q8, d0, d4                     \n"  // B
2409     "vmlal.u8   q8, d1, d5                     \n"  // G
2410     "vmlal.u8   q8, d2, d6                     \n"  // R
2411     "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
2412     "vqadd.u8   d0, d7                         \n"
2413     MEMACCESS(1)
2414     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
2415     "bgt        1b                             \n"
2416   : "+r"(src_rgb24),  // %0
2417     "+r"(dst_y),  // %1
2418     "+r"(pix)        // %2
2419   :
2420   : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2421   );
2422 }
2423
2424 void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int pix) {
2425   asm volatile (
2426     "vmov.u8    d4, #33                        \n"  // R * 0.2578 coefficient
2427     "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
2428     "vmov.u8    d6, #13                        \n"  // B * 0.1016 coefficient
2429     "vmov.u8    d7, #16                        \n"  // Add 16 constant
2430     ".p2align   2                              \n"
2431   "1:                                          \n"
2432     MEMACCESS(0)
2433     "vld3.8     {d0, d1, d2}, [%0]!            \n"  // load 8 pixels of RAW.
2434     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2435     "vmull.u8   q8, d0, d4                     \n"  // B
2436     "vmlal.u8   q8, d1, d5                     \n"  // G
2437     "vmlal.u8   q8, d2, d6                     \n"  // R
2438     "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
2439     "vqadd.u8   d0, d7                         \n"
2440     MEMACCESS(1)
2441     "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
2442     "bgt        1b                             \n"
2443   : "+r"(src_raw),  // %0
2444     "+r"(dst_y),  // %1
2445     "+r"(pix)        // %2
2446   :
2447   : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2448   );
2449 }
2450
2451 // Bilinear filter 16x2 -> 16x1
2452 void InterpolateRow_NEON(uint8* dst_ptr,
2453                          const uint8* src_ptr, ptrdiff_t src_stride,
2454                          int dst_width, int source_y_fraction) {
2455   asm volatile (
2456     "cmp        %4, #0                         \n"
2457     "beq        100f                           \n"
2458     "add        %2, %1                         \n"
2459     "cmp        %4, #64                        \n"
2460     "beq        75f                            \n"
2461     "cmp        %4, #128                       \n"
2462     "beq        50f                            \n"
2463     "cmp        %4, #192                       \n"
2464     "beq        25f                            \n"
2465
2466     "vdup.8     d5, %4                         \n"
2467     "rsb        %4, #256                       \n"
2468     "vdup.8     d4, %4                         \n"
2469     // General purpose row blend.
2470   "1:                                          \n"
2471     MEMACCESS(1)
2472     "vld1.8     {q0}, [%1]!                    \n"
2473     MEMACCESS(2)
2474     "vld1.8     {q1}, [%2]!                    \n"
2475     "subs       %3, %3, #16                    \n"
2476     "vmull.u8   q13, d0, d4                    \n"
2477     "vmull.u8   q14, d1, d4                    \n"
2478     "vmlal.u8   q13, d2, d5                    \n"
2479     "vmlal.u8   q14, d3, d5                    \n"
2480     "vrshrn.u16 d0, q13, #8                    \n"
2481     "vrshrn.u16 d1, q14, #8                    \n"
2482     MEMACCESS(0)
2483     "vst1.8     {q0}, [%0]!                    \n"
2484     "bgt        1b                             \n"
2485     "b          99f                            \n"
2486
2487     // Blend 25 / 75.
2488   "25:                                         \n"
2489     MEMACCESS(1)
2490     "vld1.8     {q0}, [%1]!                    \n"
2491     MEMACCESS(2)
2492     "vld1.8     {q1}, [%2]!                    \n"
2493     "subs       %3, %3, #16                    \n"
2494     "vrhadd.u8  q0, q1                         \n"
2495     "vrhadd.u8  q0, q1                         \n"
2496     MEMACCESS(0)
2497     "vst1.8     {q0}, [%0]!                    \n"
2498     "bgt        25b                            \n"
2499     "b          99f                            \n"
2500
2501     // Blend 50 / 50.
2502   "50:                                         \n"
2503     MEMACCESS(1)
2504     "vld1.8     {q0}, [%1]!                    \n"
2505     MEMACCESS(2)
2506     "vld1.8     {q1}, [%2]!                    \n"
2507     "subs       %3, %3, #16                    \n"
2508     "vrhadd.u8  q0, q1                         \n"
2509     MEMACCESS(0)
2510     "vst1.8     {q0}, [%0]!                    \n"
2511     "bgt        50b                            \n"
2512     "b          99f                            \n"
2513
2514     // Blend 75 / 25.
2515   "75:                                         \n"
2516     MEMACCESS(1)
2517     "vld1.8     {q1}, [%1]!                    \n"
2518     MEMACCESS(2)
2519     "vld1.8     {q0}, [%2]!                    \n"
2520     "subs       %3, %3, #16                    \n"
2521     "vrhadd.u8  q0, q1                         \n"
2522     "vrhadd.u8  q0, q1                         \n"
2523     MEMACCESS(0)
2524     "vst1.8     {q0}, [%0]!                    \n"
2525     "bgt        75b                            \n"
2526     "b          99f                            \n"
2527
2528     // Blend 100 / 0 - Copy row unchanged.
2529   "100:                                        \n"
2530     MEMACCESS(1)
2531     "vld1.8     {q0}, [%1]!                    \n"
2532     "subs       %3, %3, #16                    \n"
2533     MEMACCESS(0)
2534     "vst1.8     {q0}, [%0]!                    \n"
2535     "bgt        100b                           \n"
2536
2537   "99:                                         \n"
2538   : "+r"(dst_ptr),          // %0
2539     "+r"(src_ptr),          // %1
2540     "+r"(src_stride),       // %2
2541     "+r"(dst_width),        // %3
2542     "+r"(source_y_fraction) // %4
2543   :
2544   : "cc", "memory", "q0", "q1", "d4", "d5", "q13", "q14"
2545   );
2546 }
2547
2548 // dr * (256 - sa) / 256 + sr = dr - dr * sa / 256 + sr
2549 void ARGBBlendRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
2550                        uint8* dst_argb, int width) {
2551   asm volatile (
2552     "subs       %3, #8                         \n"
2553     "blt        89f                            \n"
2554     // Blend 8 pixels.
2555   "8:                                          \n"
2556     MEMACCESS(0)
2557     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of ARGB0.
2558     MEMACCESS(1)
2559     "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load 8 pixels of ARGB1.
2560     "subs       %3, %3, #8                     \n"  // 8 processed per loop.
2561     "vmull.u8   q10, d4, d3                    \n"  // db * a
2562     "vmull.u8   q11, d5, d3                    \n"  // dg * a
2563     "vmull.u8   q12, d6, d3                    \n"  // dr * a
2564     "vqrshrn.u16 d20, q10, #8                  \n"  // db >>= 8
2565     "vqrshrn.u16 d21, q11, #8                  \n"  // dg >>= 8
2566     "vqrshrn.u16 d22, q12, #8                  \n"  // dr >>= 8
2567     "vqsub.u8   q2, q2, q10                    \n"  // dbg - dbg * a / 256
2568     "vqsub.u8   d6, d6, d22                    \n"  // dr - dr * a / 256
2569     "vqadd.u8   q0, q0, q2                     \n"  // + sbg
2570     "vqadd.u8   d2, d2, d6                     \n"  // + sr
2571     "vmov.u8    d3, #255                       \n"  // a = 255
2572     MEMACCESS(2)
2573     "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 pixels of ARGB.
2574     "bge        8b                             \n"
2575
2576   "89:                                         \n"
2577     "adds       %3, #8-1                       \n"
2578     "blt        99f                            \n"
2579
2580     // Blend 1 pixels.
2581   "1:                                          \n"
2582     MEMACCESS(0)
2583     "vld4.8     {d0[0],d1[0],d2[0],d3[0]}, [%0]! \n"  // load 1 pixel ARGB0.
2584     MEMACCESS(1)
2585     "vld4.8     {d4[0],d5[0],d6[0],d7[0]}, [%1]! \n"  // load 1 pixel ARGB1.
2586     "subs       %3, %3, #1                     \n"  // 1 processed per loop.
2587     "vmull.u8   q10, d4, d3                    \n"  // db * a
2588     "vmull.u8   q11, d5, d3                    \n"  // dg * a
2589     "vmull.u8   q12, d6, d3                    \n"  // dr * a
2590     "vqrshrn.u16 d20, q10, #8                  \n"  // db >>= 8
2591     "vqrshrn.u16 d21, q11, #8                  \n"  // dg >>= 8
2592     "vqrshrn.u16 d22, q12, #8                  \n"  // dr >>= 8
2593     "vqsub.u8   q2, q2, q10                    \n"  // dbg - dbg * a / 256
2594     "vqsub.u8   d6, d6, d22                    \n"  // dr - dr * a / 256
2595     "vqadd.u8   q0, q0, q2                     \n"  // + sbg
2596     "vqadd.u8   d2, d2, d6                     \n"  // + sr
2597     "vmov.u8    d3, #255                       \n"  // a = 255
2598     MEMACCESS(2)
2599     "vst4.8     {d0[0],d1[0],d2[0],d3[0]}, [%2]! \n"  // store 1 pixel.
2600     "bge        1b                             \n"
2601
2602   "99:                                         \n"
2603
2604   : "+r"(src_argb0),    // %0
2605     "+r"(src_argb1),    // %1
2606     "+r"(dst_argb),     // %2
2607     "+r"(width)         // %3
2608   :
2609   : "cc", "memory", "q0", "q1", "q2", "q3", "q10", "q11", "q12"
2610   );
2611 }
2612
2613 // Attenuate 8 pixels at a time.
2614 void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) {
2615   asm volatile (
2616     // Attenuate 8 pixels.
2617   "1:                                          \n"
2618     MEMACCESS(0)
2619     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of ARGB.
2620     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2621     "vmull.u8   q10, d0, d3                    \n"  // b * a
2622     "vmull.u8   q11, d1, d3                    \n"  // g * a
2623     "vmull.u8   q12, d2, d3                    \n"  // r * a
2624     "vqrshrn.u16 d0, q10, #8                   \n"  // b >>= 8
2625     "vqrshrn.u16 d1, q11, #8                   \n"  // g >>= 8
2626     "vqrshrn.u16 d2, q12, #8                   \n"  // r >>= 8
2627     MEMACCESS(1)
2628     "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 pixels of ARGB.
2629     "bgt        1b                             \n"
2630   : "+r"(src_argb),   // %0
2631     "+r"(dst_argb),   // %1
2632     "+r"(width)       // %2
2633   :
2634   : "cc", "memory", "q0", "q1", "q10", "q11", "q12"
2635   );
2636 }
2637
2638 // Quantize 8 ARGB pixels (32 bytes).
2639 // dst = (dst * scale >> 16) * interval_size + interval_offset;
2640 void ARGBQuantizeRow_NEON(uint8* dst_argb, int scale, int interval_size,
2641                           int interval_offset, int width) {
2642   asm volatile (
2643     "vdup.u16   q8, %2                         \n"
2644     "vshr.u16   q8, q8, #1                     \n"  // scale >>= 1
2645     "vdup.u16   q9, %3                         \n"  // interval multiply.
2646     "vdup.u16   q10, %4                        \n"  // interval add
2647
2648     // 8 pixel loop.
2649     ".p2align   2                              \n"
2650   "1:                                          \n"
2651     MEMACCESS(0)
2652     "vld4.8     {d0, d2, d4, d6}, [%0]         \n"  // load 8 pixels of ARGB.
2653     "subs       %1, %1, #8                     \n"  // 8 processed per loop.
2654     "vmovl.u8   q0, d0                         \n"  // b (0 .. 255)
2655     "vmovl.u8   q1, d2                         \n"
2656     "vmovl.u8   q2, d4                         \n"
2657     "vqdmulh.s16 q0, q0, q8                    \n"  // b * scale
2658     "vqdmulh.s16 q1, q1, q8                    \n"  // g
2659     "vqdmulh.s16 q2, q2, q8                    \n"  // r
2660     "vmul.u16   q0, q0, q9                     \n"  // b * interval_size
2661     "vmul.u16   q1, q1, q9                     \n"  // g
2662     "vmul.u16   q2, q2, q9                     \n"  // r
2663     "vadd.u16   q0, q0, q10                    \n"  // b + interval_offset
2664     "vadd.u16   q1, q1, q10                    \n"  // g
2665     "vadd.u16   q2, q2, q10                    \n"  // r
2666     "vqmovn.u16 d0, q0                         \n"
2667     "vqmovn.u16 d2, q1                         \n"
2668     "vqmovn.u16 d4, q2                         \n"
2669     MEMACCESS(0)
2670     "vst4.8     {d0, d2, d4, d6}, [%0]!        \n"  // store 8 pixels of ARGB.
2671     "bgt        1b                             \n"
2672   : "+r"(dst_argb),       // %0
2673     "+r"(width)           // %1
2674   : "r"(scale),           // %2
2675     "r"(interval_size),   // %3
2676     "r"(interval_offset)  // %4
2677   : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10"
2678   );
2679 }
2680
2681 // Shade 8 pixels at a time by specified value.
2682 // NOTE vqrdmulh.s16 q10, q10, d0[0] must use a scaler register from 0 to 8.
2683 // Rounding in vqrdmulh does +1 to high if high bit of low s16 is set.
2684 void ARGBShadeRow_NEON(const uint8* src_argb, uint8* dst_argb, int width,
2685                        uint32 value) {
2686   asm volatile (
2687     "vdup.u32   q0, %3                         \n"  // duplicate scale value.
2688     "vzip.u8    d0, d1                         \n"  // d0 aarrggbb.
2689     "vshr.u16   q0, q0, #1                     \n"  // scale / 2.
2690
2691     // 8 pixel loop.
2692     ".p2align   2                              \n"
2693   "1:                                          \n"
2694     MEMACCESS(0)
2695     "vld4.8     {d20, d22, d24, d26}, [%0]!    \n"  // load 8 pixels of ARGB.
2696     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2697     "vmovl.u8   q10, d20                       \n"  // b (0 .. 255)
2698     "vmovl.u8   q11, d22                       \n"
2699     "vmovl.u8   q12, d24                       \n"
2700     "vmovl.u8   q13, d26                       \n"
2701     "vqrdmulh.s16 q10, q10, d0[0]              \n"  // b * scale * 2
2702     "vqrdmulh.s16 q11, q11, d0[1]              \n"  // g
2703     "vqrdmulh.s16 q12, q12, d0[2]              \n"  // r
2704     "vqrdmulh.s16 q13, q13, d0[3]              \n"  // a
2705     "vqmovn.u16 d20, q10                       \n"
2706     "vqmovn.u16 d22, q11                       \n"
2707     "vqmovn.u16 d24, q12                       \n"
2708     "vqmovn.u16 d26, q13                       \n"
2709     MEMACCESS(1)
2710     "vst4.8     {d20, d22, d24, d26}, [%1]!    \n"  // store 8 pixels of ARGB.
2711     "bgt        1b                             \n"
2712   : "+r"(src_argb),       // %0
2713     "+r"(dst_argb),       // %1
2714     "+r"(width)           // %2
2715   : "r"(value)            // %3
2716   : "cc", "memory", "q0", "q10", "q11", "q12", "q13"
2717   );
2718 }
2719
2720 // Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels
2721 // Similar to ARGBToYJ but stores ARGB.
2722 // C code is (15 * b + 75 * g + 38 * r + 64) >> 7;
2723 void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) {
2724   asm volatile (
2725     "vmov.u8    d24, #15                       \n"  // B * 0.11400 coefficient
2726     "vmov.u8    d25, #75                       \n"  // G * 0.58700 coefficient
2727     "vmov.u8    d26, #38                       \n"  // R * 0.29900 coefficient
2728     ".p2align   2                              \n"
2729   "1:                                          \n"
2730     MEMACCESS(0)
2731     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
2732     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2733     "vmull.u8   q2, d0, d24                    \n"  // B
2734     "vmlal.u8   q2, d1, d25                    \n"  // G
2735     "vmlal.u8   q2, d2, d26                    \n"  // R
2736     "vqrshrun.s16 d0, q2, #7                   \n"  // 15 bit to 8 bit B
2737     "vmov       d1, d0                         \n"  // G
2738     "vmov       d2, d0                         \n"  // R
2739     MEMACCESS(1)
2740     "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 ARGB pixels.
2741     "bgt        1b                             \n"
2742   : "+r"(src_argb),  // %0
2743     "+r"(dst_argb),  // %1
2744     "+r"(width)      // %2
2745   :
2746   : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
2747   );
2748 }
2749
2750 // Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels.
2751 //    b = (r * 35 + g * 68 + b * 17) >> 7
2752 //    g = (r * 45 + g * 88 + b * 22) >> 7
2753 //    r = (r * 50 + g * 98 + b * 24) >> 7
2754 void ARGBSepiaRow_NEON(uint8* dst_argb, int width) {
2755   asm volatile (
2756     "vmov.u8    d20, #17                       \n"  // BB coefficient
2757     "vmov.u8    d21, #68                       \n"  // BG coefficient
2758     "vmov.u8    d22, #35                       \n"  // BR coefficient
2759     "vmov.u8    d24, #22                       \n"  // GB coefficient
2760     "vmov.u8    d25, #88                       \n"  // GG coefficient
2761     "vmov.u8    d26, #45                       \n"  // GR coefficient
2762     "vmov.u8    d28, #24                       \n"  // BB coefficient
2763     "vmov.u8    d29, #98                       \n"  // BG coefficient
2764     "vmov.u8    d30, #50                       \n"  // BR coefficient
2765     ".p2align   2                              \n"
2766   "1:                                          \n"
2767     MEMACCESS(0)
2768     "vld4.8     {d0, d1, d2, d3}, [%0]         \n"  // load 8 ARGB pixels.
2769     "subs       %1, %1, #8                     \n"  // 8 processed per loop.
2770     "vmull.u8   q2, d0, d20                    \n"  // B to Sepia B
2771     "vmlal.u8   q2, d1, d21                    \n"  // G
2772     "vmlal.u8   q2, d2, d22                    \n"  // R
2773     "vmull.u8   q3, d0, d24                    \n"  // B to Sepia G
2774     "vmlal.u8   q3, d1, d25                    \n"  // G
2775     "vmlal.u8   q3, d2, d26                    \n"  // R
2776     "vmull.u8   q8, d0, d28                    \n"  // B to Sepia R
2777     "vmlal.u8   q8, d1, d29                    \n"  // G
2778     "vmlal.u8   q8, d2, d30                    \n"  // R
2779     "vqshrn.u16 d0, q2, #7                     \n"  // 16 bit to 8 bit B
2780     "vqshrn.u16 d1, q3, #7                     \n"  // 16 bit to 8 bit G
2781     "vqshrn.u16 d2, q8, #7                     \n"  // 16 bit to 8 bit R
2782     MEMACCESS(0)
2783     "vst4.8     {d0, d1, d2, d3}, [%0]!        \n"  // store 8 ARGB pixels.
2784     "bgt        1b                             \n"
2785   : "+r"(dst_argb),  // %0
2786     "+r"(width)      // %1
2787   :
2788   : "cc", "memory", "q0", "q1", "q2", "q3",
2789     "q10", "q11", "q12", "q13", "q14", "q15"
2790   );
2791 }
2792
2793 // Tranform 8 ARGB pixels (32 bytes) with color matrix.
2794 // TODO(fbarchard): Was same as Sepia except matrix is provided.  This function
2795 // needs to saturate.  Consider doing a non-saturating version.
2796 void ARGBColorMatrixRow_NEON(const uint8* src_argb, uint8* dst_argb,
2797                              const int8* matrix_argb, int width) {
2798   asm volatile (
2799     MEMACCESS(3)
2800     "vld1.8     {q2}, [%3]                     \n"  // load 3 ARGB vectors.
2801     "vmovl.s8   q0, d4                         \n"  // B,G coefficients s16.
2802     "vmovl.s8   q1, d5                         \n"  // R,A coefficients s16.
2803
2804     ".p2align   2                              \n"
2805   "1:                                          \n"
2806     MEMACCESS(0)
2807     "vld4.8     {d16, d18, d20, d22}, [%0]!    \n"  // load 8 ARGB pixels.
2808     "subs       %2, %2, #8                     \n"  // 8 processed per loop.
2809     "vmovl.u8   q8, d16                        \n"  // b (0 .. 255) 16 bit
2810     "vmovl.u8   q9, d18                        \n"  // g
2811     "vmovl.u8   q10, d20                       \n"  // r
2812     "vmovl.u8   q15, d22                       \n"  // a
2813     "vmul.s16   q12, q8, d0[0]                 \n"  // B = B * Matrix B
2814     "vmul.s16   q13, q8, d1[0]                 \n"  // G = B * Matrix G
2815     "vmul.s16   q14, q8, d2[0]                 \n"  // R = B * Matrix R
2816     "vmul.s16   q15, q8, d3[0]                 \n"  // A = B * Matrix A
2817     "vmul.s16   q4, q9, d0[1]                  \n"  // B += G * Matrix B
2818     "vmul.s16   q5, q9, d1[1]                  \n"  // G += G * Matrix G
2819     "vmul.s16   q6, q9, d2[1]                  \n"  // R += G * Matrix R
2820     "vmul.s16   q7, q9, d3[1]                  \n"  // A += G * Matrix A
2821     "vqadd.s16  q12, q12, q4                   \n"  // Accumulate B
2822     "vqadd.s16  q13, q13, q5                   \n"  // Accumulate G
2823     "vqadd.s16  q14, q14, q6                   \n"  // Accumulate R
2824     "vqadd.s16  q15, q15, q7                   \n"  // Accumulate A
2825     "vmul.s16   q4, q10, d0[2]                 \n"  // B += R * Matrix B
2826     "vmul.s16   q5, q10, d1[2]                 \n"  // G += R * Matrix G
2827     "vmul.s16   q6, q10, d2[2]                 \n"  // R += R * Matrix R
2828     "vmul.s16   q7, q10, d3[2]                 \n"  // A += R * Matrix A
2829     "vqadd.s16  q12, q12, q4                   \n"  // Accumulate B
2830     "vqadd.s16  q13, q13, q5                   \n"  // Accumulate G
2831     "vqadd.s16  q14, q14, q6                   \n"  // Accumulate R
2832     "vqadd.s16  q15, q15, q7                   \n"  // Accumulate A
2833     "vmul.s16   q4, q15, d0[3]                 \n"  // B += A * Matrix B
2834     "vmul.s16   q5, q15, d1[3]                 \n"  // G += A * Matrix G
2835     "vmul.s16   q6, q15, d2[3]                 \n"  // R += A * Matrix R
2836     "vmul.s16   q7, q15, d3[3]                 \n"  // A += A * Matrix A
2837     "vqadd.s16  q12, q12, q4                   \n"  // Accumulate B
2838     "vqadd.s16  q13, q13, q5                   \n"  // Accumulate G
2839     "vqadd.s16  q14, q14, q6                   \n"  // Accumulate R
2840     "vqadd.s16  q15, q15, q7                   \n"  // Accumulate A
2841     "vqshrun.s16 d16, q12, #6                  \n"  // 16 bit to 8 bit B
2842     "vqshrun.s16 d18, q13, #6                  \n"  // 16 bit to 8 bit G
2843     "vqshrun.s16 d20, q14, #6                  \n"  // 16 bit to 8 bit R
2844     "vqshrun.s16 d22, q15, #6                  \n"  // 16 bit to 8 bit A
2845     MEMACCESS(1)
2846     "vst4.8     {d16, d18, d20, d22}, [%1]!    \n"  // store 8 ARGB pixels.
2847     "bgt        1b                             \n"
2848   : "+r"(src_argb),   // %0
2849     "+r"(dst_argb),   // %1
2850     "+r"(width)       // %2
2851   : "r"(matrix_argb)  // %3
2852   : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
2853     "q10", "q11", "q12", "q13", "q14", "q15"
2854   );
2855 }
2856
2857 // TODO(fbarchard): fix vqshrun in ARGBMultiplyRow_NEON and reenable.
2858 #ifdef HAS_ARGBMULTIPLYROW_NEON
2859 // Multiply 2 rows of ARGB pixels together, 8 pixels at a time.
2860 void ARGBMultiplyRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
2861                           uint8* dst_argb, int width) {
2862   asm volatile (
2863     // 8 pixel loop.
2864     ".p2align   2                              \n"
2865   "1:                                          \n"
2866     MEMACCESS(0)
2867     "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
2868     MEMACCESS(1)
2869     "vld4.8     {d1, d3, d5, d7}, [%1]!        \n"  // load 8 more ARGB pixels.
2870     "subs       %3, %3, #8                     \n"  // 8 processed per loop.
2871     "vmull.u8   q0, d0, d1                     \n"  // multiply B
2872     "vmull.u8   q1, d2, d3                     \n"  // multiply G
2873     "vmull.u8   q2, d4, d5                     \n"  // multiply R
2874     "vmull.u8   q3, d6, d7                     \n"  // multiply A
2875     "vrshrn.u16 d0, q0, #8                     \n"  // 16 bit to 8 bit B
2876     "vrshrn.u16 d1, q1, #8                     \n"  // 16 bit to 8 bit G
2877     "vrshrn.u16 d2, q2, #8                     \n"  // 16 bit to 8 bit R
2878     "vrshrn.u16 d3, q3, #8                     \n"  // 16 bit to 8 bit A
2879     MEMACCESS(2)
2880     "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
2881     "bgt        1b                             \n"
2882
2883   : "+r"(src_argb0),  // %0
2884     "+r"(src_argb1),  // %1
2885     "+r"(dst_argb),   // %2
2886     "+r"(width)       // %3
2887   :
2888   : "cc", "memory", "q0", "q1", "q2", "q3"
2889   );
2890 }
2891 #endif  // HAS_ARGBMULTIPLYROW_NEON
2892
2893 // Add 2 rows of ARGB pixels together, 8 pixels at a time.
2894 void ARGBAddRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
2895                      uint8* dst_argb, int width) {
2896   asm volatile (
2897     // 8 pixel loop.
2898     ".p2align   2                              \n"
2899   "1:                                          \n"
2900     MEMACCESS(0)
2901     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
2902     MEMACCESS(1)
2903     "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load 8 more ARGB pixels.
2904     "subs       %3, %3, #8                     \n"  // 8 processed per loop.
2905     "vqadd.u8   q0, q0, q2                     \n"  // add B, G
2906     "vqadd.u8   q1, q1, q3                     \n"  // add R, A
2907     MEMACCESS(2)
2908     "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
2909     "bgt        1b                             \n"
2910
2911   : "+r"(src_argb0),  // %0
2912     "+r"(src_argb1),  // %1
2913     "+r"(dst_argb),   // %2
2914     "+r"(width)       // %3
2915   :
2916   : "cc", "memory", "q0", "q1", "q2", "q3"
2917   );
2918 }
2919
2920 // Subtract 2 rows of ARGB pixels, 8 pixels at a time.
2921 void ARGBSubtractRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
2922                           uint8* dst_argb, int width) {
2923   asm volatile (
2924     // 8 pixel loop.
2925     ".p2align   2                              \n"
2926   "1:                                          \n"
2927     MEMACCESS(0)
2928     "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
2929     MEMACCESS(1)
2930     "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load 8 more ARGB pixels.
2931     "subs       %3, %3, #8                     \n"  // 8 processed per loop.
2932     "vqsub.u8   q0, q0, q2                     \n"  // subtract B, G
2933     "vqsub.u8   q1, q1, q3                     \n"  // subtract R, A
2934     MEMACCESS(2)
2935     "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
2936     "bgt        1b                             \n"
2937
2938   : "+r"(src_argb0),  // %0
2939     "+r"(src_argb1),  // %1
2940     "+r"(dst_argb),   // %2
2941     "+r"(width)       // %3
2942   :
2943   : "cc", "memory", "q0", "q1", "q2", "q3"
2944   );
2945 }
2946
2947 // Adds Sobel X and Sobel Y and stores Sobel into ARGB.
2948 // A = 255
2949 // R = Sobel
2950 // G = Sobel
2951 // B = Sobel
2952 void SobelRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
2953                      uint8* dst_argb, int width) {
2954   asm volatile (
2955     "vmov.u8    d3, #255                       \n"  // alpha
2956     // 8 pixel loop.
2957     ".p2align   2                              \n"
2958   "1:                                          \n"
2959     MEMACCESS(0)
2960     "vld1.8     {d0}, [%0]!                    \n"  // load 8 sobelx.
2961     MEMACCESS(1)
2962     "vld1.8     {d1}, [%1]!                    \n"  // load 8 sobely.
2963     "subs       %3, %3, #8                     \n"  // 8 processed per loop.
2964     "vqadd.u8   d0, d0, d1                     \n"  // add
2965     "vmov.u8    d1, d0                         \n"
2966     "vmov.u8    d2, d0                         \n"
2967     MEMACCESS(2)
2968     "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
2969     "bgt        1b                             \n"
2970   : "+r"(src_sobelx),  // %0
2971     "+r"(src_sobely),  // %1
2972     "+r"(dst_argb),    // %2
2973     "+r"(width)        // %3
2974   :
2975   : "cc", "memory", "q0", "q1"
2976   );
2977 }
2978
2979 // Adds Sobel X and Sobel Y and stores Sobel into plane.
2980 void SobelToPlaneRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
2981                           uint8* dst_y, int width) {
2982   asm volatile (
2983     // 16 pixel loop.
2984     ".p2align   2                              \n"
2985   "1:                                          \n"
2986     MEMACCESS(0)
2987     "vld1.8     {q0}, [%0]!                    \n"  // load 16 sobelx.
2988     MEMACCESS(1)
2989     "vld1.8     {q1}, [%1]!                    \n"  // load 16 sobely.
2990     "subs       %3, %3, #16                    \n"  // 16 processed per loop.
2991     "vqadd.u8   q0, q0, q1                     \n"  // add
2992     MEMACCESS(2)
2993     "vst1.8     {q0}, [%2]!                    \n"  // store 16 pixels.
2994     "bgt        1b                             \n"
2995   : "+r"(src_sobelx),  // %0
2996     "+r"(src_sobely),  // %1
2997     "+r"(dst_y),       // %2
2998     "+r"(width)        // %3
2999   :
3000   : "cc", "memory", "q0", "q1"
3001   );
3002 }
3003
3004 // Mixes Sobel X, Sobel Y and Sobel into ARGB.
3005 // A = 255
3006 // R = Sobel X
3007 // G = Sobel
3008 // B = Sobel Y
3009 void SobelXYRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
3010                      uint8* dst_argb, int width) {
3011   asm volatile (
3012     "vmov.u8    d3, #255                       \n"  // alpha
3013     // 8 pixel loop.
3014     ".p2align   2                              \n"
3015   "1:                                          \n"
3016     MEMACCESS(0)
3017     "vld1.8     {d2}, [%0]!                    \n"  // load 8 sobelx.
3018     MEMACCESS(1)
3019     "vld1.8     {d0}, [%1]!                    \n"  // load 8 sobely.
3020     "subs       %3, %3, #8                     \n"  // 8 processed per loop.
3021     "vqadd.u8   d1, d0, d2                     \n"  // add
3022     MEMACCESS(2)
3023     "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
3024     "bgt        1b                             \n"
3025   : "+r"(src_sobelx),  // %0
3026     "+r"(src_sobely),  // %1
3027     "+r"(dst_argb),    // %2
3028     "+r"(width)        // %3
3029   :
3030   : "cc", "memory", "q0", "q1"
3031   );
3032 }
3033
3034 // SobelX as a matrix is
3035 // -1  0  1
3036 // -2  0  2
3037 // -1  0  1
3038 void SobelXRow_NEON(const uint8* src_y0, const uint8* src_y1,
3039                     const uint8* src_y2, uint8* dst_sobelx, int width) {
3040   asm volatile (
3041     ".p2align   2                              \n"
3042   "1:                                          \n"
3043     MEMACCESS(0)
3044     "vld1.8     {d0}, [%0],%5                  \n"  // top
3045     MEMACCESS(0)
3046     "vld1.8     {d1}, [%0],%6                  \n"
3047     "vsubl.u8   q0, d0, d1                     \n"
3048     MEMACCESS(1)
3049     "vld1.8     {d2}, [%1],%5                  \n"  // center * 2
3050     MEMACCESS(1)
3051     "vld1.8     {d3}, [%1],%6                  \n"
3052     "vsubl.u8   q1, d2, d3                     \n"
3053     "vadd.s16   q0, q0, q1                     \n"
3054     "vadd.s16   q0, q0, q1                     \n"
3055     MEMACCESS(2)
3056     "vld1.8     {d2}, [%2],%5                  \n"  // bottom
3057     MEMACCESS(2)
3058     "vld1.8     {d3}, [%2],%6                  \n"
3059     "subs       %4, %4, #8                     \n"  // 8 pixels
3060     "vsubl.u8   q1, d2, d3                     \n"
3061     "vadd.s16   q0, q0, q1                     \n"
3062     "vabs.s16   q0, q0                         \n"
3063     "vqmovn.u16 d0, q0                         \n"
3064     MEMACCESS(3)
3065     "vst1.8     {d0}, [%3]!                    \n"  // store 8 sobelx
3066     "bgt        1b                             \n"
3067   : "+r"(src_y0),      // %0
3068     "+r"(src_y1),      // %1
3069     "+r"(src_y2),      // %2
3070     "+r"(dst_sobelx),  // %3
3071     "+r"(width)        // %4
3072   : "r"(2),            // %5
3073     "r"(6)             // %6
3074   : "cc", "memory", "q0", "q1"  // Clobber List
3075   );
3076 }
3077
3078 // SobelY as a matrix is
3079 // -1 -2 -1
3080 //  0  0  0
3081 //  1  2  1
3082 void SobelYRow_NEON(const uint8* src_y0, const uint8* src_y1,
3083                     uint8* dst_sobely, int width) {
3084   asm volatile (
3085     ".p2align   2                              \n"
3086   "1:                                          \n"
3087     MEMACCESS(0)
3088     "vld1.8     {d0}, [%0],%4                  \n"  // left
3089     MEMACCESS(1)
3090     "vld1.8     {d1}, [%1],%4                  \n"
3091     "vsubl.u8   q0, d0, d1                     \n"
3092     MEMACCESS(0)
3093     "vld1.8     {d2}, [%0],%4                  \n"  // center * 2
3094     MEMACCESS(1)
3095     "vld1.8     {d3}, [%1],%4                  \n"
3096     "vsubl.u8   q1, d2, d3                     \n"
3097     "vadd.s16   q0, q0, q1                     \n"
3098     "vadd.s16   q0, q0, q1                     \n"
3099     MEMACCESS(0)
3100     "vld1.8     {d2}, [%0],%5                  \n"  // right
3101     MEMACCESS(1)
3102     "vld1.8     {d3}, [%1],%5                  \n"
3103     "subs       %3, %3, #8                     \n"  // 8 pixels
3104     "vsubl.u8   q1, d2, d3                     \n"
3105     "vadd.s16   q0, q0, q1                     \n"
3106     "vabs.s16   q0, q0                         \n"
3107     "vqmovn.u16 d0, q0                         \n"
3108     MEMACCESS(2)
3109     "vst1.8     {d0}, [%2]!                    \n"  // store 8 sobely
3110     "bgt        1b                             \n"
3111   : "+r"(src_y0),      // %0
3112     "+r"(src_y1),      // %1
3113     "+r"(dst_sobely),  // %2
3114     "+r"(width)        // %3
3115   : "r"(1),            // %4
3116     "r"(6)             // %5
3117   : "cc", "memory", "q0", "q1"  // Clobber List
3118   );
3119 }
3120 #endif  // defined(__ARM_NEON__) && !defined(__aarch64__)
3121
3122 #ifdef __cplusplus
3123 }  // extern "C"
3124 }  // namespace libyuv
3125 #endif