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