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