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