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