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