media/libyuv/source/row_neon.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/libyuv/source/row_neon.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2844 @@
     1.4 +/*
     1.5 + *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
     1.6 + *
     1.7 + *  Use of this source code is governed by a BSD-style license
     1.8 + *  that can be found in the LICENSE file in the root of the source
     1.9 + *  tree. An additional intellectual property rights grant can be found
    1.10 + *  in the file PATENTS. All contributing project authors may
    1.11 + *  be found in the AUTHORS file in the root of the source tree.
    1.12 + */
    1.13 +
    1.14 +#include "libyuv/row.h"
    1.15 +
    1.16 +#ifdef __cplusplus
    1.17 +namespace libyuv {
    1.18 +extern "C" {
    1.19 +#endif
    1.20 +
    1.21 +// This module is for GCC Neon
    1.22 +#if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)
    1.23 +
    1.24 +// Read 8 Y, 4 U and 4 V from 422
    1.25 +#define READYUV422                                                             \
    1.26 +    "vld1.8     {d0}, [%0]!                    \n"                             \
    1.27 +    "vld1.32    {d2[0]}, [%1]!                 \n"                             \
    1.28 +    "vld1.32    {d2[1]}, [%2]!                 \n"
    1.29 +
    1.30 +// Read 8 Y, 2 U and 2 V from 422
    1.31 +#define READYUV411                                                             \
    1.32 +    "vld1.8     {d0}, [%0]!                    \n"                             \
    1.33 +    "vld1.16    {d2[0]}, [%1]!                 \n"                             \
    1.34 +    "vld1.16    {d2[1]}, [%2]!                 \n"                             \
    1.35 +    "vmov.u8    d3, d2                         \n"                             \
    1.36 +    "vzip.u8    d2, d3                         \n"
    1.37 +
    1.38 +// Read 8 Y, 8 U and 8 V from 444
    1.39 +#define READYUV444                                                             \
    1.40 +    "vld1.8     {d0}, [%0]!                    \n"                             \
    1.41 +    "vld1.8     {d2}, [%1]!                    \n"                             \
    1.42 +    "vld1.8     {d3}, [%2]!                    \n"                             \
    1.43 +    "vpaddl.u8  q1, q1                         \n"                             \
    1.44 +    "vrshrn.u16 d2, q1, #1                     \n"
    1.45 +
    1.46 +// Read 8 Y, and set 4 U and 4 V to 128
    1.47 +#define READYUV400                                                             \
    1.48 +    "vld1.8     {d0}, [%0]!                    \n"                             \
    1.49 +    "vmov.u8    d2, #128                       \n"
    1.50 +
    1.51 +// Read 8 Y and 4 UV from NV12
    1.52 +#define READNV12                                                               \
    1.53 +    "vld1.8     {d0}, [%0]!                    \n"                             \
    1.54 +    "vld1.8     {d2}, [%1]!                    \n"                             \
    1.55 +    "vmov.u8    d3, d2                         \n"/* split odd/even uv apart */\
    1.56 +    "vuzp.u8    d2, d3                         \n"                             \
    1.57 +    "vtrn.u32   d2, d3                         \n"
    1.58 +
    1.59 +// Read 8 Y and 4 VU from NV21
    1.60 +#define READNV21                                                               \
    1.61 +    "vld1.8     {d0}, [%0]!                    \n"                             \
    1.62 +    "vld1.8     {d2}, [%1]!                    \n"                             \
    1.63 +    "vmov.u8    d3, d2                         \n"/* split odd/even uv apart */\
    1.64 +    "vuzp.u8    d3, d2                         \n"                             \
    1.65 +    "vtrn.u32   d2, d3                         \n"
    1.66 +
    1.67 +// Read 8 YUY2
    1.68 +#define READYUY2                                                               \
    1.69 +    "vld2.8     {d0, d2}, [%0]!                \n"                             \
    1.70 +    "vmov.u8    d3, d2                         \n"                             \
    1.71 +    "vuzp.u8    d2, d3                         \n"                             \
    1.72 +    "vtrn.u32   d2, d3                         \n"
    1.73 +
    1.74 +// Read 8 UYVY
    1.75 +#define READUYVY                                                               \
    1.76 +    "vld2.8     {d2, d3}, [%0]!                \n"                             \
    1.77 +    "vmov.u8    d0, d3                         \n"                             \
    1.78 +    "vmov.u8    d3, d2                         \n"                             \
    1.79 +    "vuzp.u8    d2, d3                         \n"                             \
    1.80 +    "vtrn.u32   d2, d3                         \n"
    1.81 +
    1.82 +#define YUV422TORGB                                                            \
    1.83 +    "veor.u8    d2, d26                        \n"/*subtract 128 from u and v*/\
    1.84 +    "vmull.s8   q8, d2, d24                    \n"/*  u/v B/R component      */\
    1.85 +    "vmull.s8   q9, d2, d25                    \n"/*  u/v G component        */\
    1.86 +    "vmov.u8    d1, #0                         \n"/*  split odd/even y apart */\
    1.87 +    "vtrn.u8    d0, d1                         \n"                             \
    1.88 +    "vsub.s16   q0, q0, q15                    \n"/*  offset y               */\
    1.89 +    "vmul.s16   q0, q0, q14                    \n"                             \
    1.90 +    "vadd.s16   d18, d19                       \n"                             \
    1.91 +    "vqadd.s16  d20, d0, d16                   \n" /* B */                     \
    1.92 +    "vqadd.s16  d21, d1, d16                   \n"                             \
    1.93 +    "vqadd.s16  d22, d0, d17                   \n" /* R */                     \
    1.94 +    "vqadd.s16  d23, d1, d17                   \n"                             \
    1.95 +    "vqadd.s16  d16, d0, d18                   \n" /* G */                     \
    1.96 +    "vqadd.s16  d17, d1, d18                   \n"                             \
    1.97 +    "vqshrun.s16 d0, q10, #6                   \n" /* B */                     \
    1.98 +    "vqshrun.s16 d1, q11, #6                   \n" /* G */                     \
    1.99 +    "vqshrun.s16 d2, q8, #6                    \n" /* R */                     \
   1.100 +    "vmovl.u8   q10, d0                        \n"/*  set up for reinterleave*/\
   1.101 +    "vmovl.u8   q11, d1                        \n"                             \
   1.102 +    "vmovl.u8   q8, d2                         \n"                             \
   1.103 +    "vtrn.u8    d20, d21                       \n"                             \
   1.104 +    "vtrn.u8    d22, d23                       \n"                             \
   1.105 +    "vtrn.u8    d16, d17                       \n"                             \
   1.106 +    "vmov.u8    d21, d16                       \n"
   1.107 +
   1.108 +static vec8 kUVToRB  = { 127, 127, 127, 127, 102, 102, 102, 102,
   1.109 +                         0, 0, 0, 0, 0, 0, 0, 0 };
   1.110 +static vec8 kUVToG = { -25, -25, -25, -25, -52, -52, -52, -52,
   1.111 +                       0, 0, 0, 0, 0, 0, 0, 0 };
   1.112 +
   1.113 +void I444ToARGBRow_NEON(const uint8* src_y,
   1.114 +                        const uint8* src_u,
   1.115 +                        const uint8* src_v,
   1.116 +                        uint8* dst_argb,
   1.117 +                        int width) {
   1.118 +  asm volatile (
   1.119 +    "vld1.8     {d24}, [%5]                    \n"
   1.120 +    "vld1.8     {d25}, [%6]                    \n"
   1.121 +    "vmov.u8    d26, #128                      \n"
   1.122 +    "vmov.u16   q14, #74                       \n"
   1.123 +    "vmov.u16   q15, #16                       \n"
   1.124 +    ".p2align   2                              \n"
   1.125 +  "1:                                          \n"
   1.126 +    READYUV444
   1.127 +    YUV422TORGB
   1.128 +    "subs       %4, %4, #8                     \n"
   1.129 +    "vmov.u8    d23, #255                      \n"
   1.130 +    "vst4.8     {d20, d21, d22, d23}, [%3]!    \n"
   1.131 +    "bgt        1b                             \n"
   1.132 +    : "+r"(src_y),     // %0
   1.133 +      "+r"(src_u),     // %1
   1.134 +      "+r"(src_v),     // %2
   1.135 +      "+r"(dst_argb),  // %3
   1.136 +      "+r"(width)      // %4
   1.137 +    : "r"(&kUVToRB),   // %5
   1.138 +      "r"(&kUVToG)     // %6
   1.139 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.140 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.141 +  );
   1.142 +}
   1.143 +
   1.144 +void I422ToARGBRow_NEON(const uint8* src_y,
   1.145 +                        const uint8* src_u,
   1.146 +                        const uint8* src_v,
   1.147 +                        uint8* dst_argb,
   1.148 +                        int width) {
   1.149 +  asm volatile (
   1.150 +    "vld1.8     {d24}, [%5]                    \n"
   1.151 +    "vld1.8     {d25}, [%6]                    \n"
   1.152 +    "vmov.u8    d26, #128                      \n"
   1.153 +    "vmov.u16   q14, #74                       \n"
   1.154 +    "vmov.u16   q15, #16                       \n"
   1.155 +    ".p2align   2                              \n"
   1.156 +  "1:                                          \n"
   1.157 +    READYUV422
   1.158 +    YUV422TORGB
   1.159 +    "subs       %4, %4, #8                     \n"
   1.160 +    "vmov.u8    d23, #255                      \n"
   1.161 +    "vst4.8     {d20, d21, d22, d23}, [%3]!    \n"
   1.162 +    "bgt        1b                             \n"
   1.163 +    : "+r"(src_y),     // %0
   1.164 +      "+r"(src_u),     // %1
   1.165 +      "+r"(src_v),     // %2
   1.166 +      "+r"(dst_argb),  // %3
   1.167 +      "+r"(width)      // %4
   1.168 +    : "r"(&kUVToRB),   // %5
   1.169 +      "r"(&kUVToG)     // %6
   1.170 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.171 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.172 +  );
   1.173 +}
   1.174 +
   1.175 +void I411ToARGBRow_NEON(const uint8* src_y,
   1.176 +                        const uint8* src_u,
   1.177 +                        const uint8* src_v,
   1.178 +                        uint8* dst_argb,
   1.179 +                        int width) {
   1.180 +  asm volatile (
   1.181 +    "vld1.8     {d24}, [%5]                    \n"
   1.182 +    "vld1.8     {d25}, [%6]                    \n"
   1.183 +    "vmov.u8    d26, #128                      \n"
   1.184 +    "vmov.u16   q14, #74                       \n"
   1.185 +    "vmov.u16   q15, #16                       \n"
   1.186 +    ".p2align   2                              \n"
   1.187 +  "1:                                          \n"
   1.188 +    READYUV411
   1.189 +    YUV422TORGB
   1.190 +    "subs       %4, %4, #8                     \n"
   1.191 +    "vmov.u8    d23, #255                      \n"
   1.192 +    "vst4.8     {d20, d21, d22, d23}, [%3]!    \n"
   1.193 +    "bgt        1b                             \n"
   1.194 +    : "+r"(src_y),     // %0
   1.195 +      "+r"(src_u),     // %1
   1.196 +      "+r"(src_v),     // %2
   1.197 +      "+r"(dst_argb),  // %3
   1.198 +      "+r"(width)      // %4
   1.199 +    : "r"(&kUVToRB),   // %5
   1.200 +      "r"(&kUVToG)     // %6
   1.201 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.202 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.203 +  );
   1.204 +}
   1.205 +
   1.206 +void I422ToBGRARow_NEON(const uint8* src_y,
   1.207 +                        const uint8* src_u,
   1.208 +                        const uint8* src_v,
   1.209 +                        uint8* dst_bgra,
   1.210 +                        int width) {
   1.211 +  asm volatile (
   1.212 +    "vld1.8     {d24}, [%5]                    \n"
   1.213 +    "vld1.8     {d25}, [%6]                    \n"
   1.214 +    "vmov.u8    d26, #128                      \n"
   1.215 +    "vmov.u16   q14, #74                       \n"
   1.216 +    "vmov.u16   q15, #16                       \n"
   1.217 +    ".p2align   2                              \n"
   1.218 +  "1:                                          \n"
   1.219 +    READYUV422
   1.220 +    YUV422TORGB
   1.221 +    "subs       %4, %4, #8                     \n"
   1.222 +    "vswp.u8    d20, d22                       \n"
   1.223 +    "vmov.u8    d19, #255                      \n"
   1.224 +    "vst4.8     {d19, d20, d21, d22}, [%3]!    \n"
   1.225 +    "bgt        1b                             \n"
   1.226 +    : "+r"(src_y),     // %0
   1.227 +      "+r"(src_u),     // %1
   1.228 +      "+r"(src_v),     // %2
   1.229 +      "+r"(dst_bgra),  // %3
   1.230 +      "+r"(width)      // %4
   1.231 +    : "r"(&kUVToRB),   // %5
   1.232 +      "r"(&kUVToG)     // %6
   1.233 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.234 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.235 +  );
   1.236 +}
   1.237 +
   1.238 +void I422ToABGRRow_NEON(const uint8* src_y,
   1.239 +                        const uint8* src_u,
   1.240 +                        const uint8* src_v,
   1.241 +                        uint8* dst_abgr,
   1.242 +                        int width) {
   1.243 +  asm volatile (
   1.244 +    "vld1.8     {d24}, [%5]                    \n"
   1.245 +    "vld1.8     {d25}, [%6]                    \n"
   1.246 +    "vmov.u8    d26, #128                      \n"
   1.247 +    "vmov.u16   q14, #74                       \n"
   1.248 +    "vmov.u16   q15, #16                       \n"
   1.249 +    ".p2align   2                              \n"
   1.250 +  "1:                                          \n"
   1.251 +    READYUV422
   1.252 +    YUV422TORGB
   1.253 +    "subs       %4, %4, #8                     \n"
   1.254 +    "vswp.u8    d20, d22                       \n"
   1.255 +    "vmov.u8    d23, #255                      \n"
   1.256 +    "vst4.8     {d20, d21, d22, d23}, [%3]!    \n"
   1.257 +    "bgt        1b                             \n"
   1.258 +    : "+r"(src_y),     // %0
   1.259 +      "+r"(src_u),     // %1
   1.260 +      "+r"(src_v),     // %2
   1.261 +      "+r"(dst_abgr),  // %3
   1.262 +      "+r"(width)      // %4
   1.263 +    : "r"(&kUVToRB),   // %5
   1.264 +      "r"(&kUVToG)     // %6
   1.265 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.266 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.267 +  );
   1.268 +}
   1.269 +
   1.270 +void I422ToRGBARow_NEON(const uint8* src_y,
   1.271 +                        const uint8* src_u,
   1.272 +                        const uint8* src_v,
   1.273 +                        uint8* dst_rgba,
   1.274 +                        int width) {
   1.275 +  asm volatile (
   1.276 +    "vld1.8     {d24}, [%5]                    \n"
   1.277 +    "vld1.8     {d25}, [%6]                    \n"
   1.278 +    "vmov.u8    d26, #128                      \n"
   1.279 +    "vmov.u16   q14, #74                       \n"
   1.280 +    "vmov.u16   q15, #16                       \n"
   1.281 +    ".p2align   2                              \n"
   1.282 +  "1:                                          \n"
   1.283 +    READYUV422
   1.284 +    YUV422TORGB
   1.285 +    "subs       %4, %4, #8                     \n"
   1.286 +    "vmov.u8    d19, #255                      \n"
   1.287 +    "vst4.8     {d19, d20, d21, d22}, [%3]!    \n"
   1.288 +    "bgt        1b                             \n"
   1.289 +    : "+r"(src_y),     // %0
   1.290 +      "+r"(src_u),     // %1
   1.291 +      "+r"(src_v),     // %2
   1.292 +      "+r"(dst_rgba),  // %3
   1.293 +      "+r"(width)      // %4
   1.294 +    : "r"(&kUVToRB),   // %5
   1.295 +      "r"(&kUVToG)     // %6
   1.296 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.297 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.298 +  );
   1.299 +}
   1.300 +
   1.301 +void I422ToRGB24Row_NEON(const uint8* src_y,
   1.302 +                         const uint8* src_u,
   1.303 +                         const uint8* src_v,
   1.304 +                         uint8* dst_rgb24,
   1.305 +                         int width) {
   1.306 +  asm volatile (
   1.307 +    "vld1.8     {d24}, [%5]                    \n"
   1.308 +    "vld1.8     {d25}, [%6]                    \n"
   1.309 +    "vmov.u8    d26, #128                      \n"
   1.310 +    "vmov.u16   q14, #74                       \n"
   1.311 +    "vmov.u16   q15, #16                       \n"
   1.312 +    ".p2align   2                              \n"
   1.313 +  "1:                                          \n"
   1.314 +    READYUV422
   1.315 +    YUV422TORGB
   1.316 +    "subs       %4, %4, #8                     \n"
   1.317 +    "vst3.8     {d20, d21, d22}, [%3]!         \n"
   1.318 +    "bgt        1b                             \n"
   1.319 +    : "+r"(src_y),      // %0
   1.320 +      "+r"(src_u),      // %1
   1.321 +      "+r"(src_v),      // %2
   1.322 +      "+r"(dst_rgb24),  // %3
   1.323 +      "+r"(width)       // %4
   1.324 +    : "r"(&kUVToRB),    // %5
   1.325 +      "r"(&kUVToG)      // %6
   1.326 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.327 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.328 +  );
   1.329 +}
   1.330 +
   1.331 +void I422ToRAWRow_NEON(const uint8* src_y,
   1.332 +                       const uint8* src_u,
   1.333 +                       const uint8* src_v,
   1.334 +                       uint8* dst_raw,
   1.335 +                       int width) {
   1.336 +  asm volatile (
   1.337 +    "vld1.8     {d24}, [%5]                    \n"
   1.338 +    "vld1.8     {d25}, [%6]                    \n"
   1.339 +    "vmov.u8    d26, #128                      \n"
   1.340 +    "vmov.u16   q14, #74                       \n"
   1.341 +    "vmov.u16   q15, #16                       \n"
   1.342 +    ".p2align   2                              \n"
   1.343 +  "1:                                          \n"
   1.344 +    READYUV422
   1.345 +    YUV422TORGB
   1.346 +    "subs       %4, %4, #8                     \n"
   1.347 +    "vswp.u8    d20, d22                       \n"
   1.348 +    "vst3.8     {d20, d21, d22}, [%3]!         \n"
   1.349 +    "bgt        1b                             \n"
   1.350 +    : "+r"(src_y),    // %0
   1.351 +      "+r"(src_u),    // %1
   1.352 +      "+r"(src_v),    // %2
   1.353 +      "+r"(dst_raw),  // %3
   1.354 +      "+r"(width)     // %4
   1.355 +    : "r"(&kUVToRB),  // %5
   1.356 +      "r"(&kUVToG)    // %6
   1.357 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.358 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.359 +  );
   1.360 +}
   1.361 +
   1.362 +#define ARGBTORGB565                                                           \
   1.363 +    "vshr.u8    d20, d20, #3                   \n"  /* B                    */ \
   1.364 +    "vshr.u8    d21, d21, #2                   \n"  /* G                    */ \
   1.365 +    "vshr.u8    d22, d22, #3                   \n"  /* R                    */ \
   1.366 +    "vmovl.u8   q8, d20                        \n"  /* B                    */ \
   1.367 +    "vmovl.u8   q9, d21                        \n"  /* G                    */ \
   1.368 +    "vmovl.u8   q10, d22                       \n"  /* R                    */ \
   1.369 +    "vshl.u16   q9, q9, #5                     \n"  /* G                    */ \
   1.370 +    "vshl.u16   q10, q10, #11                  \n"  /* R                    */ \
   1.371 +    "vorr       q0, q8, q9                     \n"  /* BG                   */ \
   1.372 +    "vorr       q0, q0, q10                    \n"  /* BGR                  */
   1.373 +
   1.374 +void I422ToRGB565Row_NEON(const uint8* src_y,
   1.375 +                          const uint8* src_u,
   1.376 +                          const uint8* src_v,
   1.377 +                          uint8* dst_rgb565,
   1.378 +                          int width) {
   1.379 +  asm volatile (
   1.380 +    "vld1.8     {d24}, [%5]                    \n"
   1.381 +    "vld1.8     {d25}, [%6]                    \n"
   1.382 +    "vmov.u8    d26, #128                      \n"
   1.383 +    "vmov.u16   q14, #74                       \n"
   1.384 +    "vmov.u16   q15, #16                       \n"
   1.385 +    ".p2align   2                              \n"
   1.386 +  "1:                                          \n"
   1.387 +    READYUV422
   1.388 +    YUV422TORGB
   1.389 +    "subs       %4, %4, #8                     \n"
   1.390 +    ARGBTORGB565
   1.391 +    "vst1.8     {q0}, [%3]!                    \n"  // store 8 pixels RGB565.
   1.392 +    "bgt        1b                             \n"
   1.393 +    : "+r"(src_y),    // %0
   1.394 +      "+r"(src_u),    // %1
   1.395 +      "+r"(src_v),    // %2
   1.396 +      "+r"(dst_rgb565),  // %3
   1.397 +      "+r"(width)     // %4
   1.398 +    : "r"(&kUVToRB),  // %5
   1.399 +      "r"(&kUVToG)    // %6
   1.400 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.401 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.402 +  );
   1.403 +}
   1.404 +
   1.405 +#define ARGBTOARGB1555                                                         \
   1.406 +    "vshr.u8    q10, q10, #3                   \n"  /* B                    */ \
   1.407 +    "vshr.u8    d22, d22, #3                   \n"  /* R                    */ \
   1.408 +    "vshr.u8    d23, d23, #7                   \n"  /* A                    */ \
   1.409 +    "vmovl.u8   q8, d20                        \n"  /* B                    */ \
   1.410 +    "vmovl.u8   q9, d21                        \n"  /* G                    */ \
   1.411 +    "vmovl.u8   q10, d22                       \n"  /* R                    */ \
   1.412 +    "vmovl.u8   q11, d23                       \n"  /* A                    */ \
   1.413 +    "vshl.u16   q9, q9, #5                     \n"  /* G                    */ \
   1.414 +    "vshl.u16   q10, q10, #10                  \n"  /* R                    */ \
   1.415 +    "vshl.u16   q11, q11, #15                  \n"  /* A                    */ \
   1.416 +    "vorr       q0, q8, q9                     \n"  /* BG                   */ \
   1.417 +    "vorr       q1, q10, q11                   \n"  /* RA                   */ \
   1.418 +    "vorr       q0, q0, q1                     \n"  /* BGRA                 */
   1.419 +
   1.420 +void I422ToARGB1555Row_NEON(const uint8* src_y,
   1.421 +                            const uint8* src_u,
   1.422 +                            const uint8* src_v,
   1.423 +                            uint8* dst_argb1555,
   1.424 +                            int width) {
   1.425 +  asm volatile (
   1.426 +    "vld1.8     {d24}, [%5]                    \n"
   1.427 +    "vld1.8     {d25}, [%6]                    \n"
   1.428 +    "vmov.u8    d26, #128                      \n"
   1.429 +    "vmov.u16   q14, #74                       \n"
   1.430 +    "vmov.u16   q15, #16                       \n"
   1.431 +    ".p2align   2                              \n"
   1.432 +  "1:                                          \n"
   1.433 +    READYUV422
   1.434 +    YUV422TORGB
   1.435 +    "subs       %4, %4, #8                     \n"
   1.436 +    "vmov.u8    d23, #255                      \n"
   1.437 +    ARGBTOARGB1555
   1.438 +    "vst1.8     {q0}, [%3]!                    \n"  // store 8 pixels ARGB1555.
   1.439 +    "bgt        1b                             \n"
   1.440 +    : "+r"(src_y),    // %0
   1.441 +      "+r"(src_u),    // %1
   1.442 +      "+r"(src_v),    // %2
   1.443 +      "+r"(dst_argb1555),  // %3
   1.444 +      "+r"(width)     // %4
   1.445 +    : "r"(&kUVToRB),  // %5
   1.446 +      "r"(&kUVToG)    // %6
   1.447 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.448 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.449 +  );
   1.450 +}
   1.451 +
   1.452 +#define ARGBTOARGB4444                                                         \
   1.453 +    "vshr.u8    d20, d20, #4                   \n"  /* B                    */ \
   1.454 +    "vbic.32    d21, d21, d4                   \n"  /* G                    */ \
   1.455 +    "vshr.u8    d22, d22, #4                   \n"  /* R                    */ \
   1.456 +    "vbic.32    d23, d23, d4                   \n"  /* A                    */ \
   1.457 +    "vorr       d0, d20, d21                   \n"  /* BG                   */ \
   1.458 +    "vorr       d1, d22, d23                   \n"  /* RA                   */ \
   1.459 +    "vzip.u8    d0, d1                         \n"  /* BGRA                 */
   1.460 +
   1.461 +void I422ToARGB4444Row_NEON(const uint8* src_y,
   1.462 +                            const uint8* src_u,
   1.463 +                            const uint8* src_v,
   1.464 +                            uint8* dst_argb4444,
   1.465 +                            int width) {
   1.466 +  asm volatile (
   1.467 +    "vld1.8     {d24}, [%5]                    \n"
   1.468 +    "vld1.8     {d25}, [%6]                    \n"
   1.469 +    "vmov.u8    d26, #128                      \n"
   1.470 +    "vmov.u16   q14, #74                       \n"
   1.471 +    "vmov.u16   q15, #16                       \n"
   1.472 +    "vmov.u8    d4, #0x0f                      \n"  // bits to clear with vbic.
   1.473 +    ".p2align   2                              \n"
   1.474 +  "1:                                          \n"
   1.475 +    READYUV422
   1.476 +    YUV422TORGB
   1.477 +    "subs       %4, %4, #8                     \n"
   1.478 +    "vmov.u8    d23, #255                      \n"
   1.479 +    ARGBTOARGB4444
   1.480 +    "vst1.8     {q0}, [%3]!                    \n"  // store 8 pixels ARGB4444.
   1.481 +    "bgt        1b                             \n"
   1.482 +    : "+r"(src_y),    // %0
   1.483 +      "+r"(src_u),    // %1
   1.484 +      "+r"(src_v),    // %2
   1.485 +      "+r"(dst_argb4444),  // %3
   1.486 +      "+r"(width)     // %4
   1.487 +    : "r"(&kUVToRB),  // %5
   1.488 +      "r"(&kUVToG)    // %6
   1.489 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.490 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.491 +  );
   1.492 +}
   1.493 +
   1.494 +void YToARGBRow_NEON(const uint8* src_y,
   1.495 +                     uint8* dst_argb,
   1.496 +                     int width) {
   1.497 +  asm volatile (
   1.498 +    "vld1.8     {d24}, [%3]                    \n"
   1.499 +    "vld1.8     {d25}, [%4]                    \n"
   1.500 +    "vmov.u8    d26, #128                      \n"
   1.501 +    "vmov.u16   q14, #74                       \n"
   1.502 +    "vmov.u16   q15, #16                       \n"
   1.503 +    ".p2align   2                              \n"
   1.504 +  "1:                                          \n"
   1.505 +    READYUV400
   1.506 +    YUV422TORGB
   1.507 +    "subs       %2, %2, #8                     \n"
   1.508 +    "vmov.u8    d23, #255                      \n"
   1.509 +    "vst4.8     {d20, d21, d22, d23}, [%1]!    \n"
   1.510 +    "bgt        1b                             \n"
   1.511 +    : "+r"(src_y),     // %0
   1.512 +      "+r"(dst_argb),  // %1
   1.513 +      "+r"(width)      // %2
   1.514 +    : "r"(&kUVToRB),   // %3
   1.515 +      "r"(&kUVToG)     // %4
   1.516 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.517 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.518 +  );
   1.519 +}
   1.520 +
   1.521 +void I400ToARGBRow_NEON(const uint8* src_y,
   1.522 +                        uint8* dst_argb,
   1.523 +                        int width) {
   1.524 +  asm volatile (
   1.525 +    ".p2align   2                              \n"
   1.526 +    "vmov.u8    d23, #255                      \n"
   1.527 +  "1:                                          \n"
   1.528 +    "vld1.8     {d20}, [%0]!                   \n"
   1.529 +    "vmov       d21, d20                       \n"
   1.530 +    "vmov       d22, d20                       \n"
   1.531 +    "subs       %2, %2, #8                     \n"
   1.532 +    "vst4.8     {d20, d21, d22, d23}, [%1]!    \n"
   1.533 +    "bgt        1b                             \n"
   1.534 +    : "+r"(src_y),     // %0
   1.535 +      "+r"(dst_argb),  // %1
   1.536 +      "+r"(width)      // %2
   1.537 +    :
   1.538 +    : "cc", "memory", "d20", "d21", "d22", "d23"
   1.539 +  );
   1.540 +}
   1.541 +
   1.542 +void NV12ToARGBRow_NEON(const uint8* src_y,
   1.543 +                        const uint8* src_uv,
   1.544 +                        uint8* dst_argb,
   1.545 +                        int width) {
   1.546 +  asm volatile (
   1.547 +    "vld1.8     {d24}, [%4]                    \n"
   1.548 +    "vld1.8     {d25}, [%5]                    \n"
   1.549 +    "vmov.u8    d26, #128                      \n"
   1.550 +    "vmov.u16   q14, #74                       \n"
   1.551 +    "vmov.u16   q15, #16                       \n"
   1.552 +    ".p2align   2                              \n"
   1.553 +  "1:                                          \n"
   1.554 +    READNV12
   1.555 +    YUV422TORGB
   1.556 +    "subs       %3, %3, #8                     \n"
   1.557 +    "vmov.u8    d23, #255                      \n"
   1.558 +    "vst4.8     {d20, d21, d22, d23}, [%2]!    \n"
   1.559 +    "bgt        1b                             \n"
   1.560 +    : "+r"(src_y),     // %0
   1.561 +      "+r"(src_uv),    // %1
   1.562 +      "+r"(dst_argb),  // %2
   1.563 +      "+r"(width)      // %3
   1.564 +    : "r"(&kUVToRB),   // %4
   1.565 +      "r"(&kUVToG)     // %5
   1.566 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.567 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.568 +  );
   1.569 +}
   1.570 +
   1.571 +void NV21ToARGBRow_NEON(const uint8* src_y,
   1.572 +                        const uint8* src_uv,
   1.573 +                        uint8* dst_argb,
   1.574 +                        int width) {
   1.575 +  asm volatile (
   1.576 +    "vld1.8     {d24}, [%4]                    \n"
   1.577 +    "vld1.8     {d25}, [%5]                    \n"
   1.578 +    "vmov.u8    d26, #128                      \n"
   1.579 +    "vmov.u16   q14, #74                       \n"
   1.580 +    "vmov.u16   q15, #16                       \n"
   1.581 +    ".p2align   2                              \n"
   1.582 +  "1:                                          \n"
   1.583 +    READNV21
   1.584 +    YUV422TORGB
   1.585 +    "subs       %3, %3, #8                     \n"
   1.586 +    "vmov.u8    d23, #255                      \n"
   1.587 +    "vst4.8     {d20, d21, d22, d23}, [%2]!    \n"
   1.588 +    "bgt        1b                             \n"
   1.589 +    : "+r"(src_y),     // %0
   1.590 +      "+r"(src_uv),    // %1
   1.591 +      "+r"(dst_argb),  // %2
   1.592 +      "+r"(width)      // %3
   1.593 +    : "r"(&kUVToRB),   // %4
   1.594 +      "r"(&kUVToG)     // %5
   1.595 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.596 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.597 +  );
   1.598 +}
   1.599 +
   1.600 +void NV12ToRGB565Row_NEON(const uint8* src_y,
   1.601 +                          const uint8* src_uv,
   1.602 +                          uint8* dst_rgb565,
   1.603 +                          int width) {
   1.604 +  asm volatile (
   1.605 +    "vld1.8     {d24}, [%4]                    \n"
   1.606 +    "vld1.8     {d25}, [%5]                    \n"
   1.607 +    "vmov.u8    d26, #128                      \n"
   1.608 +    "vmov.u16   q14, #74                       \n"
   1.609 +    "vmov.u16   q15, #16                       \n"
   1.610 +    ".p2align   2                              \n"
   1.611 +  "1:                                          \n"
   1.612 +    READNV12
   1.613 +    YUV422TORGB
   1.614 +    "subs       %3, %3, #8                     \n"
   1.615 +    ARGBTORGB565
   1.616 +    "vst1.8     {q0}, [%2]!                    \n"  // store 8 pixels RGB565.
   1.617 +    "bgt        1b                             \n"
   1.618 +    : "+r"(src_y),     // %0
   1.619 +      "+r"(src_uv),    // %1
   1.620 +      "+r"(dst_rgb565),  // %2
   1.621 +      "+r"(width)      // %3
   1.622 +    : "r"(&kUVToRB),   // %4
   1.623 +      "r"(&kUVToG)     // %5
   1.624 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.625 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.626 +  );
   1.627 +}
   1.628 +
   1.629 +void NV21ToRGB565Row_NEON(const uint8* src_y,
   1.630 +                          const uint8* src_uv,
   1.631 +                          uint8* dst_rgb565,
   1.632 +                          int width) {
   1.633 +  asm volatile (
   1.634 +    "vld1.8     {d24}, [%4]                    \n"
   1.635 +    "vld1.8     {d25}, [%5]                    \n"
   1.636 +    "vmov.u8    d26, #128                      \n"
   1.637 +    "vmov.u16   q14, #74                       \n"
   1.638 +    "vmov.u16   q15, #16                       \n"
   1.639 +    ".p2align   2                              \n"
   1.640 +  "1:                                          \n"
   1.641 +    READNV21
   1.642 +    YUV422TORGB
   1.643 +    "subs       %3, %3, #8                     \n"
   1.644 +    ARGBTORGB565
   1.645 +    "vst1.8     {q0}, [%2]!                    \n"  // store 8 pixels RGB565.
   1.646 +    "bgt        1b                             \n"
   1.647 +    : "+r"(src_y),     // %0
   1.648 +      "+r"(src_uv),    // %1
   1.649 +      "+r"(dst_rgb565),  // %2
   1.650 +      "+r"(width)      // %3
   1.651 +    : "r"(&kUVToRB),   // %4
   1.652 +      "r"(&kUVToG)     // %5
   1.653 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.654 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.655 +  );
   1.656 +}
   1.657 +
   1.658 +void YUY2ToARGBRow_NEON(const uint8* src_yuy2,
   1.659 +                        uint8* dst_argb,
   1.660 +                        int width) {
   1.661 +  asm volatile (
   1.662 +    "vld1.8     {d24}, [%3]                    \n"
   1.663 +    "vld1.8     {d25}, [%4]                    \n"
   1.664 +    "vmov.u8    d26, #128                      \n"
   1.665 +    "vmov.u16   q14, #74                       \n"
   1.666 +    "vmov.u16   q15, #16                       \n"
   1.667 +    ".p2align   2                              \n"
   1.668 +  "1:                                          \n"
   1.669 +    READYUY2
   1.670 +    YUV422TORGB
   1.671 +    "subs       %2, %2, #8                     \n"
   1.672 +    "vmov.u8    d23, #255                      \n"
   1.673 +    "vst4.8     {d20, d21, d22, d23}, [%1]!    \n"
   1.674 +    "bgt        1b                             \n"
   1.675 +    : "+r"(src_yuy2),  // %0
   1.676 +      "+r"(dst_argb),  // %1
   1.677 +      "+r"(width)      // %2
   1.678 +    : "r"(&kUVToRB),   // %3
   1.679 +      "r"(&kUVToG)     // %4
   1.680 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.681 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.682 +  );
   1.683 +}
   1.684 +
   1.685 +void UYVYToARGBRow_NEON(const uint8* src_uyvy,
   1.686 +                        uint8* dst_argb,
   1.687 +                        int width) {
   1.688 +  asm volatile (
   1.689 +    "vld1.8     {d24}, [%3]                    \n"
   1.690 +    "vld1.8     {d25}, [%4]                    \n"
   1.691 +    "vmov.u8    d26, #128                      \n"
   1.692 +    "vmov.u16   q14, #74                       \n"
   1.693 +    "vmov.u16   q15, #16                       \n"
   1.694 +    ".p2align   2                              \n"
   1.695 +  "1:                                          \n"
   1.696 +    READUYVY
   1.697 +    YUV422TORGB
   1.698 +    "subs       %2, %2, #8                     \n"
   1.699 +    "vmov.u8    d23, #255                      \n"
   1.700 +    "vst4.8     {d20, d21, d22, d23}, [%1]!    \n"
   1.701 +    "bgt        1b                             \n"
   1.702 +    : "+r"(src_uyvy),  // %0
   1.703 +      "+r"(dst_argb),  // %1
   1.704 +      "+r"(width)      // %2
   1.705 +    : "r"(&kUVToRB),   // %3
   1.706 +      "r"(&kUVToG)     // %4
   1.707 +    : "cc", "memory", "q0", "q1", "q2", "q3",
   1.708 +      "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
   1.709 +  );
   1.710 +}
   1.711 +
   1.712 +// Reads 16 pairs of UV and write even values to dst_u and odd to dst_v.
   1.713 +void SplitUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
   1.714 +                     int width) {
   1.715 +  asm volatile (
   1.716 +    ".p2align   2                              \n"
   1.717 +  "1:                                          \n"
   1.718 +    "vld2.8     {q0, q1}, [%0]!                \n"  // load 16 pairs of UV
   1.719 +    "subs       %3, %3, #16                    \n"  // 16 processed per loop
   1.720 +    "vst1.8     {q0}, [%1]!                    \n"  // store U
   1.721 +    "vst1.8     {q1}, [%2]!                    \n"  // store V
   1.722 +    "bgt        1b                             \n"
   1.723 +    : "+r"(src_uv),  // %0
   1.724 +      "+r"(dst_u),   // %1
   1.725 +      "+r"(dst_v),   // %2
   1.726 +      "+r"(width)    // %3  // Output registers
   1.727 +    :                       // Input registers
   1.728 +    : "cc", "memory", "q0", "q1"  // Clobber List
   1.729 +  );
   1.730 +}
   1.731 +
   1.732 +// Reads 16 U's and V's and writes out 16 pairs of UV.
   1.733 +void MergeUVRow_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
   1.734 +                     int width) {
   1.735 +  asm volatile (
   1.736 +    ".p2align   2                              \n"
   1.737 +  "1:                                          \n"
   1.738 +    "vld1.8     {q0}, [%0]!                    \n"  // load U
   1.739 +    "vld1.8     {q1}, [%1]!                    \n"  // load V
   1.740 +    "subs       %3, %3, #16                    \n"  // 16 processed per loop
   1.741 +    "vst2.u8    {q0, q1}, [%2]!                \n"  // store 16 pairs of UV
   1.742 +    "bgt        1b                             \n"
   1.743 +    :
   1.744 +      "+r"(src_u),   // %0
   1.745 +      "+r"(src_v),   // %1
   1.746 +      "+r"(dst_uv),  // %2
   1.747 +      "+r"(width)    // %3  // Output registers
   1.748 +    :                       // Input registers
   1.749 +    : "cc", "memory", "q0", "q1"  // Clobber List
   1.750 +  );
   1.751 +}
   1.752 +
   1.753 +// Copy multiple of 32.  vld4.8  allow unaligned and is fastest on a15.
   1.754 +void CopyRow_NEON(const uint8* src, uint8* dst, int count) {
   1.755 +  asm volatile (
   1.756 +    ".p2align   2                              \n"
   1.757 +  "1:                                          \n"
   1.758 +    "vld1.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 32
   1.759 +    "subs       %2, %2, #32                    \n"  // 32 processed per loop
   1.760 +    "vst1.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 32
   1.761 +    "bgt        1b                             \n"
   1.762 +  : "+r"(src),   // %0
   1.763 +    "+r"(dst),   // %1
   1.764 +    "+r"(count)  // %2  // Output registers
   1.765 +  :                     // Input registers
   1.766 +  : "cc", "memory", "q0", "q1"  // Clobber List
   1.767 +  );
   1.768 +}
   1.769 +
   1.770 +// SetRow8 writes 'count' bytes using a 32 bit value repeated.
   1.771 +void SetRow_NEON(uint8* dst, uint32 v32, int count) {
   1.772 +  asm volatile (
   1.773 +    "vdup.u32  q0, %2                          \n"  // duplicate 4 ints
   1.774 +    "1:                                        \n"
   1.775 +    "subs      %1, %1, #16                     \n"  // 16 bytes per loop
   1.776 +    "vst1.8    {q0}, [%0]!                     \n"  // store
   1.777 +    "bgt       1b                              \n"
   1.778 +  : "+r"(dst),   // %0
   1.779 +    "+r"(count)  // %1
   1.780 +  : "r"(v32)     // %2
   1.781 +  : "cc", "memory", "q0"
   1.782 +  );
   1.783 +}
   1.784 +
   1.785 +// TODO(fbarchard): Make fully assembler
   1.786 +// SetRow32 writes 'count' words using a 32 bit value repeated.
   1.787 +void ARGBSetRows_NEON(uint8* dst, uint32 v32, int width,
   1.788 +                      int dst_stride, int height) {
   1.789 +  for (int y = 0; y < height; ++y) {
   1.790 +    SetRow_NEON(dst, v32, width << 2);
   1.791 +    dst += dst_stride;
   1.792 +  }
   1.793 +}
   1.794 +
   1.795 +void MirrorRow_NEON(const uint8* src, uint8* dst, int width) {
   1.796 +  asm volatile (
   1.797 +    // Start at end of source row.
   1.798 +    "mov        r3, #-16                       \n"
   1.799 +    "add        %0, %0, %2                     \n"
   1.800 +    "sub        %0, #16                        \n"
   1.801 +
   1.802 +    ".p2align   2                              \n"
   1.803 +  "1:                                          \n"
   1.804 +    "vld1.8     {q0}, [%0], r3                 \n"  // src -= 16
   1.805 +    "subs       %2, #16                        \n"  // 16 pixels per loop.
   1.806 +    "vrev64.8   q0, q0                         \n"
   1.807 +    "vst1.8     {d1}, [%1]!                    \n"  // dst += 16
   1.808 +    "vst1.8     {d0}, [%1]!                    \n"
   1.809 +    "bgt        1b                             \n"
   1.810 +  : "+r"(src),   // %0
   1.811 +    "+r"(dst),   // %1
   1.812 +    "+r"(width)  // %2
   1.813 +  :
   1.814 +  : "cc", "memory", "r3", "q0"
   1.815 +  );
   1.816 +}
   1.817 +
   1.818 +void MirrorUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
   1.819 +                      int width) {
   1.820 +  asm volatile (
   1.821 +    // Start at end of source row.
   1.822 +    "mov        r12, #-16                      \n"
   1.823 +    "add        %0, %0, %3, lsl #1             \n"
   1.824 +    "sub        %0, #16                        \n"
   1.825 +
   1.826 +    ".p2align   2                              \n"
   1.827 +  "1:                                          \n"
   1.828 +    "vld2.8     {d0, d1}, [%0], r12            \n"  // src -= 16
   1.829 +    "subs       %3, #8                         \n"  // 8 pixels per loop.
   1.830 +    "vrev64.8   q0, q0                         \n"
   1.831 +    "vst1.8     {d0}, [%1]!                    \n"  // dst += 8
   1.832 +    "vst1.8     {d1}, [%2]!                    \n"
   1.833 +    "bgt        1b                             \n"
   1.834 +  : "+r"(src_uv),  // %0
   1.835 +    "+r"(dst_u),   // %1
   1.836 +    "+r"(dst_v),   // %2
   1.837 +    "+r"(width)    // %3
   1.838 +  :
   1.839 +  : "cc", "memory", "r12", "q0"
   1.840 +  );
   1.841 +}
   1.842 +
   1.843 +void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) {
   1.844 +  asm volatile (
   1.845 +    // Start at end of source row.
   1.846 +    "mov        r3, #-16                       \n"
   1.847 +    "add        %0, %0, %2, lsl #2             \n"
   1.848 +    "sub        %0, #16                        \n"
   1.849 +
   1.850 +    ".p2align   2                              \n"
   1.851 +  "1:                                          \n"
   1.852 +    "vld1.8     {q0}, [%0], r3                 \n"  // src -= 16
   1.853 +    "subs       %2, #4                         \n"  // 4 pixels per loop.
   1.854 +    "vrev64.32  q0, q0                         \n"
   1.855 +    "vst1.8     {d1}, [%1]!                    \n"  // dst += 16
   1.856 +    "vst1.8     {d0}, [%1]!                    \n"
   1.857 +    "bgt        1b                             \n"
   1.858 +  : "+r"(src),   // %0
   1.859 +    "+r"(dst),   // %1
   1.860 +    "+r"(width)  // %2
   1.861 +  :
   1.862 +  : "cc", "memory", "r3", "q0"
   1.863 +  );
   1.864 +}
   1.865 +
   1.866 +void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix) {
   1.867 +  asm volatile (
   1.868 +    "vmov.u8    d4, #255                       \n"  // Alpha
   1.869 +    ".p2align   2                              \n"
   1.870 +  "1:                                          \n"
   1.871 +    "vld3.8     {d1, d2, d3}, [%0]!            \n"  // load 8 pixels of RGB24.
   1.872 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
   1.873 +    "vst4.8     {d1, d2, d3, d4}, [%1]!        \n"  // store 8 pixels of ARGB.
   1.874 +    "bgt        1b                             \n"
   1.875 +  : "+r"(src_rgb24),  // %0
   1.876 +    "+r"(dst_argb),   // %1
   1.877 +    "+r"(pix)         // %2
   1.878 +  :
   1.879 +  : "cc", "memory", "d1", "d2", "d3", "d4"  // Clobber List
   1.880 +  );
   1.881 +}
   1.882 +
   1.883 +void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int pix) {
   1.884 +  asm volatile (
   1.885 +    "vmov.u8    d4, #255                       \n"  // Alpha
   1.886 +    ".p2align   2                              \n"
   1.887 +  "1:                                          \n"
   1.888 +    "vld3.8     {d1, d2, d3}, [%0]!            \n"  // load 8 pixels of RAW.
   1.889 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
   1.890 +    "vswp.u8    d1, d3                         \n"  // swap R, B
   1.891 +    "vst4.8     {d1, d2, d3, d4}, [%1]!        \n"  // store 8 pixels of ARGB.
   1.892 +    "bgt        1b                             \n"
   1.893 +  : "+r"(src_raw),   // %0
   1.894 +    "+r"(dst_argb),  // %1
   1.895 +    "+r"(pix)        // %2
   1.896 +  :
   1.897 +  : "cc", "memory", "d1", "d2", "d3", "d4"  // Clobber List
   1.898 +  );
   1.899 +}
   1.900 +
   1.901 +#define RGB565TOARGB                                                           \
   1.902 +    "vshrn.u16  d6, q0, #5                     \n"  /* G xxGGGGGG           */ \
   1.903 +    "vuzp.u8    d0, d1                         \n"  /* d0 xxxBBBBB RRRRRxxx */ \
   1.904 +    "vshl.u8    d6, d6, #2                     \n"  /* G GGGGGG00 upper 6   */ \
   1.905 +    "vshr.u8    d1, d1, #3                     \n"  /* R 000RRRRR lower 5   */ \
   1.906 +    "vshl.u8    q0, q0, #3                     \n"  /* B,R BBBBB000 upper 5 */ \
   1.907 +    "vshr.u8    q2, q0, #5                     \n"  /* B,R 00000BBB lower 3 */ \
   1.908 +    "vorr.u8    d0, d0, d4                     \n"  /* B                    */ \
   1.909 +    "vshr.u8    d4, d6, #6                     \n"  /* G 000000GG lower 2   */ \
   1.910 +    "vorr.u8    d2, d1, d5                     \n"  /* R                    */ \
   1.911 +    "vorr.u8    d1, d4, d6                     \n"  /* G                    */
   1.912 +
   1.913 +void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int pix) {
   1.914 +  asm volatile (
   1.915 +    "vmov.u8    d3, #255                       \n"  // Alpha
   1.916 +    ".p2align   2                              \n"
   1.917 +  "1:                                          \n"
   1.918 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 RGB565 pixels.
   1.919 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
   1.920 +    RGB565TOARGB
   1.921 +    "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 pixels of ARGB.
   1.922 +    "bgt        1b                             \n"
   1.923 +  : "+r"(src_rgb565),  // %0
   1.924 +    "+r"(dst_argb),    // %1
   1.925 +    "+r"(pix)          // %2
   1.926 +  :
   1.927 +  : "cc", "memory", "q0", "q1", "q2", "q3"  // Clobber List
   1.928 +  );
   1.929 +}
   1.930 +
   1.931 +#define ARGB1555TOARGB                                                         \
   1.932 +    "vshrn.u16  d7, q0, #8                     \n"  /* A Arrrrrxx           */ \
   1.933 +    "vshr.u8    d6, d7, #2                     \n"  /* R xxxRRRRR           */ \
   1.934 +    "vshrn.u16  d5, q0, #5                     \n"  /* G xxxGGGGG           */ \
   1.935 +    "vmovn.u16  d4, q0                         \n"  /* B xxxBBBBB           */ \
   1.936 +    "vshr.u8    d7, d7, #7                     \n"  /* A 0000000A           */ \
   1.937 +    "vneg.s8    d7, d7                         \n"  /* A AAAAAAAA upper 8   */ \
   1.938 +    "vshl.u8    d6, d6, #3                     \n"  /* R RRRRR000 upper 5   */ \
   1.939 +    "vshr.u8    q1, q3, #5                     \n"  /* R,A 00000RRR lower 3 */ \
   1.940 +    "vshl.u8    q0, q2, #3                     \n"  /* B,G BBBBB000 upper 5 */ \
   1.941 +    "vshr.u8    q2, q0, #5                     \n"  /* B,G 00000BBB lower 3 */ \
   1.942 +    "vorr.u8    q1, q1, q3                     \n"  /* R,A                  */ \
   1.943 +    "vorr.u8    q0, q0, q2                     \n"  /* B,G                  */ \
   1.944 +
   1.945 +// RGB555TOARGB is same as ARGB1555TOARGB but ignores alpha.
   1.946 +#define RGB555TOARGB                                                           \
   1.947 +    "vshrn.u16  d6, q0, #5                     \n"  /* G xxxGGGGG           */ \
   1.948 +    "vuzp.u8    d0, d1                         \n"  /* d0 xxxBBBBB xRRRRRxx */ \
   1.949 +    "vshl.u8    d6, d6, #3                     \n"  /* G GGGGG000 upper 5   */ \
   1.950 +    "vshr.u8    d1, d1, #2                     \n"  /* R 00xRRRRR lower 5   */ \
   1.951 +    "vshl.u8    q0, q0, #3                     \n"  /* B,R BBBBB000 upper 5 */ \
   1.952 +    "vshr.u8    q2, q0, #5                     \n"  /* B,R 00000BBB lower 3 */ \
   1.953 +    "vorr.u8    d0, d0, d4                     \n"  /* B                    */ \
   1.954 +    "vshr.u8    d4, d6, #5                     \n"  /* G 00000GGG lower 3   */ \
   1.955 +    "vorr.u8    d2, d1, d5                     \n"  /* R                    */ \
   1.956 +    "vorr.u8    d1, d4, d6                     \n"  /* G                    */
   1.957 +
   1.958 +void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, uint8* dst_argb,
   1.959 +                            int pix) {
   1.960 +  asm volatile (
   1.961 +    "vmov.u8    d3, #255                       \n"  // Alpha
   1.962 +    ".p2align   2                              \n"
   1.963 +  "1:                                          \n"
   1.964 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB1555 pixels.
   1.965 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
   1.966 +    ARGB1555TOARGB
   1.967 +    "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 pixels of ARGB.
   1.968 +    "bgt        1b                             \n"
   1.969 +  : "+r"(src_argb1555),  // %0
   1.970 +    "+r"(dst_argb),    // %1
   1.971 +    "+r"(pix)          // %2
   1.972 +  :
   1.973 +  : "cc", "memory", "q0", "q1", "q2", "q3"  // Clobber List
   1.974 +  );
   1.975 +}
   1.976 +
   1.977 +#define ARGB4444TOARGB                                                         \
   1.978 +    "vuzp.u8    d0, d1                         \n"  /* d0 BG, d1 RA         */ \
   1.979 +    "vshl.u8    q2, q0, #4                     \n"  /* B,R BBBB0000         */ \
   1.980 +    "vshr.u8    q1, q0, #4                     \n"  /* G,A 0000GGGG         */ \
   1.981 +    "vshr.u8    q0, q2, #4                     \n"  /* B,R 0000BBBB         */ \
   1.982 +    "vorr.u8    q0, q0, q2                     \n"  /* B,R BBBBBBBB         */ \
   1.983 +    "vshl.u8    q2, q1, #4                     \n"  /* G,A GGGG0000         */ \
   1.984 +    "vorr.u8    q1, q1, q2                     \n"  /* G,A GGGGGGGG         */ \
   1.985 +    "vswp.u8    d1, d2                         \n"  /* B,R,G,A -> B,G,R,A   */
   1.986 +
   1.987 +void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, uint8* dst_argb,
   1.988 +                            int pix) {
   1.989 +  asm volatile (
   1.990 +    "vmov.u8    d3, #255                       \n"  // Alpha
   1.991 +    ".p2align   2                              \n"
   1.992 +  "1:                                          \n"
   1.993 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB4444 pixels.
   1.994 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
   1.995 +    ARGB4444TOARGB
   1.996 +    "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 pixels of ARGB.
   1.997 +    "bgt        1b                             \n"
   1.998 +  : "+r"(src_argb4444),  // %0
   1.999 +    "+r"(dst_argb),    // %1
  1.1000 +    "+r"(pix)          // %2
  1.1001 +  :
  1.1002 +  : "cc", "memory", "q0", "q1", "q2"  // Clobber List
  1.1003 +  );
  1.1004 +}
  1.1005 +
  1.1006 +void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int pix) {
  1.1007 +  asm volatile (
  1.1008 +    ".p2align   2                              \n"
  1.1009 +  "1:                                          \n"
  1.1010 +    "vld4.8     {d1, d2, d3, d4}, [%0]!        \n"  // load 8 pixels of ARGB.
  1.1011 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.1012 +    "vst3.8     {d1, d2, d3}, [%1]!            \n"  // store 8 pixels of RGB24.
  1.1013 +    "bgt        1b                             \n"
  1.1014 +  : "+r"(src_argb),   // %0
  1.1015 +    "+r"(dst_rgb24),  // %1
  1.1016 +    "+r"(pix)         // %2
  1.1017 +  :
  1.1018 +  : "cc", "memory", "d1", "d2", "d3", "d4"  // Clobber List
  1.1019 +  );
  1.1020 +}
  1.1021 +
  1.1022 +void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int pix) {
  1.1023 +  asm volatile (
  1.1024 +    ".p2align   2                              \n"
  1.1025 +  "1:                                          \n"
  1.1026 +    "vld4.8     {d1, d2, d3, d4}, [%0]!        \n"  // load 8 pixels of ARGB.
  1.1027 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.1028 +    "vswp.u8    d1, d3                         \n"  // swap R, B
  1.1029 +    "vst3.8     {d1, d2, d3}, [%1]!            \n"  // store 8 pixels of RAW.
  1.1030 +    "bgt        1b                             \n"
  1.1031 +  : "+r"(src_argb),  // %0
  1.1032 +    "+r"(dst_raw),   // %1
  1.1033 +    "+r"(pix)        // %2
  1.1034 +  :
  1.1035 +  : "cc", "memory", "d1", "d2", "d3", "d4"  // Clobber List
  1.1036 +  );
  1.1037 +}
  1.1038 +
  1.1039 +void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int pix) {
  1.1040 +  asm volatile (
  1.1041 +    ".p2align   2                              \n"
  1.1042 +  "1:                                          \n"
  1.1043 +    "vld2.8     {q0, q1}, [%0]!                \n"  // load 16 pixels of YUY2.
  1.1044 +    "subs       %2, %2, #16                    \n"  // 16 processed per loop.
  1.1045 +    "vst1.8     {q0}, [%1]!                    \n"  // store 16 pixels of Y.
  1.1046 +    "bgt        1b                             \n"
  1.1047 +  : "+r"(src_yuy2),  // %0
  1.1048 +    "+r"(dst_y),     // %1
  1.1049 +    "+r"(pix)        // %2
  1.1050 +  :
  1.1051 +  : "cc", "memory", "q0", "q1"  // Clobber List
  1.1052 +  );
  1.1053 +}
  1.1054 +
  1.1055 +void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int pix) {
  1.1056 +  asm volatile (
  1.1057 +    ".p2align   2                              \n"
  1.1058 +  "1:                                          \n"
  1.1059 +    "vld2.8     {q0, q1}, [%0]!                \n"  // load 16 pixels of UYVY.
  1.1060 +    "subs       %2, %2, #16                    \n"  // 16 processed per loop.
  1.1061 +    "vst1.8     {q1}, [%1]!                    \n"  // store 16 pixels of Y.
  1.1062 +    "bgt        1b                             \n"
  1.1063 +  : "+r"(src_uyvy),  // %0
  1.1064 +    "+r"(dst_y),     // %1
  1.1065 +    "+r"(pix)        // %2
  1.1066 +  :
  1.1067 +  : "cc", "memory", "q0", "q1"  // Clobber List
  1.1068 +  );
  1.1069 +}
  1.1070 +
  1.1071 +void YUY2ToUV422Row_NEON(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
  1.1072 +                         int pix) {
  1.1073 +  asm volatile (
  1.1074 +    ".p2align   2                              \n"
  1.1075 +  "1:                                          \n"
  1.1076 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 16 pixels of YUY2.
  1.1077 +    "subs       %3, %3, #16                    \n"  // 16 pixels = 8 UVs.
  1.1078 +    "vst1.8     {d1}, [%1]!                    \n"  // store 8 U.
  1.1079 +    "vst1.8     {d3}, [%2]!                    \n"  // store 8 V.
  1.1080 +    "bgt        1b                             \n"
  1.1081 +  : "+r"(src_yuy2),  // %0
  1.1082 +    "+r"(dst_u),     // %1
  1.1083 +    "+r"(dst_v),     // %2
  1.1084 +    "+r"(pix)        // %3
  1.1085 +  :
  1.1086 +  : "cc", "memory", "d0", "d1", "d2", "d3"  // Clobber List
  1.1087 +  );
  1.1088 +}
  1.1089 +
  1.1090 +void UYVYToUV422Row_NEON(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v,
  1.1091 +                         int pix) {
  1.1092 +  asm volatile (
  1.1093 +    ".p2align   2                              \n"
  1.1094 +  "1:                                          \n"
  1.1095 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 16 pixels of UYVY.
  1.1096 +    "subs       %3, %3, #16                    \n"  // 16 pixels = 8 UVs.
  1.1097 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 U.
  1.1098 +    "vst1.8     {d2}, [%2]!                    \n"  // store 8 V.
  1.1099 +    "bgt        1b                             \n"
  1.1100 +  : "+r"(src_uyvy),  // %0
  1.1101 +    "+r"(dst_u),     // %1
  1.1102 +    "+r"(dst_v),     // %2
  1.1103 +    "+r"(pix)        // %3
  1.1104 +  :
  1.1105 +  : "cc", "memory", "d0", "d1", "d2", "d3"  // Clobber List
  1.1106 +  );
  1.1107 +}
  1.1108 +
  1.1109 +void YUY2ToUVRow_NEON(const uint8* src_yuy2, int stride_yuy2,
  1.1110 +                      uint8* dst_u, uint8* dst_v, int pix) {
  1.1111 +  asm volatile (
  1.1112 +    "add        %1, %0, %1                     \n"  // stride + src_yuy2
  1.1113 +    ".p2align   2                              \n"
  1.1114 +  "1:                                          \n"
  1.1115 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 16 pixels of YUY2.
  1.1116 +    "subs       %4, %4, #16                    \n"  // 16 pixels = 8 UVs.
  1.1117 +    "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load next row YUY2.
  1.1118 +    "vrhadd.u8  d1, d1, d5                     \n"  // average rows of U
  1.1119 +    "vrhadd.u8  d3, d3, d7                     \n"  // average rows of V
  1.1120 +    "vst1.8     {d1}, [%2]!                    \n"  // store 8 U.
  1.1121 +    "vst1.8     {d3}, [%3]!                    \n"  // store 8 V.
  1.1122 +    "bgt        1b                             \n"
  1.1123 +  : "+r"(src_yuy2),     // %0
  1.1124 +    "+r"(stride_yuy2),  // %1
  1.1125 +    "+r"(dst_u),        // %2
  1.1126 +    "+r"(dst_v),        // %3
  1.1127 +    "+r"(pix)           // %4
  1.1128 +  :
  1.1129 +  : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"  // Clobber List
  1.1130 +  );
  1.1131 +}
  1.1132 +
  1.1133 +void UYVYToUVRow_NEON(const uint8* src_uyvy, int stride_uyvy,
  1.1134 +                      uint8* dst_u, uint8* dst_v, int pix) {
  1.1135 +  asm volatile (
  1.1136 +    "add        %1, %0, %1                     \n"  // stride + src_uyvy
  1.1137 +    ".p2align   2                              \n"
  1.1138 +  "1:                                          \n"
  1.1139 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 16 pixels of UYVY.
  1.1140 +    "subs       %4, %4, #16                    \n"  // 16 pixels = 8 UVs.
  1.1141 +    "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load next row UYVY.
  1.1142 +    "vrhadd.u8  d0, d0, d4                     \n"  // average rows of U
  1.1143 +    "vrhadd.u8  d2, d2, d6                     \n"  // average rows of V
  1.1144 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 U.
  1.1145 +    "vst1.8     {d2}, [%3]!                    \n"  // store 8 V.
  1.1146 +    "bgt        1b                             \n"
  1.1147 +  : "+r"(src_uyvy),     // %0
  1.1148 +    "+r"(stride_uyvy),  // %1
  1.1149 +    "+r"(dst_u),        // %2
  1.1150 +    "+r"(dst_v),        // %3
  1.1151 +    "+r"(pix)           // %4
  1.1152 +  :
  1.1153 +  : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"  // Clobber List
  1.1154 +  );
  1.1155 +}
  1.1156 +
  1.1157 +void HalfRow_NEON(const uint8* src_uv, int src_uv_stride,
  1.1158 +                  uint8* dst_uv, int pix) {
  1.1159 +  asm volatile (
  1.1160 +    // change the stride to row 2 pointer
  1.1161 +    "add        %1, %0                         \n"
  1.1162 +  "1:                                          \n"
  1.1163 +    "vld1.8     {q0}, [%0]!                    \n"  // load row 1 16 pixels.
  1.1164 +    "subs       %3, %3, #16                    \n"  // 16 processed per loop
  1.1165 +    "vld1.8     {q1}, [%1]!                    \n"  // load row 2 16 pixels.
  1.1166 +    "vrhadd.u8  q0, q1                         \n"  // average row 1 and 2
  1.1167 +    "vst1.8     {q0}, [%2]!                    \n"
  1.1168 +    "bgt        1b                             \n"
  1.1169 +  : "+r"(src_uv),         // %0
  1.1170 +    "+r"(src_uv_stride),  // %1
  1.1171 +    "+r"(dst_uv),         // %2
  1.1172 +    "+r"(pix)             // %3
  1.1173 +  :
  1.1174 +  : "cc", "memory", "q0", "q1"  // Clobber List
  1.1175 +  );
  1.1176 +}
  1.1177 +
  1.1178 +// Select 2 channels from ARGB on alternating pixels.  e.g.  BGBGBGBG
  1.1179 +void ARGBToBayerRow_NEON(const uint8* src_argb, uint8* dst_bayer,
  1.1180 +                         uint32 selector, int pix) {
  1.1181 +  asm volatile (
  1.1182 +    "vmov.u32   d6[0], %3                      \n"  // selector
  1.1183 +  "1:                                          \n"
  1.1184 +    "vld1.8     {q0, q1}, [%0]!                \n"  // load row 8 pixels.
  1.1185 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop
  1.1186 +    "vtbl.8     d4, {d0, d1}, d6               \n"  // look up 4 pixels
  1.1187 +    "vtbl.8     d5, {d2, d3}, d6               \n"  // look up 4 pixels
  1.1188 +    "vtrn.u32   d4, d5                         \n"  // combine 8 pixels
  1.1189 +    "vst1.8     {d4}, [%1]!                    \n"  // store 8.
  1.1190 +    "bgt        1b                             \n"
  1.1191 +  : "+r"(src_argb),   // %0
  1.1192 +    "+r"(dst_bayer),  // %1
  1.1193 +    "+r"(pix)         // %2
  1.1194 +  : "r"(selector)     // %3
  1.1195 +  : "cc", "memory", "q0", "q1", "q2", "q3"  // Clobber List
  1.1196 +  );
  1.1197 +}
  1.1198 +
  1.1199 +// Select G channels from ARGB.  e.g.  GGGGGGGG
  1.1200 +void ARGBToBayerGGRow_NEON(const uint8* src_argb, uint8* dst_bayer,
  1.1201 +                           uint32 /*selector*/, int pix) {
  1.1202 +  asm volatile (
  1.1203 +  "1:                                          \n"
  1.1204 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load row 8 pixels.
  1.1205 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop
  1.1206 +    "vst1.8     {d1}, [%1]!                    \n"  // store 8 G's.
  1.1207 +    "bgt        1b                             \n"
  1.1208 +  : "+r"(src_argb),   // %0
  1.1209 +    "+r"(dst_bayer),  // %1
  1.1210 +    "+r"(pix)         // %2
  1.1211 +  :
  1.1212 +  : "cc", "memory", "q0", "q1"  // Clobber List
  1.1213 +  );
  1.1214 +}
  1.1215 +
  1.1216 +// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA.
  1.1217 +void ARGBShuffleRow_NEON(const uint8* src_argb, uint8* dst_argb,
  1.1218 +                         const uint8* shuffler, int pix) {
  1.1219 +  asm volatile (
  1.1220 +    "vld1.8     {q2}, [%3]                     \n"  // shuffler
  1.1221 +  "1:                                          \n"
  1.1222 +    "vld1.8     {q0}, [%0]!                    \n"  // load 4 pixels.
  1.1223 +    "subs       %2, %2, #4                     \n"  // 4 processed per loop
  1.1224 +    "vtbl.8     d2, {d0, d1}, d4               \n"  // look up 2 first pixels
  1.1225 +    "vtbl.8     d3, {d0, d1}, d5               \n"  // look up 2 next pixels
  1.1226 +    "vst1.8     {q1}, [%1]!                    \n"  // store 4.
  1.1227 +    "bgt        1b                             \n"
  1.1228 +  : "+r"(src_argb),  // %0
  1.1229 +    "+r"(dst_argb),  // %1
  1.1230 +    "+r"(pix)        // %2
  1.1231 +  : "r"(shuffler)    // %3
  1.1232 +  : "cc", "memory", "q0", "q1", "q2"  // Clobber List
  1.1233 +  );
  1.1234 +}
  1.1235 +
  1.1236 +void I422ToYUY2Row_NEON(const uint8* src_y,
  1.1237 +                        const uint8* src_u,
  1.1238 +                        const uint8* src_v,
  1.1239 +                        uint8* dst_yuy2, int width) {
  1.1240 +  asm volatile (
  1.1241 +    ".p2align   2                              \n"
  1.1242 +  "1:                                          \n"
  1.1243 +    "vld2.8     {d0, d2}, [%0]!                \n"  // load 16 Ys
  1.1244 +    "vld1.8     {d1}, [%1]!                    \n"  // load 8 Us
  1.1245 +    "vld1.8     {d3}, [%2]!                    \n"  // load 8 Vs
  1.1246 +    "subs       %4, %4, #16                    \n"  // 16 pixels
  1.1247 +    "vst4.8     {d0, d1, d2, d3}, [%3]!        \n"  // Store 8 YUY2/16 pixels.
  1.1248 +    "bgt        1b                             \n"
  1.1249 +  : "+r"(src_y),     // %0
  1.1250 +    "+r"(src_u),     // %1
  1.1251 +    "+r"(src_v),     // %2
  1.1252 +    "+r"(dst_yuy2),  // %3
  1.1253 +    "+r"(width)      // %4
  1.1254 +  :
  1.1255 +  : "cc", "memory", "d0", "d1", "d2", "d3"
  1.1256 +  );
  1.1257 +}
  1.1258 +
  1.1259 +void I422ToUYVYRow_NEON(const uint8* src_y,
  1.1260 +                        const uint8* src_u,
  1.1261 +                        const uint8* src_v,
  1.1262 +                        uint8* dst_uyvy, int width) {
  1.1263 +  asm volatile (
  1.1264 +    ".p2align   2                              \n"
  1.1265 +  "1:                                          \n"
  1.1266 +    "vld2.8     {d1, d3}, [%0]!                \n"  // load 16 Ys
  1.1267 +    "vld1.8     {d0}, [%1]!                    \n"  // load 8 Us
  1.1268 +    "vld1.8     {d2}, [%2]!                    \n"  // load 8 Vs
  1.1269 +    "subs       %4, %4, #16                    \n"  // 16 pixels
  1.1270 +    "vst4.8     {d0, d1, d2, d3}, [%3]!        \n"  // Store 8 UYVY/16 pixels.
  1.1271 +    "bgt        1b                             \n"
  1.1272 +  : "+r"(src_y),     // %0
  1.1273 +    "+r"(src_u),     // %1
  1.1274 +    "+r"(src_v),     // %2
  1.1275 +    "+r"(dst_uyvy),  // %3
  1.1276 +    "+r"(width)      // %4
  1.1277 +  :
  1.1278 +  : "cc", "memory", "d0", "d1", "d2", "d3"
  1.1279 +  );
  1.1280 +}
  1.1281 +
  1.1282 +void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int pix) {
  1.1283 +  asm volatile (
  1.1284 +    ".p2align   2                              \n"
  1.1285 +  "1:                                          \n"
  1.1286 +    "vld4.8     {d20, d21, d22, d23}, [%0]!    \n"  // load 8 pixels of ARGB.
  1.1287 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.1288 +    ARGBTORGB565
  1.1289 +    "vst1.8     {q0}, [%1]!                    \n"  // store 8 pixels RGB565.
  1.1290 +    "bgt        1b                             \n"
  1.1291 +  : "+r"(src_argb),  // %0
  1.1292 +    "+r"(dst_rgb565),  // %1
  1.1293 +    "+r"(pix)        // %2
  1.1294 +  :
  1.1295 +  : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
  1.1296 +  );
  1.1297 +}
  1.1298 +
  1.1299 +void ARGBToARGB1555Row_NEON(const uint8* src_argb, uint8* dst_argb1555,
  1.1300 +                            int pix) {
  1.1301 +  asm volatile (
  1.1302 +    ".p2align   2                              \n"
  1.1303 +  "1:                                          \n"
  1.1304 +    "vld4.8     {d20, d21, d22, d23}, [%0]!    \n"  // load 8 pixels of ARGB.
  1.1305 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.1306 +    ARGBTOARGB1555
  1.1307 +    "vst1.8     {q0}, [%1]!                    \n"  // store 8 pixels ARGB1555.
  1.1308 +    "bgt        1b                             \n"
  1.1309 +  : "+r"(src_argb),  // %0
  1.1310 +    "+r"(dst_argb1555),  // %1
  1.1311 +    "+r"(pix)        // %2
  1.1312 +  :
  1.1313 +  : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
  1.1314 +  );
  1.1315 +}
  1.1316 +
  1.1317 +void ARGBToARGB4444Row_NEON(const uint8* src_argb, uint8* dst_argb4444,
  1.1318 +                            int pix) {
  1.1319 +  asm volatile (
  1.1320 +    "vmov.u8    d4, #0x0f                      \n"  // bits to clear with vbic.
  1.1321 +    ".p2align   2                              \n"
  1.1322 +  "1:                                          \n"
  1.1323 +    "vld4.8     {d20, d21, d22, d23}, [%0]!    \n"  // load 8 pixels of ARGB.
  1.1324 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.1325 +    ARGBTOARGB4444
  1.1326 +    "vst1.8     {q0}, [%1]!                    \n"  // store 8 pixels ARGB4444.
  1.1327 +    "bgt        1b                             \n"
  1.1328 +  : "+r"(src_argb),      // %0
  1.1329 +    "+r"(dst_argb4444),  // %1
  1.1330 +    "+r"(pix)            // %2
  1.1331 +  :
  1.1332 +  : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
  1.1333 +  );
  1.1334 +}
  1.1335 +
  1.1336 +void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) {
  1.1337 +  asm volatile (
  1.1338 +    "vmov.u8    d24, #13                       \n"  // B * 0.1016 coefficient
  1.1339 +    "vmov.u8    d25, #65                       \n"  // G * 0.5078 coefficient
  1.1340 +    "vmov.u8    d26, #33                       \n"  // R * 0.2578 coefficient
  1.1341 +    "vmov.u8    d27, #16                       \n"  // Add 16 constant
  1.1342 +    ".p2align   2                              \n"
  1.1343 +  "1:                                          \n"
  1.1344 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
  1.1345 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.1346 +    "vmull.u8   q2, d0, d24                    \n"  // B
  1.1347 +    "vmlal.u8   q2, d1, d25                    \n"  // G
  1.1348 +    "vmlal.u8   q2, d2, d26                    \n"  // R
  1.1349 +    "vqrshrun.s16 d0, q2, #7                   \n"  // 16 bit to 8 bit Y
  1.1350 +    "vqadd.u8   d0, d27                        \n"
  1.1351 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.1352 +    "bgt        1b                             \n"
  1.1353 +  : "+r"(src_argb),  // %0
  1.1354 +    "+r"(dst_y),     // %1
  1.1355 +    "+r"(pix)        // %2
  1.1356 +  :
  1.1357 +  : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
  1.1358 +  );
  1.1359 +}
  1.1360 +
  1.1361 +void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) {
  1.1362 +  asm volatile (
  1.1363 +    "vmov.u8    d24, #15                       \n"  // B * 0.11400 coefficient
  1.1364 +    "vmov.u8    d25, #75                       \n"  // G * 0.58700 coefficient
  1.1365 +    "vmov.u8    d26, #38                       \n"  // R * 0.29900 coefficient
  1.1366 +    ".p2align   2                              \n"
  1.1367 +  "1:                                          \n"
  1.1368 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
  1.1369 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.1370 +    "vmull.u8   q2, d0, d24                    \n"  // B
  1.1371 +    "vmlal.u8   q2, d1, d25                    \n"  // G
  1.1372 +    "vmlal.u8   q2, d2, d26                    \n"  // R
  1.1373 +    "vqrshrun.s16 d0, q2, #7                   \n"  // 15 bit to 8 bit Y
  1.1374 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.1375 +    "bgt        1b                             \n"
  1.1376 +  : "+r"(src_argb),  // %0
  1.1377 +    "+r"(dst_y),     // %1
  1.1378 +    "+r"(pix)        // %2
  1.1379 +  :
  1.1380 +  : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
  1.1381 +  );
  1.1382 +}
  1.1383 +
  1.1384 +// 8x1 pixels.
  1.1385 +void ARGBToUV444Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
  1.1386 +                         int pix) {
  1.1387 +  asm volatile (
  1.1388 +    "vmov.u8    d24, #112                      \n"  // UB / VR 0.875 coefficient
  1.1389 +    "vmov.u8    d25, #74                       \n"  // UG -0.5781 coefficient
  1.1390 +    "vmov.u8    d26, #38                       \n"  // UR -0.2969 coefficient
  1.1391 +    "vmov.u8    d27, #18                       \n"  // VB -0.1406 coefficient
  1.1392 +    "vmov.u8    d28, #94                       \n"  // VG -0.7344 coefficient
  1.1393 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1394 +    ".p2align   2                              \n"
  1.1395 +  "1:                                          \n"
  1.1396 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
  1.1397 +    "subs       %3, %3, #8                     \n"  // 8 processed per loop.
  1.1398 +    "vmull.u8   q2, d0, d24                    \n"  // B
  1.1399 +    "vmlsl.u8   q2, d1, d25                    \n"  // G
  1.1400 +    "vmlsl.u8   q2, d2, d26                    \n"  // R
  1.1401 +    "vadd.u16   q2, q2, q15                    \n"  // +128 -> unsigned
  1.1402 +
  1.1403 +    "vmull.u8   q3, d2, d24                    \n"  // R
  1.1404 +    "vmlsl.u8   q3, d1, d28                    \n"  // G
  1.1405 +    "vmlsl.u8   q3, d0, d27                    \n"  // B
  1.1406 +    "vadd.u16   q3, q3, q15                    \n"  // +128 -> unsigned
  1.1407 +
  1.1408 +    "vqshrn.u16  d0, q2, #8                    \n"  // 16 bit to 8 bit U
  1.1409 +    "vqshrn.u16  d1, q3, #8                    \n"  // 16 bit to 8 bit V
  1.1410 +
  1.1411 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels U.
  1.1412 +    "vst1.8     {d1}, [%2]!                    \n"  // store 8 pixels V.
  1.1413 +    "bgt        1b                             \n"
  1.1414 +  : "+r"(src_argb),  // %0
  1.1415 +    "+r"(dst_u),     // %1
  1.1416 +    "+r"(dst_v),     // %2
  1.1417 +    "+r"(pix)        // %3
  1.1418 +  :
  1.1419 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q12", "q13", "q14", "q15"
  1.1420 +  );
  1.1421 +}
  1.1422 +
  1.1423 +// 16x1 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
  1.1424 +void ARGBToUV422Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
  1.1425 +                         int pix) {
  1.1426 +  asm volatile (
  1.1427 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1428 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1429 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1430 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1431 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1432 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1433 +    ".p2align   2                              \n"
  1.1434 +  "1:                                          \n"
  1.1435 +    "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
  1.1436 +    "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ARGB pixels.
  1.1437 +
  1.1438 +    "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
  1.1439 +    "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
  1.1440 +    "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
  1.1441 +
  1.1442 +    "subs       %3, %3, #16                    \n"  // 16 processed per loop.
  1.1443 +    "vmul.s16   q8, q0, q10                    \n"  // B
  1.1444 +    "vmls.s16   q8, q1, q11                    \n"  // G
  1.1445 +    "vmls.s16   q8, q2, q12                    \n"  // R
  1.1446 +    "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
  1.1447 +
  1.1448 +    "vmul.s16   q9, q2, q10                    \n"  // R
  1.1449 +    "vmls.s16   q9, q1, q14                    \n"  // G
  1.1450 +    "vmls.s16   q9, q0, q13                    \n"  // B
  1.1451 +    "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
  1.1452 +
  1.1453 +    "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
  1.1454 +    "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
  1.1455 +
  1.1456 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels U.
  1.1457 +    "vst1.8     {d1}, [%2]!                    \n"  // store 8 pixels V.
  1.1458 +    "bgt        1b                             \n"
  1.1459 +  : "+r"(src_argb),  // %0
  1.1460 +    "+r"(dst_u),     // %1
  1.1461 +    "+r"(dst_v),     // %2
  1.1462 +    "+r"(pix)        // %3
  1.1463 +  :
  1.1464 +  : "cc", "memory", "q0", "q1", "q2", "q3",
  1.1465 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1466 +  );
  1.1467 +}
  1.1468 +
  1.1469 +// 32x1 pixels -> 8x1.  pix is number of argb pixels. e.g. 32.
  1.1470 +void ARGBToUV411Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
  1.1471 +                         int pix) {
  1.1472 +  asm volatile (
  1.1473 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1474 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1475 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1476 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1477 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1478 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1479 +    ".p2align   2                              \n"
  1.1480 +  "1:                                          \n"
  1.1481 +    "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
  1.1482 +    "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ARGB pixels.
  1.1483 +    "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
  1.1484 +    "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
  1.1485 +    "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
  1.1486 +    "vld4.8     {d8, d10, d12, d14}, [%0]!     \n"  // load 8 more ARGB pixels.
  1.1487 +    "vld4.8     {d9, d11, d13, d15}, [%0]!     \n"  // load last 8 ARGB pixels.
  1.1488 +    "vpaddl.u8  q4, q4                         \n"  // B 16 bytes -> 8 shorts.
  1.1489 +    "vpaddl.u8  q5, q5                         \n"  // G 16 bytes -> 8 shorts.
  1.1490 +    "vpaddl.u8  q6, q6                         \n"  // R 16 bytes -> 8 shorts.
  1.1491 +
  1.1492 +    "vpadd.u16  d0, d0, d1                     \n"  // B 16 shorts -> 8 shorts.
  1.1493 +    "vpadd.u16  d1, d8, d9                     \n"  // B
  1.1494 +    "vpadd.u16  d2, d2, d3                     \n"  // G 16 shorts -> 8 shorts.
  1.1495 +    "vpadd.u16  d3, d10, d11                   \n"  // G
  1.1496 +    "vpadd.u16  d4, d4, d5                     \n"  // R 16 shorts -> 8 shorts.
  1.1497 +    "vpadd.u16  d5, d12, d13                   \n"  // R
  1.1498 +
  1.1499 +    "vrshr.u16  q0, q0, #1                     \n"  // 2x average
  1.1500 +    "vrshr.u16  q1, q1, #1                     \n"
  1.1501 +    "vrshr.u16  q2, q2, #1                     \n"
  1.1502 +
  1.1503 +    "subs       %3, %3, #32                    \n"  // 32 processed per loop.
  1.1504 +    "vmul.s16   q8, q0, q10                    \n"  // B
  1.1505 +    "vmls.s16   q8, q1, q11                    \n"  // G
  1.1506 +    "vmls.s16   q8, q2, q12                    \n"  // R
  1.1507 +    "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
  1.1508 +    "vmul.s16   q9, q2, q10                    \n"  // R
  1.1509 +    "vmls.s16   q9, q1, q14                    \n"  // G
  1.1510 +    "vmls.s16   q9, q0, q13                    \n"  // B
  1.1511 +    "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
  1.1512 +    "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
  1.1513 +    "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
  1.1514 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels U.
  1.1515 +    "vst1.8     {d1}, [%2]!                    \n"  // store 8 pixels V.
  1.1516 +    "bgt        1b                             \n"
  1.1517 +  : "+r"(src_argb),  // %0
  1.1518 +    "+r"(dst_u),     // %1
  1.1519 +    "+r"(dst_v),     // %2
  1.1520 +    "+r"(pix)        // %3
  1.1521 +  :
  1.1522 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1523 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1524 +  );
  1.1525 +}
  1.1526 +
  1.1527 +// 16x2 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
  1.1528 +#define RGBTOUV(QB, QG, QR) \
  1.1529 +    "vmul.s16   q8, " #QB ", q10               \n"  /* B                    */ \
  1.1530 +    "vmls.s16   q8, " #QG ", q11               \n"  /* G                    */ \
  1.1531 +    "vmls.s16   q8, " #QR ", q12               \n"  /* R                    */ \
  1.1532 +    "vadd.u16   q8, q8, q15                    \n"  /* +128 -> unsigned     */ \
  1.1533 +    "vmul.s16   q9, " #QR ", q10               \n"  /* R                    */ \
  1.1534 +    "vmls.s16   q9, " #QG ", q14               \n"  /* G                    */ \
  1.1535 +    "vmls.s16   q9, " #QB ", q13               \n"  /* B                    */ \
  1.1536 +    "vadd.u16   q9, q9, q15                    \n"  /* +128 -> unsigned     */ \
  1.1537 +    "vqshrn.u16  d0, q8, #8                    \n"  /* 16 bit to 8 bit U    */ \
  1.1538 +    "vqshrn.u16  d1, q9, #8                    \n"  /* 16 bit to 8 bit V    */
  1.1539 +
  1.1540 +// TODO(fbarchard): Consider vhadd vertical, then vpaddl horizontal, avoid shr.
  1.1541 +void ARGBToUVRow_NEON(const uint8* src_argb, int src_stride_argb,
  1.1542 +                      uint8* dst_u, uint8* dst_v, int pix) {
  1.1543 +  asm volatile (
  1.1544 +    "add        %1, %0, %1                     \n"  // src_stride + src_argb
  1.1545 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1546 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1547 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1548 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1549 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1550 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1551 +    ".p2align   2                              \n"
  1.1552 +  "1:                                          \n"
  1.1553 +    "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
  1.1554 +    "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ARGB pixels.
  1.1555 +    "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
  1.1556 +    "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
  1.1557 +    "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
  1.1558 +    "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more ARGB pixels.
  1.1559 +    "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 ARGB pixels.
  1.1560 +    "vpadal.u8  q0, q4                         \n"  // B 16 bytes -> 8 shorts.
  1.1561 +    "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
  1.1562 +    "vpadal.u8  q2, q6                         \n"  // R 16 bytes -> 8 shorts.
  1.1563 +
  1.1564 +    "vrshr.u16  q0, q0, #1                     \n"  // 2x average
  1.1565 +    "vrshr.u16  q1, q1, #1                     \n"
  1.1566 +    "vrshr.u16  q2, q2, #1                     \n"
  1.1567 +
  1.1568 +    "subs       %4, %4, #16                    \n"  // 32 processed per loop.
  1.1569 +    RGBTOUV(q0, q1, q2)
  1.1570 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1571 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1572 +    "bgt        1b                             \n"
  1.1573 +  : "+r"(src_argb),  // %0
  1.1574 +    "+r"(src_stride_argb),  // %1
  1.1575 +    "+r"(dst_u),     // %2
  1.1576 +    "+r"(dst_v),     // %3
  1.1577 +    "+r"(pix)        // %4
  1.1578 +  :
  1.1579 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1580 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1581 +  );
  1.1582 +}
  1.1583 +
  1.1584 +// TODO(fbarchard): Subsample match C code.
  1.1585 +void ARGBToUVJRow_NEON(const uint8* src_argb, int src_stride_argb,
  1.1586 +                       uint8* dst_u, uint8* dst_v, int pix) {
  1.1587 +  asm volatile (
  1.1588 +    "add        %1, %0, %1                     \n"  // src_stride + src_argb
  1.1589 +    "vmov.s16   q10, #127 / 2                  \n"  // UB / VR 0.500 coefficient
  1.1590 +    "vmov.s16   q11, #84 / 2                   \n"  // UG -0.33126 coefficient
  1.1591 +    "vmov.s16   q12, #43 / 2                   \n"  // UR -0.16874 coefficient
  1.1592 +    "vmov.s16   q13, #20 / 2                   \n"  // VB -0.08131 coefficient
  1.1593 +    "vmov.s16   q14, #107 / 2                  \n"  // VG -0.41869 coefficient
  1.1594 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1595 +    ".p2align   2                              \n"
  1.1596 +  "1:                                          \n"
  1.1597 +    "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
  1.1598 +    "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ARGB pixels.
  1.1599 +    "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
  1.1600 +    "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
  1.1601 +    "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
  1.1602 +    "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more ARGB pixels.
  1.1603 +    "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 ARGB pixels.
  1.1604 +    "vpadal.u8  q0, q4                         \n"  // B 16 bytes -> 8 shorts.
  1.1605 +    "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
  1.1606 +    "vpadal.u8  q2, q6                         \n"  // R 16 bytes -> 8 shorts.
  1.1607 +
  1.1608 +    "vrshr.u16  q0, q0, #1                     \n"  // 2x average
  1.1609 +    "vrshr.u16  q1, q1, #1                     \n"
  1.1610 +    "vrshr.u16  q2, q2, #1                     \n"
  1.1611 +
  1.1612 +    "subs       %4, %4, #16                    \n"  // 32 processed per loop.
  1.1613 +    RGBTOUV(q0, q1, q2)
  1.1614 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1615 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1616 +    "bgt        1b                             \n"
  1.1617 +  : "+r"(src_argb),  // %0
  1.1618 +    "+r"(src_stride_argb),  // %1
  1.1619 +    "+r"(dst_u),     // %2
  1.1620 +    "+r"(dst_v),     // %3
  1.1621 +    "+r"(pix)        // %4
  1.1622 +  :
  1.1623 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1624 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1625 +  );
  1.1626 +}
  1.1627 +
  1.1628 +void BGRAToUVRow_NEON(const uint8* src_bgra, int src_stride_bgra,
  1.1629 +                      uint8* dst_u, uint8* dst_v, int pix) {
  1.1630 +  asm volatile (
  1.1631 +    "add        %1, %0, %1                     \n"  // src_stride + src_bgra
  1.1632 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1633 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1634 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1635 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1636 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1637 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1638 +    ".p2align   2                              \n"
  1.1639 +  "1:                                          \n"
  1.1640 +    "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 BGRA pixels.
  1.1641 +    "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 BGRA pixels.
  1.1642 +    "vpaddl.u8  q3, q3                         \n"  // B 16 bytes -> 8 shorts.
  1.1643 +    "vpaddl.u8  q2, q2                         \n"  // G 16 bytes -> 8 shorts.
  1.1644 +    "vpaddl.u8  q1, q1                         \n"  // R 16 bytes -> 8 shorts.
  1.1645 +    "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more BGRA pixels.
  1.1646 +    "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 BGRA pixels.
  1.1647 +    "vpadal.u8  q3, q7                         \n"  // B 16 bytes -> 8 shorts.
  1.1648 +    "vpadal.u8  q2, q6                         \n"  // G 16 bytes -> 8 shorts.
  1.1649 +    "vpadal.u8  q1, q5                         \n"  // R 16 bytes -> 8 shorts.
  1.1650 +
  1.1651 +    "vrshr.u16  q1, q1, #1                     \n"  // 2x average
  1.1652 +    "vrshr.u16  q2, q2, #1                     \n"
  1.1653 +    "vrshr.u16  q3, q3, #1                     \n"
  1.1654 +
  1.1655 +    "subs       %4, %4, #16                    \n"  // 32 processed per loop.
  1.1656 +    RGBTOUV(q3, q2, q1)
  1.1657 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1658 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1659 +    "bgt        1b                             \n"
  1.1660 +  : "+r"(src_bgra),  // %0
  1.1661 +    "+r"(src_stride_bgra),  // %1
  1.1662 +    "+r"(dst_u),     // %2
  1.1663 +    "+r"(dst_v),     // %3
  1.1664 +    "+r"(pix)        // %4
  1.1665 +  :
  1.1666 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1667 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1668 +  );
  1.1669 +}
  1.1670 +
  1.1671 +void ABGRToUVRow_NEON(const uint8* src_abgr, int src_stride_abgr,
  1.1672 +                      uint8* dst_u, uint8* dst_v, int pix) {
  1.1673 +  asm volatile (
  1.1674 +    "add        %1, %0, %1                     \n"  // src_stride + src_abgr
  1.1675 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1676 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1677 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1678 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1679 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1680 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1681 +    ".p2align   2                              \n"
  1.1682 +  "1:                                          \n"
  1.1683 +    "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ABGR pixels.
  1.1684 +    "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 ABGR pixels.
  1.1685 +    "vpaddl.u8  q2, q2                         \n"  // B 16 bytes -> 8 shorts.
  1.1686 +    "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
  1.1687 +    "vpaddl.u8  q0, q0                         \n"  // R 16 bytes -> 8 shorts.
  1.1688 +    "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more ABGR pixels.
  1.1689 +    "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 ABGR pixels.
  1.1690 +    "vpadal.u8  q2, q6                         \n"  // B 16 bytes -> 8 shorts.
  1.1691 +    "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
  1.1692 +    "vpadal.u8  q0, q4                         \n"  // R 16 bytes -> 8 shorts.
  1.1693 +
  1.1694 +    "vrshr.u16  q0, q0, #1                     \n"  // 2x average
  1.1695 +    "vrshr.u16  q1, q1, #1                     \n"
  1.1696 +    "vrshr.u16  q2, q2, #1                     \n"
  1.1697 +
  1.1698 +    "subs       %4, %4, #16                    \n"  // 32 processed per loop.
  1.1699 +    RGBTOUV(q2, q1, q0)
  1.1700 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1701 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1702 +    "bgt        1b                             \n"
  1.1703 +  : "+r"(src_abgr),  // %0
  1.1704 +    "+r"(src_stride_abgr),  // %1
  1.1705 +    "+r"(dst_u),     // %2
  1.1706 +    "+r"(dst_v),     // %3
  1.1707 +    "+r"(pix)        // %4
  1.1708 +  :
  1.1709 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1710 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1711 +  );
  1.1712 +}
  1.1713 +
  1.1714 +void RGBAToUVRow_NEON(const uint8* src_rgba, int src_stride_rgba,
  1.1715 +                      uint8* dst_u, uint8* dst_v, int pix) {
  1.1716 +  asm volatile (
  1.1717 +    "add        %1, %0, %1                     \n"  // src_stride + src_rgba
  1.1718 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1719 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1720 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1721 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1722 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1723 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1724 +    ".p2align   2                              \n"
  1.1725 +  "1:                                          \n"
  1.1726 +    "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 RGBA pixels.
  1.1727 +    "vld4.8     {d1, d3, d5, d7}, [%0]!        \n"  // load next 8 RGBA pixels.
  1.1728 +    "vpaddl.u8  q0, q1                         \n"  // B 16 bytes -> 8 shorts.
  1.1729 +    "vpaddl.u8  q1, q2                         \n"  // G 16 bytes -> 8 shorts.
  1.1730 +    "vpaddl.u8  q2, q3                         \n"  // R 16 bytes -> 8 shorts.
  1.1731 +    "vld4.8     {d8, d10, d12, d14}, [%1]!     \n"  // load 8 more RGBA pixels.
  1.1732 +    "vld4.8     {d9, d11, d13, d15}, [%1]!     \n"  // load last 8 RGBA pixels.
  1.1733 +    "vpadal.u8  q0, q5                         \n"  // B 16 bytes -> 8 shorts.
  1.1734 +    "vpadal.u8  q1, q6                         \n"  // G 16 bytes -> 8 shorts.
  1.1735 +    "vpadal.u8  q2, q7                         \n"  // R 16 bytes -> 8 shorts.
  1.1736 +
  1.1737 +    "vrshr.u16  q0, q0, #1                     \n"  // 2x average
  1.1738 +    "vrshr.u16  q1, q1, #1                     \n"
  1.1739 +    "vrshr.u16  q2, q2, #1                     \n"
  1.1740 +
  1.1741 +    "subs       %4, %4, #16                    \n"  // 32 processed per loop.
  1.1742 +    RGBTOUV(q0, q1, q2)
  1.1743 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1744 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1745 +    "bgt        1b                             \n"
  1.1746 +  : "+r"(src_rgba),  // %0
  1.1747 +    "+r"(src_stride_rgba),  // %1
  1.1748 +    "+r"(dst_u),     // %2
  1.1749 +    "+r"(dst_v),     // %3
  1.1750 +    "+r"(pix)        // %4
  1.1751 +  :
  1.1752 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1753 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1754 +  );
  1.1755 +}
  1.1756 +
  1.1757 +void RGB24ToUVRow_NEON(const uint8* src_rgb24, int src_stride_rgb24,
  1.1758 +                       uint8* dst_u, uint8* dst_v, int pix) {
  1.1759 +  asm volatile (
  1.1760 +    "add        %1, %0, %1                     \n"  // src_stride + src_rgb24
  1.1761 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1762 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1763 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1764 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1765 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1766 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1767 +    ".p2align   2                              \n"
  1.1768 +  "1:                                          \n"
  1.1769 +    "vld3.8     {d0, d2, d4}, [%0]!            \n"  // load 8 RGB24 pixels.
  1.1770 +    "vld3.8     {d1, d3, d5}, [%0]!            \n"  // load next 8 RGB24 pixels.
  1.1771 +    "vpaddl.u8  q0, q0                         \n"  // B 16 bytes -> 8 shorts.
  1.1772 +    "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
  1.1773 +    "vpaddl.u8  q2, q2                         \n"  // R 16 bytes -> 8 shorts.
  1.1774 +    "vld3.8     {d8, d10, d12}, [%1]!          \n"  // load 8 more RGB24 pixels.
  1.1775 +    "vld3.8     {d9, d11, d13}, [%1]!          \n"  // load last 8 RGB24 pixels.
  1.1776 +    "vpadal.u8  q0, q4                         \n"  // B 16 bytes -> 8 shorts.
  1.1777 +    "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
  1.1778 +    "vpadal.u8  q2, q6                         \n"  // R 16 bytes -> 8 shorts.
  1.1779 +
  1.1780 +    "vrshr.u16  q0, q0, #1                     \n"  // 2x average
  1.1781 +    "vrshr.u16  q1, q1, #1                     \n"
  1.1782 +    "vrshr.u16  q2, q2, #1                     \n"
  1.1783 +
  1.1784 +    "subs       %4, %4, #16                    \n"  // 32 processed per loop.
  1.1785 +    RGBTOUV(q0, q1, q2)
  1.1786 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1787 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1788 +    "bgt        1b                             \n"
  1.1789 +  : "+r"(src_rgb24),  // %0
  1.1790 +    "+r"(src_stride_rgb24),  // %1
  1.1791 +    "+r"(dst_u),     // %2
  1.1792 +    "+r"(dst_v),     // %3
  1.1793 +    "+r"(pix)        // %4
  1.1794 +  :
  1.1795 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1796 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1797 +  );
  1.1798 +}
  1.1799 +
  1.1800 +void RAWToUVRow_NEON(const uint8* src_raw, int src_stride_raw,
  1.1801 +                     uint8* dst_u, uint8* dst_v, int pix) {
  1.1802 +  asm volatile (
  1.1803 +    "add        %1, %0, %1                     \n"  // src_stride + src_raw
  1.1804 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1805 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1806 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1807 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1808 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1809 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1810 +    ".p2align   2                              \n"
  1.1811 +  "1:                                          \n"
  1.1812 +    "vld3.8     {d0, d2, d4}, [%0]!            \n"  // load 8 RAW pixels.
  1.1813 +    "vld3.8     {d1, d3, d5}, [%0]!            \n"  // load next 8 RAW pixels.
  1.1814 +    "vpaddl.u8  q2, q2                         \n"  // B 16 bytes -> 8 shorts.
  1.1815 +    "vpaddl.u8  q1, q1                         \n"  // G 16 bytes -> 8 shorts.
  1.1816 +    "vpaddl.u8  q0, q0                         \n"  // R 16 bytes -> 8 shorts.
  1.1817 +    "vld3.8     {d8, d10, d12}, [%1]!          \n"  // load 8 more RAW pixels.
  1.1818 +    "vld3.8     {d9, d11, d13}, [%1]!          \n"  // load last 8 RAW pixels.
  1.1819 +    "vpadal.u8  q2, q6                         \n"  // B 16 bytes -> 8 shorts.
  1.1820 +    "vpadal.u8  q1, q5                         \n"  // G 16 bytes -> 8 shorts.
  1.1821 +    "vpadal.u8  q0, q4                         \n"  // R 16 bytes -> 8 shorts.
  1.1822 +
  1.1823 +    "vrshr.u16  q0, q0, #1                     \n"  // 2x average
  1.1824 +    "vrshr.u16  q1, q1, #1                     \n"
  1.1825 +    "vrshr.u16  q2, q2, #1                     \n"
  1.1826 +
  1.1827 +    "subs       %4, %4, #16                    \n"  // 32 processed per loop.
  1.1828 +    RGBTOUV(q2, q1, q0)
  1.1829 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1830 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1831 +    "bgt        1b                             \n"
  1.1832 +  : "+r"(src_raw),  // %0
  1.1833 +    "+r"(src_stride_raw),  // %1
  1.1834 +    "+r"(dst_u),     // %2
  1.1835 +    "+r"(dst_v),     // %3
  1.1836 +    "+r"(pix)        // %4
  1.1837 +  :
  1.1838 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1839 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1840 +  );
  1.1841 +}
  1.1842 +
  1.1843 +// 16x2 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
  1.1844 +void RGB565ToUVRow_NEON(const uint8* src_rgb565, int src_stride_rgb565,
  1.1845 +                        uint8* dst_u, uint8* dst_v, int pix) {
  1.1846 +  asm volatile (
  1.1847 +    "add        %1, %0, %1                     \n"  // src_stride + src_argb
  1.1848 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1849 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1850 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1851 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1852 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1853 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1854 +    ".p2align   2                              \n"
  1.1855 +  "1:                                          \n"
  1.1856 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 RGB565 pixels.
  1.1857 +    RGB565TOARGB
  1.1858 +    "vpaddl.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1859 +    "vpaddl.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1860 +    "vpaddl.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1861 +    "vld1.8     {q0}, [%0]!                    \n"  // next 8 RGB565 pixels.
  1.1862 +    RGB565TOARGB
  1.1863 +    "vpaddl.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1864 +    "vpaddl.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1865 +    "vpaddl.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1866 +
  1.1867 +    "vld1.8     {q0}, [%1]!                    \n"  // load 8 RGB565 pixels.
  1.1868 +    RGB565TOARGB
  1.1869 +    "vpadal.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1870 +    "vpadal.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1871 +    "vpadal.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1872 +    "vld1.8     {q0}, [%1]!                    \n"  // next 8 RGB565 pixels.
  1.1873 +    RGB565TOARGB
  1.1874 +    "vpadal.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1875 +    "vpadal.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1876 +    "vpadal.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1877 +
  1.1878 +    "vrshr.u16  q4, q4, #1                     \n"  // 2x average
  1.1879 +    "vrshr.u16  q5, q5, #1                     \n"
  1.1880 +    "vrshr.u16  q6, q6, #1                     \n"
  1.1881 +
  1.1882 +    "subs       %4, %4, #16                    \n"  // 16 processed per loop.
  1.1883 +    "vmul.s16   q8, q4, q10                    \n"  // B
  1.1884 +    "vmls.s16   q8, q5, q11                    \n"  // G
  1.1885 +    "vmls.s16   q8, q6, q12                    \n"  // R
  1.1886 +    "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
  1.1887 +    "vmul.s16   q9, q6, q10                    \n"  // R
  1.1888 +    "vmls.s16   q9, q5, q14                    \n"  // G
  1.1889 +    "vmls.s16   q9, q4, q13                    \n"  // B
  1.1890 +    "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
  1.1891 +    "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
  1.1892 +    "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
  1.1893 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1894 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1895 +    "bgt        1b                             \n"
  1.1896 +  : "+r"(src_rgb565),  // %0
  1.1897 +    "+r"(src_stride_rgb565),  // %1
  1.1898 +    "+r"(dst_u),     // %2
  1.1899 +    "+r"(dst_v),     // %3
  1.1900 +    "+r"(pix)        // %4
  1.1901 +  :
  1.1902 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1903 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1904 +  );
  1.1905 +}
  1.1906 +
  1.1907 +// 16x2 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
  1.1908 +void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, int src_stride_argb1555,
  1.1909 +                        uint8* dst_u, uint8* dst_v, int pix) {
  1.1910 +  asm volatile (
  1.1911 +    "add        %1, %0, %1                     \n"  // src_stride + src_argb
  1.1912 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1913 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1914 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1915 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1916 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1917 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1918 +    ".p2align   2                              \n"
  1.1919 +  "1:                                          \n"
  1.1920 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB1555 pixels.
  1.1921 +    RGB555TOARGB
  1.1922 +    "vpaddl.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1923 +    "vpaddl.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1924 +    "vpaddl.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1925 +    "vld1.8     {q0}, [%0]!                    \n"  // next 8 ARGB1555 pixels.
  1.1926 +    RGB555TOARGB
  1.1927 +    "vpaddl.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1928 +    "vpaddl.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1929 +    "vpaddl.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1930 +
  1.1931 +    "vld1.8     {q0}, [%1]!                    \n"  // load 8 ARGB1555 pixels.
  1.1932 +    RGB555TOARGB
  1.1933 +    "vpadal.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1934 +    "vpadal.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1935 +    "vpadal.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1936 +    "vld1.8     {q0}, [%1]!                    \n"  // next 8 ARGB1555 pixels.
  1.1937 +    RGB555TOARGB
  1.1938 +    "vpadal.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1939 +    "vpadal.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1940 +    "vpadal.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1941 +
  1.1942 +    "vrshr.u16  q4, q4, #1                     \n"  // 2x average
  1.1943 +    "vrshr.u16  q5, q5, #1                     \n"
  1.1944 +    "vrshr.u16  q6, q6, #1                     \n"
  1.1945 +
  1.1946 +    "subs       %4, %4, #16                    \n"  // 16 processed per loop.
  1.1947 +    "vmul.s16   q8, q4, q10                    \n"  // B
  1.1948 +    "vmls.s16   q8, q5, q11                    \n"  // G
  1.1949 +    "vmls.s16   q8, q6, q12                    \n"  // R
  1.1950 +    "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
  1.1951 +    "vmul.s16   q9, q6, q10                    \n"  // R
  1.1952 +    "vmls.s16   q9, q5, q14                    \n"  // G
  1.1953 +    "vmls.s16   q9, q4, q13                    \n"  // B
  1.1954 +    "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
  1.1955 +    "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
  1.1956 +    "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
  1.1957 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.1958 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.1959 +    "bgt        1b                             \n"
  1.1960 +  : "+r"(src_argb1555),  // %0
  1.1961 +    "+r"(src_stride_argb1555),  // %1
  1.1962 +    "+r"(dst_u),     // %2
  1.1963 +    "+r"(dst_v),     // %3
  1.1964 +    "+r"(pix)        // %4
  1.1965 +  :
  1.1966 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.1967 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.1968 +  );
  1.1969 +}
  1.1970 +
  1.1971 +// 16x2 pixels -> 8x1.  pix is number of argb pixels. e.g. 16.
  1.1972 +void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, int src_stride_argb4444,
  1.1973 +                          uint8* dst_u, uint8* dst_v, int pix) {
  1.1974 +  asm volatile (
  1.1975 +    "add        %1, %0, %1                     \n"  // src_stride + src_argb
  1.1976 +    "vmov.s16   q10, #112 / 2                  \n"  // UB / VR 0.875 coefficient
  1.1977 +    "vmov.s16   q11, #74 / 2                   \n"  // UG -0.5781 coefficient
  1.1978 +    "vmov.s16   q12, #38 / 2                   \n"  // UR -0.2969 coefficient
  1.1979 +    "vmov.s16   q13, #18 / 2                   \n"  // VB -0.1406 coefficient
  1.1980 +    "vmov.s16   q14, #94 / 2                   \n"  // VG -0.7344 coefficient
  1.1981 +    "vmov.u16   q15, #0x8080                   \n"  // 128.5
  1.1982 +    ".p2align   2                              \n"
  1.1983 +  "1:                                          \n"
  1.1984 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB4444 pixels.
  1.1985 +    ARGB4444TOARGB
  1.1986 +    "vpaddl.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1987 +    "vpaddl.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1988 +    "vpaddl.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1989 +    "vld1.8     {q0}, [%0]!                    \n"  // next 8 ARGB4444 pixels.
  1.1990 +    ARGB4444TOARGB
  1.1991 +    "vpaddl.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1992 +    "vpaddl.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1993 +    "vpaddl.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.1994 +
  1.1995 +    "vld1.8     {q0}, [%1]!                    \n"  // load 8 ARGB4444 pixels.
  1.1996 +    ARGB4444TOARGB
  1.1997 +    "vpadal.u8  d8, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.1998 +    "vpadal.u8  d10, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.1999 +    "vpadal.u8  d12, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.2000 +    "vld1.8     {q0}, [%1]!                    \n"  // next 8 ARGB4444 pixels.
  1.2001 +    ARGB4444TOARGB
  1.2002 +    "vpadal.u8  d9, d0                         \n"  // B 8 bytes -> 4 shorts.
  1.2003 +    "vpadal.u8  d11, d1                        \n"  // G 8 bytes -> 4 shorts.
  1.2004 +    "vpadal.u8  d13, d2                        \n"  // R 8 bytes -> 4 shorts.
  1.2005 +
  1.2006 +    "vrshr.u16  q4, q4, #1                     \n"  // 2x average
  1.2007 +    "vrshr.u16  q5, q5, #1                     \n"
  1.2008 +    "vrshr.u16  q6, q6, #1                     \n"
  1.2009 +
  1.2010 +    "subs       %4, %4, #16                    \n"  // 16 processed per loop.
  1.2011 +    "vmul.s16   q8, q4, q10                    \n"  // B
  1.2012 +    "vmls.s16   q8, q5, q11                    \n"  // G
  1.2013 +    "vmls.s16   q8, q6, q12                    \n"  // R
  1.2014 +    "vadd.u16   q8, q8, q15                    \n"  // +128 -> unsigned
  1.2015 +    "vmul.s16   q9, q6, q10                    \n"  // R
  1.2016 +    "vmls.s16   q9, q5, q14                    \n"  // G
  1.2017 +    "vmls.s16   q9, q4, q13                    \n"  // B
  1.2018 +    "vadd.u16   q9, q9, q15                    \n"  // +128 -> unsigned
  1.2019 +    "vqshrn.u16  d0, q8, #8                    \n"  // 16 bit to 8 bit U
  1.2020 +    "vqshrn.u16  d1, q9, #8                    \n"  // 16 bit to 8 bit V
  1.2021 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 pixels U.
  1.2022 +    "vst1.8     {d1}, [%3]!                    \n"  // store 8 pixels V.
  1.2023 +    "bgt        1b                             \n"
  1.2024 +  : "+r"(src_argb4444),  // %0
  1.2025 +    "+r"(src_stride_argb4444),  // %1
  1.2026 +    "+r"(dst_u),     // %2
  1.2027 +    "+r"(dst_v),     // %3
  1.2028 +    "+r"(pix)        // %4
  1.2029 +  :
  1.2030 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
  1.2031 +    "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
  1.2032 +  );
  1.2033 +}
  1.2034 +
  1.2035 +void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int pix) {
  1.2036 +  asm volatile (
  1.2037 +    "vmov.u8    d24, #13                       \n"  // B * 0.1016 coefficient
  1.2038 +    "vmov.u8    d25, #65                       \n"  // G * 0.5078 coefficient
  1.2039 +    "vmov.u8    d26, #33                       \n"  // R * 0.2578 coefficient
  1.2040 +    "vmov.u8    d27, #16                       \n"  // Add 16 constant
  1.2041 +    ".p2align   2                              \n"
  1.2042 +  "1:                                          \n"
  1.2043 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 RGB565 pixels.
  1.2044 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2045 +    RGB565TOARGB
  1.2046 +    "vmull.u8   q2, d0, d24                    \n"  // B
  1.2047 +    "vmlal.u8   q2, d1, d25                    \n"  // G
  1.2048 +    "vmlal.u8   q2, d2, d26                    \n"  // R
  1.2049 +    "vqrshrun.s16 d0, q2, #7                   \n"  // 16 bit to 8 bit Y
  1.2050 +    "vqadd.u8   d0, d27                        \n"
  1.2051 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.2052 +    "bgt        1b                             \n"
  1.2053 +  : "+r"(src_rgb565),  // %0
  1.2054 +    "+r"(dst_y),       // %1
  1.2055 +    "+r"(pix)          // %2
  1.2056 +  :
  1.2057 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
  1.2058 +  );
  1.2059 +}
  1.2060 +
  1.2061 +void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int pix) {
  1.2062 +  asm volatile (
  1.2063 +    "vmov.u8    d24, #13                       \n"  // B * 0.1016 coefficient
  1.2064 +    "vmov.u8    d25, #65                       \n"  // G * 0.5078 coefficient
  1.2065 +    "vmov.u8    d26, #33                       \n"  // R * 0.2578 coefficient
  1.2066 +    "vmov.u8    d27, #16                       \n"  // Add 16 constant
  1.2067 +    ".p2align   2                              \n"
  1.2068 +  "1:                                          \n"
  1.2069 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB1555 pixels.
  1.2070 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2071 +    ARGB1555TOARGB
  1.2072 +    "vmull.u8   q2, d0, d24                    \n"  // B
  1.2073 +    "vmlal.u8   q2, d1, d25                    \n"  // G
  1.2074 +    "vmlal.u8   q2, d2, d26                    \n"  // R
  1.2075 +    "vqrshrun.s16 d0, q2, #7                   \n"  // 16 bit to 8 bit Y
  1.2076 +    "vqadd.u8   d0, d27                        \n"
  1.2077 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.2078 +    "bgt        1b                             \n"
  1.2079 +  : "+r"(src_argb1555),  // %0
  1.2080 +    "+r"(dst_y),         // %1
  1.2081 +    "+r"(pix)            // %2
  1.2082 +  :
  1.2083 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
  1.2084 +  );
  1.2085 +}
  1.2086 +
  1.2087 +void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int pix) {
  1.2088 +  asm volatile (
  1.2089 +    "vmov.u8    d24, #13                       \n"  // B * 0.1016 coefficient
  1.2090 +    "vmov.u8    d25, #65                       \n"  // G * 0.5078 coefficient
  1.2091 +    "vmov.u8    d26, #33                       \n"  // R * 0.2578 coefficient
  1.2092 +    "vmov.u8    d27, #16                       \n"  // Add 16 constant
  1.2093 +    ".p2align   2                              \n"
  1.2094 +  "1:                                          \n"
  1.2095 +    "vld1.8     {q0}, [%0]!                    \n"  // load 8 ARGB4444 pixels.
  1.2096 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2097 +    ARGB4444TOARGB
  1.2098 +    "vmull.u8   q2, d0, d24                    \n"  // B
  1.2099 +    "vmlal.u8   q2, d1, d25                    \n"  // G
  1.2100 +    "vmlal.u8   q2, d2, d26                    \n"  // R
  1.2101 +    "vqrshrun.s16 d0, q2, #7                   \n"  // 16 bit to 8 bit Y
  1.2102 +    "vqadd.u8   d0, d27                        \n"
  1.2103 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.2104 +    "bgt        1b                             \n"
  1.2105 +  : "+r"(src_argb4444),  // %0
  1.2106 +    "+r"(dst_y),         // %1
  1.2107 +    "+r"(pix)            // %2
  1.2108 +  :
  1.2109 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
  1.2110 +  );
  1.2111 +}
  1.2112 +
  1.2113 +void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int pix) {
  1.2114 +  asm volatile (
  1.2115 +    "vmov.u8    d4, #33                        \n"  // R * 0.2578 coefficient
  1.2116 +    "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
  1.2117 +    "vmov.u8    d6, #13                        \n"  // B * 0.1016 coefficient
  1.2118 +    "vmov.u8    d7, #16                        \n"  // Add 16 constant
  1.2119 +    ".p2align   2                              \n"
  1.2120 +  "1:                                          \n"
  1.2121 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of BGRA.
  1.2122 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2123 +    "vmull.u8   q8, d1, d4                     \n"  // R
  1.2124 +    "vmlal.u8   q8, d2, d5                     \n"  // G
  1.2125 +    "vmlal.u8   q8, d3, d6                     \n"  // B
  1.2126 +    "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
  1.2127 +    "vqadd.u8   d0, d7                         \n"
  1.2128 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.2129 +    "bgt        1b                             \n"
  1.2130 +  : "+r"(src_bgra),  // %0
  1.2131 +    "+r"(dst_y),     // %1
  1.2132 +    "+r"(pix)        // %2
  1.2133 +  :
  1.2134 +  : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
  1.2135 +  );
  1.2136 +}
  1.2137 +
  1.2138 +void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int pix) {
  1.2139 +  asm volatile (
  1.2140 +    "vmov.u8    d4, #33                        \n"  // R * 0.2578 coefficient
  1.2141 +    "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
  1.2142 +    "vmov.u8    d6, #13                        \n"  // B * 0.1016 coefficient
  1.2143 +    "vmov.u8    d7, #16                        \n"  // Add 16 constant
  1.2144 +    ".p2align   2                              \n"
  1.2145 +  "1:                                          \n"
  1.2146 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of ABGR.
  1.2147 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2148 +    "vmull.u8   q8, d0, d4                     \n"  // R
  1.2149 +    "vmlal.u8   q8, d1, d5                     \n"  // G
  1.2150 +    "vmlal.u8   q8, d2, d6                     \n"  // B
  1.2151 +    "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
  1.2152 +    "vqadd.u8   d0, d7                         \n"
  1.2153 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.2154 +    "bgt        1b                             \n"
  1.2155 +  : "+r"(src_abgr),  // %0
  1.2156 +    "+r"(dst_y),  // %1
  1.2157 +    "+r"(pix)        // %2
  1.2158 +  :
  1.2159 +  : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
  1.2160 +  );
  1.2161 +}
  1.2162 +
  1.2163 +void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int pix) {
  1.2164 +  asm volatile (
  1.2165 +    "vmov.u8    d4, #13                        \n"  // B * 0.1016 coefficient
  1.2166 +    "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
  1.2167 +    "vmov.u8    d6, #33                        \n"  // R * 0.2578 coefficient
  1.2168 +    "vmov.u8    d7, #16                        \n"  // Add 16 constant
  1.2169 +    ".p2align   2                              \n"
  1.2170 +  "1:                                          \n"
  1.2171 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of RGBA.
  1.2172 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2173 +    "vmull.u8   q8, d1, d4                     \n"  // B
  1.2174 +    "vmlal.u8   q8, d2, d5                     \n"  // G
  1.2175 +    "vmlal.u8   q8, d3, d6                     \n"  // R
  1.2176 +    "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
  1.2177 +    "vqadd.u8   d0, d7                         \n"
  1.2178 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.2179 +    "bgt        1b                             \n"
  1.2180 +  : "+r"(src_rgba),  // %0
  1.2181 +    "+r"(dst_y),  // %1
  1.2182 +    "+r"(pix)        // %2
  1.2183 +  :
  1.2184 +  : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
  1.2185 +  );
  1.2186 +}
  1.2187 +
  1.2188 +void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int pix) {
  1.2189 +  asm volatile (
  1.2190 +    "vmov.u8    d4, #13                        \n"  // B * 0.1016 coefficient
  1.2191 +    "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
  1.2192 +    "vmov.u8    d6, #33                        \n"  // R * 0.2578 coefficient
  1.2193 +    "vmov.u8    d7, #16                        \n"  // Add 16 constant
  1.2194 +    ".p2align   2                              \n"
  1.2195 +  "1:                                          \n"
  1.2196 +    "vld3.8     {d0, d1, d2}, [%0]!            \n"  // load 8 pixels of RGB24.
  1.2197 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2198 +    "vmull.u8   q8, d0, d4                     \n"  // B
  1.2199 +    "vmlal.u8   q8, d1, d5                     \n"  // G
  1.2200 +    "vmlal.u8   q8, d2, d6                     \n"  // R
  1.2201 +    "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
  1.2202 +    "vqadd.u8   d0, d7                         \n"
  1.2203 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.2204 +    "bgt        1b                             \n"
  1.2205 +  : "+r"(src_rgb24),  // %0
  1.2206 +    "+r"(dst_y),  // %1
  1.2207 +    "+r"(pix)        // %2
  1.2208 +  :
  1.2209 +  : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
  1.2210 +  );
  1.2211 +}
  1.2212 +
  1.2213 +void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int pix) {
  1.2214 +  asm volatile (
  1.2215 +    "vmov.u8    d4, #33                        \n"  // R * 0.2578 coefficient
  1.2216 +    "vmov.u8    d5, #65                        \n"  // G * 0.5078 coefficient
  1.2217 +    "vmov.u8    d6, #13                        \n"  // B * 0.1016 coefficient
  1.2218 +    "vmov.u8    d7, #16                        \n"  // Add 16 constant
  1.2219 +    ".p2align   2                              \n"
  1.2220 +  "1:                                          \n"
  1.2221 +    "vld3.8     {d0, d1, d2}, [%0]!            \n"  // load 8 pixels of RAW.
  1.2222 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2223 +    "vmull.u8   q8, d0, d4                     \n"  // B
  1.2224 +    "vmlal.u8   q8, d1, d5                     \n"  // G
  1.2225 +    "vmlal.u8   q8, d2, d6                     \n"  // R
  1.2226 +    "vqrshrun.s16 d0, q8, #7                   \n"  // 16 bit to 8 bit Y
  1.2227 +    "vqadd.u8   d0, d7                         \n"
  1.2228 +    "vst1.8     {d0}, [%1]!                    \n"  // store 8 pixels Y.
  1.2229 +    "bgt        1b                             \n"
  1.2230 +  : "+r"(src_raw),  // %0
  1.2231 +    "+r"(dst_y),  // %1
  1.2232 +    "+r"(pix)        // %2
  1.2233 +  :
  1.2234 +  : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
  1.2235 +  );
  1.2236 +}
  1.2237 +
  1.2238 +// Bilinear filter 16x2 -> 16x1
  1.2239 +void InterpolateRow_NEON(uint8* dst_ptr,
  1.2240 +                         const uint8* src_ptr, ptrdiff_t src_stride,
  1.2241 +                         int dst_width, int source_y_fraction) {
  1.2242 +  asm volatile (
  1.2243 +    "cmp        %4, #0                         \n"
  1.2244 +    "beq        100f                           \n"
  1.2245 +    "add        %2, %1                         \n"
  1.2246 +    "cmp        %4, #64                        \n"
  1.2247 +    "beq        75f                            \n"
  1.2248 +    "cmp        %4, #128                       \n"
  1.2249 +    "beq        50f                            \n"
  1.2250 +    "cmp        %4, #192                       \n"
  1.2251 +    "beq        25f                            \n"
  1.2252 +
  1.2253 +    "vdup.8     d5, %4                         \n"
  1.2254 +    "rsb        %4, #256                       \n"
  1.2255 +    "vdup.8     d4, %4                         \n"
  1.2256 +    // General purpose row blend.
  1.2257 +  "1:                                          \n"
  1.2258 +    "vld1.8     {q0}, [%1]!                    \n"
  1.2259 +    "vld1.8     {q1}, [%2]!                    \n"
  1.2260 +    "subs       %3, %3, #16                    \n"
  1.2261 +    "vmull.u8   q13, d0, d4                    \n"
  1.2262 +    "vmull.u8   q14, d1, d4                    \n"
  1.2263 +    "vmlal.u8   q13, d2, d5                    \n"
  1.2264 +    "vmlal.u8   q14, d3, d5                    \n"
  1.2265 +    "vrshrn.u16 d0, q13, #8                    \n"
  1.2266 +    "vrshrn.u16 d1, q14, #8                    \n"
  1.2267 +    "vst1.8     {q0}, [%0]!                    \n"
  1.2268 +    "bgt        1b                             \n"
  1.2269 +    "b          99f                            \n"
  1.2270 +
  1.2271 +    // Blend 25 / 75.
  1.2272 +  "25:                                         \n"
  1.2273 +    "vld1.8     {q0}, [%1]!                    \n"
  1.2274 +    "vld1.8     {q1}, [%2]!                    \n"
  1.2275 +    "subs       %3, %3, #16                    \n"
  1.2276 +    "vrhadd.u8  q0, q1                         \n"
  1.2277 +    "vrhadd.u8  q0, q1                         \n"
  1.2278 +    "vst1.8     {q0}, [%0]!                    \n"
  1.2279 +    "bgt        25b                            \n"
  1.2280 +    "b          99f                            \n"
  1.2281 +
  1.2282 +    // Blend 50 / 50.
  1.2283 +  "50:                                         \n"
  1.2284 +    "vld1.8     {q0}, [%1]!                    \n"
  1.2285 +    "vld1.8     {q1}, [%2]!                    \n"
  1.2286 +    "subs       %3, %3, #16                    \n"
  1.2287 +    "vrhadd.u8  q0, q1                         \n"
  1.2288 +    "vst1.8     {q0}, [%0]!                    \n"
  1.2289 +    "bgt        50b                            \n"
  1.2290 +    "b          99f                            \n"
  1.2291 +
  1.2292 +    // Blend 75 / 25.
  1.2293 +  "75:                                         \n"
  1.2294 +    "vld1.8     {q1}, [%1]!                    \n"
  1.2295 +    "vld1.8     {q0}, [%2]!                    \n"
  1.2296 +    "subs       %3, %3, #16                    \n"
  1.2297 +    "vrhadd.u8  q0, q1                         \n"
  1.2298 +    "vrhadd.u8  q0, q1                         \n"
  1.2299 +    "vst1.8     {q0}, [%0]!                    \n"
  1.2300 +    "bgt        75b                            \n"
  1.2301 +    "b          99f                            \n"
  1.2302 +
  1.2303 +    // Blend 100 / 0 - Copy row unchanged.
  1.2304 +  "100:                                        \n"
  1.2305 +    "vld1.8     {q0}, [%1]!                    \n"
  1.2306 +    "subs       %3, %3, #16                    \n"
  1.2307 +    "vst1.8     {q0}, [%0]!                    \n"
  1.2308 +    "bgt        100b                           \n"
  1.2309 +
  1.2310 +  "99:                                         \n"
  1.2311 +  : "+r"(dst_ptr),          // %0
  1.2312 +    "+r"(src_ptr),          // %1
  1.2313 +    "+r"(src_stride),       // %2
  1.2314 +    "+r"(dst_width),        // %3
  1.2315 +    "+r"(source_y_fraction) // %4
  1.2316 +  :
  1.2317 +  : "cc", "memory", "q0", "q1", "d4", "d5", "q13", "q14"
  1.2318 +  );
  1.2319 +}
  1.2320 +
  1.2321 +// dr * (256 - sa) / 256 + sr = dr - dr * sa / 256 + sr
  1.2322 +void ARGBBlendRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
  1.2323 +                       uint8* dst_argb, int width) {
  1.2324 +  asm volatile (
  1.2325 +    "subs       %3, #8                         \n"
  1.2326 +    "blt        89f                            \n"
  1.2327 +    // Blend 8 pixels.
  1.2328 +  "8:                                          \n"
  1.2329 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of ARGB0.
  1.2330 +    "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load 8 pixels of ARGB1.
  1.2331 +    "subs       %3, %3, #8                     \n"  // 8 processed per loop.
  1.2332 +    "vmull.u8   q10, d4, d3                    \n"  // db * a
  1.2333 +    "vmull.u8   q11, d5, d3                    \n"  // dg * a
  1.2334 +    "vmull.u8   q12, d6, d3                    \n"  // dr * a
  1.2335 +    "vqrshrn.u16 d20, q10, #8                  \n"  // db >>= 8
  1.2336 +    "vqrshrn.u16 d21, q11, #8                  \n"  // dg >>= 8
  1.2337 +    "vqrshrn.u16 d22, q12, #8                  \n"  // dr >>= 8
  1.2338 +    "vqsub.u8   q2, q2, q10                    \n"  // dbg - dbg * a / 256
  1.2339 +    "vqsub.u8   d6, d6, d22                    \n"  // dr - dr * a / 256
  1.2340 +    "vqadd.u8   q0, q0, q2                     \n"  // + sbg
  1.2341 +    "vqadd.u8   d2, d2, d6                     \n"  // + sr
  1.2342 +    "vmov.u8    d3, #255                       \n"  // a = 255
  1.2343 +    "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 pixels of ARGB.
  1.2344 +    "bge        8b                             \n"
  1.2345 +
  1.2346 +  "89:                                         \n"
  1.2347 +    "adds       %3, #8-1                       \n"
  1.2348 +    "blt        99f                            \n"
  1.2349 +
  1.2350 +    // Blend 1 pixels.
  1.2351 +  "1:                                          \n"
  1.2352 +    "vld4.8     {d0[0],d1[0],d2[0],d3[0]}, [%0]! \n"  // load 1 pixel ARGB0.
  1.2353 +    "vld4.8     {d4[0],d5[0],d6[0],d7[0]}, [%1]! \n"  // load 1 pixel ARGB1.
  1.2354 +    "subs       %3, %3, #1                     \n"  // 1 processed per loop.
  1.2355 +    "vmull.u8   q10, d4, d3                    \n"  // db * a
  1.2356 +    "vmull.u8   q11, d5, d3                    \n"  // dg * a
  1.2357 +    "vmull.u8   q12, d6, d3                    \n"  // dr * a
  1.2358 +    "vqrshrn.u16 d20, q10, #8                  \n"  // db >>= 8
  1.2359 +    "vqrshrn.u16 d21, q11, #8                  \n"  // dg >>= 8
  1.2360 +    "vqrshrn.u16 d22, q12, #8                  \n"  // dr >>= 8
  1.2361 +    "vqsub.u8   q2, q2, q10                    \n"  // dbg - dbg * a / 256
  1.2362 +    "vqsub.u8   d6, d6, d22                    \n"  // dr - dr * a / 256
  1.2363 +    "vqadd.u8   q0, q0, q2                     \n"  // + sbg
  1.2364 +    "vqadd.u8   d2, d2, d6                     \n"  // + sr
  1.2365 +    "vmov.u8    d3, #255                       \n"  // a = 255
  1.2366 +    "vst4.8     {d0[0],d1[0],d2[0],d3[0]}, [%2]! \n"  // store 1 pixel.
  1.2367 +    "bge        1b                             \n"
  1.2368 +
  1.2369 +  "99:                                         \n"
  1.2370 +
  1.2371 +  : "+r"(src_argb0),    // %0
  1.2372 +    "+r"(src_argb1),    // %1
  1.2373 +    "+r"(dst_argb),     // %2
  1.2374 +    "+r"(width)         // %3
  1.2375 +  :
  1.2376 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q10", "q11", "q12"
  1.2377 +  );
  1.2378 +}
  1.2379 +
  1.2380 +// Attenuate 8 pixels at a time.
  1.2381 +void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) {
  1.2382 +  asm volatile (
  1.2383 +    // Attenuate 8 pixels.
  1.2384 +  "1:                                          \n"
  1.2385 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 pixels of ARGB.
  1.2386 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2387 +    "vmull.u8   q10, d0, d3                    \n"  // b * a
  1.2388 +    "vmull.u8   q11, d1, d3                    \n"  // g * a
  1.2389 +    "vmull.u8   q12, d2, d3                    \n"  // r * a
  1.2390 +    "vqrshrn.u16 d0, q10, #8                   \n"  // b >>= 8
  1.2391 +    "vqrshrn.u16 d1, q11, #8                   \n"  // g >>= 8
  1.2392 +    "vqrshrn.u16 d2, q12, #8                   \n"  // r >>= 8
  1.2393 +    "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 pixels of ARGB.
  1.2394 +    "bgt        1b                             \n"
  1.2395 +  : "+r"(src_argb),   // %0
  1.2396 +    "+r"(dst_argb),   // %1
  1.2397 +    "+r"(width)       // %2
  1.2398 +  :
  1.2399 +  : "cc", "memory", "q0", "q1", "q10", "q11", "q12"
  1.2400 +  );
  1.2401 +}
  1.2402 +
  1.2403 +// Quantize 8 ARGB pixels (32 bytes).
  1.2404 +// dst = (dst * scale >> 16) * interval_size + interval_offset;
  1.2405 +void ARGBQuantizeRow_NEON(uint8* dst_argb, int scale, int interval_size,
  1.2406 +                          int interval_offset, int width) {
  1.2407 +  asm volatile (
  1.2408 +    "vdup.u16   q8, %2                         \n"
  1.2409 +    "vshr.u16   q8, q8, #1                     \n"  // scale >>= 1
  1.2410 +    "vdup.u16   q9, %3                         \n"  // interval multiply.
  1.2411 +    "vdup.u16   q10, %4                        \n"  // interval add
  1.2412 +
  1.2413 +    // 8 pixel loop.
  1.2414 +    ".p2align   2                              \n"
  1.2415 +  "1:                                          \n"
  1.2416 +    "vld4.8     {d0, d2, d4, d6}, [%0]         \n"  // load 8 pixels of ARGB.
  1.2417 +    "subs       %1, %1, #8                     \n"  // 8 processed per loop.
  1.2418 +    "vmovl.u8   q0, d0                         \n"  // b (0 .. 255)
  1.2419 +    "vmovl.u8   q1, d2                         \n"
  1.2420 +    "vmovl.u8   q2, d4                         \n"
  1.2421 +    "vqdmulh.s16 q0, q0, q8                    \n"  // b * scale
  1.2422 +    "vqdmulh.s16 q1, q1, q8                    \n"  // g
  1.2423 +    "vqdmulh.s16 q2, q2, q8                    \n"  // r
  1.2424 +    "vmul.u16   q0, q0, q9                     \n"  // b * interval_size
  1.2425 +    "vmul.u16   q1, q1, q9                     \n"  // g
  1.2426 +    "vmul.u16   q2, q2, q9                     \n"  // r
  1.2427 +    "vadd.u16   q0, q0, q10                    \n"  // b + interval_offset
  1.2428 +    "vadd.u16   q1, q1, q10                    \n"  // g
  1.2429 +    "vadd.u16   q2, q2, q10                    \n"  // r
  1.2430 +    "vqmovn.u16 d0, q0                         \n"
  1.2431 +    "vqmovn.u16 d2, q1                         \n"
  1.2432 +    "vqmovn.u16 d4, q2                         \n"
  1.2433 +    "vst4.8     {d0, d2, d4, d6}, [%0]!        \n"  // store 8 pixels of ARGB.
  1.2434 +    "bgt        1b                             \n"
  1.2435 +  : "+r"(dst_argb),       // %0
  1.2436 +    "+r"(width)           // %1
  1.2437 +  : "r"(scale),           // %2
  1.2438 +    "r"(interval_size),   // %3
  1.2439 +    "r"(interval_offset)  // %4
  1.2440 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10"
  1.2441 +  );
  1.2442 +}
  1.2443 +
  1.2444 +// Shade 8 pixels at a time by specified value.
  1.2445 +// NOTE vqrdmulh.s16 q10, q10, d0[0] must use a scaler register from 0 to 8.
  1.2446 +// Rounding in vqrdmulh does +1 to high if high bit of low s16 is set.
  1.2447 +void ARGBShadeRow_NEON(const uint8* src_argb, uint8* dst_argb, int width,
  1.2448 +                       uint32 value) {
  1.2449 +  asm volatile (
  1.2450 +    "vdup.u32   q0, %3                         \n"  // duplicate scale value.
  1.2451 +    "vzip.u8    d0, d1                         \n"  // d0 aarrggbb.
  1.2452 +    "vshr.u16   q0, q0, #1                     \n"  // scale / 2.
  1.2453 +
  1.2454 +    // 8 pixel loop.
  1.2455 +    ".p2align   2                              \n"
  1.2456 +  "1:                                          \n"
  1.2457 +    "vld4.8     {d20, d22, d24, d26}, [%0]!    \n"  // load 8 pixels of ARGB.
  1.2458 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2459 +    "vmovl.u8   q10, d20                       \n"  // b (0 .. 255)
  1.2460 +    "vmovl.u8   q11, d22                       \n"
  1.2461 +    "vmovl.u8   q12, d24                       \n"
  1.2462 +    "vmovl.u8   q13, d26                       \n"
  1.2463 +    "vqrdmulh.s16 q10, q10, d0[0]              \n"  // b * scale * 2
  1.2464 +    "vqrdmulh.s16 q11, q11, d0[1]              \n"  // g
  1.2465 +    "vqrdmulh.s16 q12, q12, d0[2]              \n"  // r
  1.2466 +    "vqrdmulh.s16 q13, q13, d0[3]              \n"  // a
  1.2467 +    "vqmovn.u16 d20, q10                       \n"
  1.2468 +    "vqmovn.u16 d22, q11                       \n"
  1.2469 +    "vqmovn.u16 d24, q12                       \n"
  1.2470 +    "vqmovn.u16 d26, q13                       \n"
  1.2471 +    "vst4.8     {d20, d22, d24, d26}, [%1]!    \n"  // store 8 pixels of ARGB.
  1.2472 +    "bgt        1b                             \n"
  1.2473 +  : "+r"(src_argb),       // %0
  1.2474 +    "+r"(dst_argb),       // %1
  1.2475 +    "+r"(width)           // %2
  1.2476 +  : "r"(value)            // %3
  1.2477 +  : "cc", "memory", "q0", "q10", "q11", "q12", "q13"
  1.2478 +  );
  1.2479 +}
  1.2480 +
  1.2481 +// Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels
  1.2482 +// Similar to ARGBToYJ but stores ARGB.
  1.2483 +// C code is (15 * b + 75 * g + 38 * r + 64) >> 7;
  1.2484 +void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) {
  1.2485 +  asm volatile (
  1.2486 +    "vmov.u8    d24, #15                       \n"  // B * 0.11400 coefficient
  1.2487 +    "vmov.u8    d25, #75                       \n"  // G * 0.58700 coefficient
  1.2488 +    "vmov.u8    d26, #38                       \n"  // R * 0.29900 coefficient
  1.2489 +    ".p2align   2                              \n"
  1.2490 +  "1:                                          \n"
  1.2491 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
  1.2492 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2493 +    "vmull.u8   q2, d0, d24                    \n"  // B
  1.2494 +    "vmlal.u8   q2, d1, d25                    \n"  // G
  1.2495 +    "vmlal.u8   q2, d2, d26                    \n"  // R
  1.2496 +    "vqrshrun.s16 d0, q2, #7                   \n"  // 15 bit to 8 bit B
  1.2497 +    "vmov       d1, d0                         \n"  // G
  1.2498 +    "vmov       d2, d0                         \n"  // R
  1.2499 +    "vst4.8     {d0, d1, d2, d3}, [%1]!        \n"  // store 8 ARGB pixels.
  1.2500 +    "bgt        1b                             \n"
  1.2501 +  : "+r"(src_argb),  // %0
  1.2502 +    "+r"(dst_argb),  // %1
  1.2503 +    "+r"(width)      // %2
  1.2504 +  :
  1.2505 +  : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
  1.2506 +  );
  1.2507 +}
  1.2508 +
  1.2509 +// Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels.
  1.2510 +//    b = (r * 35 + g * 68 + b * 17) >> 7
  1.2511 +//    g = (r * 45 + g * 88 + b * 22) >> 7
  1.2512 +//    r = (r * 50 + g * 98 + b * 24) >> 7
  1.2513 +void ARGBSepiaRow_NEON(uint8* dst_argb, int width) {
  1.2514 +  asm volatile (
  1.2515 +    "vmov.u8    d20, #17                       \n"  // BB coefficient
  1.2516 +    "vmov.u8    d21, #68                       \n"  // BG coefficient
  1.2517 +    "vmov.u8    d22, #35                       \n"  // BR coefficient
  1.2518 +    "vmov.u8    d24, #22                       \n"  // GB coefficient
  1.2519 +    "vmov.u8    d25, #88                       \n"  // GG coefficient
  1.2520 +    "vmov.u8    d26, #45                       \n"  // GR coefficient
  1.2521 +    "vmov.u8    d28, #24                       \n"  // BB coefficient
  1.2522 +    "vmov.u8    d29, #98                       \n"  // BG coefficient
  1.2523 +    "vmov.u8    d30, #50                       \n"  // BR coefficient
  1.2524 +    ".p2align   2                              \n"
  1.2525 +  "1:                                          \n"
  1.2526 +    "vld4.8     {d0, d1, d2, d3}, [%0]         \n"  // load 8 ARGB pixels.
  1.2527 +    "subs       %1, %1, #8                     \n"  // 8 processed per loop.
  1.2528 +    "vmull.u8   q2, d0, d20                    \n"  // B to Sepia B
  1.2529 +    "vmlal.u8   q2, d1, d21                    \n"  // G
  1.2530 +    "vmlal.u8   q2, d2, d22                    \n"  // R
  1.2531 +    "vmull.u8   q3, d0, d24                    \n"  // B to Sepia G
  1.2532 +    "vmlal.u8   q3, d1, d25                    \n"  // G
  1.2533 +    "vmlal.u8   q3, d2, d26                    \n"  // R
  1.2534 +    "vmull.u8   q8, d0, d28                    \n"  // B to Sepia R
  1.2535 +    "vmlal.u8   q8, d1, d29                    \n"  // G
  1.2536 +    "vmlal.u8   q8, d2, d30                    \n"  // R
  1.2537 +    "vqshrn.u16 d0, q2, #7                     \n"  // 16 bit to 8 bit B
  1.2538 +    "vqshrn.u16 d1, q3, #7                     \n"  // 16 bit to 8 bit G
  1.2539 +    "vqshrn.u16 d2, q8, #7                     \n"  // 16 bit to 8 bit R
  1.2540 +    "vst4.8     {d0, d1, d2, d3}, [%0]!        \n"  // store 8 ARGB pixels.
  1.2541 +    "bgt        1b                             \n"
  1.2542 +  : "+r"(dst_argb),  // %0
  1.2543 +    "+r"(width)      // %1
  1.2544 +  :
  1.2545 +  : "cc", "memory", "q0", "q1", "q2", "q3",
  1.2546 +    "q10", "q11", "q12", "q13", "q14", "q15"
  1.2547 +  );
  1.2548 +}
  1.2549 +
  1.2550 +// Tranform 8 ARGB pixels (32 bytes) with color matrix.
  1.2551 +// TODO(fbarchard): Was same as Sepia except matrix is provided.  This function
  1.2552 +// needs to saturate.  Consider doing a non-saturating version.
  1.2553 +void ARGBColorMatrixRow_NEON(const uint8* src_argb, uint8* dst_argb,
  1.2554 +                             const int8* matrix_argb, int width) {
  1.2555 +  asm volatile (
  1.2556 +    "vld1.8     {q2}, [%3]                     \n"  // load 3 ARGB vectors.
  1.2557 +    "vmovl.s8   q0, d4                         \n"  // B,G coefficients s16.
  1.2558 +    "vmovl.s8   q1, d5                         \n"  // R,A coefficients s16.
  1.2559 +
  1.2560 +    ".p2align   2                              \n"
  1.2561 +  "1:                                          \n"
  1.2562 +    "vld4.8     {d16, d18, d20, d22}, [%0]!    \n"  // load 8 ARGB pixels.
  1.2563 +    "subs       %2, %2, #8                     \n"  // 8 processed per loop.
  1.2564 +    "vmovl.u8   q8, d16                        \n"  // b (0 .. 255) 16 bit
  1.2565 +    "vmovl.u8   q9, d18                        \n"  // g
  1.2566 +    "vmovl.u8   q10, d20                       \n"  // r
  1.2567 +    "vmovl.u8   q15, d22                       \n"  // a
  1.2568 +    "vmul.s16   q12, q8, d0[0]                 \n"  // B = B * Matrix B
  1.2569 +    "vmul.s16   q13, q8, d1[0]                 \n"  // G = B * Matrix G
  1.2570 +    "vmul.s16   q14, q8, d2[0]                 \n"  // R = B * Matrix R
  1.2571 +    "vmul.s16   q15, q8, d3[0]                 \n"  // A = B * Matrix A
  1.2572 +    "vmul.s16   q4, q9, d0[1]                  \n"  // B += G * Matrix B
  1.2573 +    "vmul.s16   q5, q9, d1[1]                  \n"  // G += G * Matrix G
  1.2574 +    "vmul.s16   q6, q9, d2[1]                  \n"  // R += G * Matrix R
  1.2575 +    "vmul.s16   q7, q9, d3[1]                  \n"  // A += G * Matrix A
  1.2576 +    "vqadd.s16  q12, q12, q4                   \n"  // Accumulate B
  1.2577 +    "vqadd.s16  q13, q13, q5                   \n"  // Accumulate G
  1.2578 +    "vqadd.s16  q14, q14, q6                   \n"  // Accumulate R
  1.2579 +    "vqadd.s16  q15, q15, q7                   \n"  // Accumulate A
  1.2580 +    "vmul.s16   q4, q10, d0[2]                 \n"  // B += R * Matrix B
  1.2581 +    "vmul.s16   q5, q10, d1[2]                 \n"  // G += R * Matrix G
  1.2582 +    "vmul.s16   q6, q10, d2[2]                 \n"  // R += R * Matrix R
  1.2583 +    "vmul.s16   q7, q10, d3[2]                 \n"  // A += R * Matrix A
  1.2584 +    "vqadd.s16  q12, q12, q4                   \n"  // Accumulate B
  1.2585 +    "vqadd.s16  q13, q13, q5                   \n"  // Accumulate G
  1.2586 +    "vqadd.s16  q14, q14, q6                   \n"  // Accumulate R
  1.2587 +    "vqadd.s16  q15, q15, q7                   \n"  // Accumulate A
  1.2588 +    "vmul.s16   q4, q15, d0[3]                 \n"  // B += A * Matrix B
  1.2589 +    "vmul.s16   q5, q15, d1[3]                 \n"  // G += A * Matrix G
  1.2590 +    "vmul.s16   q6, q15, d2[3]                 \n"  // R += A * Matrix R
  1.2591 +    "vmul.s16   q7, q15, d3[3]                 \n"  // A += A * Matrix A
  1.2592 +    "vqadd.s16  q12, q12, q4                   \n"  // Accumulate B
  1.2593 +    "vqadd.s16  q13, q13, q5                   \n"  // Accumulate G
  1.2594 +    "vqadd.s16  q14, q14, q6                   \n"  // Accumulate R
  1.2595 +    "vqadd.s16  q15, q15, q7                   \n"  // Accumulate A
  1.2596 +    "vqshrun.s16 d16, q12, #6                  \n"  // 16 bit to 8 bit B
  1.2597 +    "vqshrun.s16 d18, q13, #6                  \n"  // 16 bit to 8 bit G
  1.2598 +    "vqshrun.s16 d20, q14, #6                  \n"  // 16 bit to 8 bit R
  1.2599 +    "vqshrun.s16 d22, q15, #6                  \n"  // 16 bit to 8 bit A
  1.2600 +    "vst4.8     {d16, d18, d20, d22}, [%1]!    \n"  // store 8 ARGB pixels.
  1.2601 +    "bgt        1b                             \n"
  1.2602 +  : "+r"(src_argb),   // %0
  1.2603 +    "+r"(dst_argb),   // %1
  1.2604 +    "+r"(width)       // %2
  1.2605 +  : "r"(matrix_argb)  // %3
  1.2606 +  : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
  1.2607 +    "q10", "q11", "q12", "q13", "q14", "q15"
  1.2608 +  );
  1.2609 +}
  1.2610 +
  1.2611 +// TODO(fbarchard): fix vqshrun in ARGBMultiplyRow_NEON and reenable.
  1.2612 +#ifdef HAS_ARGBMULTIPLYROW_NEON
  1.2613 +// Multiply 2 rows of ARGB pixels together, 8 pixels at a time.
  1.2614 +void ARGBMultiplyRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
  1.2615 +                          uint8* dst_argb, int width) {
  1.2616 +  asm volatile (
  1.2617 +    // 8 pixel loop.
  1.2618 +    ".p2align   2                              \n"
  1.2619 +  "1:                                          \n"
  1.2620 +    "vld4.8     {d0, d2, d4, d6}, [%0]!        \n"  // load 8 ARGB pixels.
  1.2621 +    "vld4.8     {d1, d3, d5, d7}, [%1]!        \n"  // load 8 more ARGB pixels.
  1.2622 +    "subs       %3, %3, #8                     \n"  // 8 processed per loop.
  1.2623 +    "vmull.u8   q0, d0, d1                     \n"  // multiply B
  1.2624 +    "vmull.u8   q1, d2, d3                     \n"  // multiply G
  1.2625 +    "vmull.u8   q2, d4, d5                     \n"  // multiply R
  1.2626 +    "vmull.u8   q3, d6, d7                     \n"  // multiply A
  1.2627 +    "vrshrn.u16 d0, q0, #8                     \n"  // 16 bit to 8 bit B
  1.2628 +    "vrshrn.u16 d1, q1, #8                     \n"  // 16 bit to 8 bit G
  1.2629 +    "vrshrn.u16 d2, q2, #8                     \n"  // 16 bit to 8 bit R
  1.2630 +    "vrshrn.u16 d3, q3, #8                     \n"  // 16 bit to 8 bit A
  1.2631 +    "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
  1.2632 +    "bgt        1b                             \n"
  1.2633 +
  1.2634 +  : "+r"(src_argb0),  // %0
  1.2635 +    "+r"(src_argb1),  // %1
  1.2636 +    "+r"(dst_argb),   // %2
  1.2637 +    "+r"(width)       // %3
  1.2638 +  :
  1.2639 +  : "cc", "memory", "q0", "q1", "q2", "q3"
  1.2640 +  );
  1.2641 +}
  1.2642 +#endif  // HAS_ARGBMULTIPLYROW_NEON
  1.2643 +
  1.2644 +// Add 2 rows of ARGB pixels together, 8 pixels at a time.
  1.2645 +void ARGBAddRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
  1.2646 +                     uint8* dst_argb, int width) {
  1.2647 +  asm volatile (
  1.2648 +    // 8 pixel loop.
  1.2649 +    ".p2align   2                              \n"
  1.2650 +  "1:                                          \n"
  1.2651 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
  1.2652 +    "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load 8 more ARGB pixels.
  1.2653 +    "subs       %3, %3, #8                     \n"  // 8 processed per loop.
  1.2654 +    "vqadd.u8   q0, q0, q2                     \n"  // add B, G
  1.2655 +    "vqadd.u8   q1, q1, q3                     \n"  // add R, A
  1.2656 +    "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
  1.2657 +    "bgt        1b                             \n"
  1.2658 +
  1.2659 +  : "+r"(src_argb0),  // %0
  1.2660 +    "+r"(src_argb1),  // %1
  1.2661 +    "+r"(dst_argb),   // %2
  1.2662 +    "+r"(width)       // %3
  1.2663 +  :
  1.2664 +  : "cc", "memory", "q0", "q1", "q2", "q3"
  1.2665 +  );
  1.2666 +}
  1.2667 +
  1.2668 +// Subtract 2 rows of ARGB pixels, 8 pixels at a time.
  1.2669 +void ARGBSubtractRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
  1.2670 +                          uint8* dst_argb, int width) {
  1.2671 +  asm volatile (
  1.2672 +    // 8 pixel loop.
  1.2673 +    ".p2align   2                              \n"
  1.2674 +  "1:                                          \n"
  1.2675 +    "vld4.8     {d0, d1, d2, d3}, [%0]!        \n"  // load 8 ARGB pixels.
  1.2676 +    "vld4.8     {d4, d5, d6, d7}, [%1]!        \n"  // load 8 more ARGB pixels.
  1.2677 +    "subs       %3, %3, #8                     \n"  // 8 processed per loop.
  1.2678 +    "vqsub.u8   q0, q0, q2                     \n"  // subtract B, G
  1.2679 +    "vqsub.u8   q1, q1, q3                     \n"  // subtract R, A
  1.2680 +    "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
  1.2681 +    "bgt        1b                             \n"
  1.2682 +
  1.2683 +  : "+r"(src_argb0),  // %0
  1.2684 +    "+r"(src_argb1),  // %1
  1.2685 +    "+r"(dst_argb),   // %2
  1.2686 +    "+r"(width)       // %3
  1.2687 +  :
  1.2688 +  : "cc", "memory", "q0", "q1", "q2", "q3"
  1.2689 +  );
  1.2690 +}
  1.2691 +
  1.2692 +// Adds Sobel X and Sobel Y and stores Sobel into ARGB.
  1.2693 +// A = 255
  1.2694 +// R = Sobel
  1.2695 +// G = Sobel
  1.2696 +// B = Sobel
  1.2697 +void SobelRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
  1.2698 +                     uint8* dst_argb, int width) {
  1.2699 +  asm volatile (
  1.2700 +    "vmov.u8    d3, #255                       \n"  // alpha
  1.2701 +    // 8 pixel loop.
  1.2702 +    ".p2align   2                              \n"
  1.2703 +  "1:                                          \n"
  1.2704 +    "vld1.8     {d0}, [%0]!                    \n"  // load 8 sobelx.
  1.2705 +    "vld1.8     {d1}, [%1]!                    \n"  // load 8 sobely.
  1.2706 +    "subs       %3, %3, #8                     \n"  // 8 processed per loop.
  1.2707 +    "vqadd.u8   d0, d0, d1                     \n"  // add
  1.2708 +    "vmov.u8    d1, d0                         \n"
  1.2709 +    "vmov.u8    d2, d0                         \n"
  1.2710 +    "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
  1.2711 +    "bgt        1b                             \n"
  1.2712 +  : "+r"(src_sobelx),  // %0
  1.2713 +    "+r"(src_sobely),  // %1
  1.2714 +    "+r"(dst_argb),    // %2
  1.2715 +    "+r"(width)        // %3
  1.2716 +  :
  1.2717 +  : "cc", "memory", "q0", "q1"
  1.2718 +  );
  1.2719 +}
  1.2720 +
  1.2721 +// Adds Sobel X and Sobel Y and stores Sobel into plane.
  1.2722 +void SobelToPlaneRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
  1.2723 +                          uint8* dst_y, int width) {
  1.2724 +  asm volatile (
  1.2725 +    // 16 pixel loop.
  1.2726 +    ".p2align   2                              \n"
  1.2727 +  "1:                                          \n"
  1.2728 +    "vld1.8     {q0}, [%0]!                    \n"  // load 16 sobelx.
  1.2729 +    "vld1.8     {q1}, [%1]!                    \n"  // load 16 sobely.
  1.2730 +    "subs       %3, %3, #16                    \n"  // 16 processed per loop.
  1.2731 +    "vqadd.u8   q0, q0, q1                     \n"  // add
  1.2732 +    "vst1.8     {q0}, [%2]!                    \n"  // store 16 pixels.
  1.2733 +    "bgt        1b                             \n"
  1.2734 +  : "+r"(src_sobelx),  // %0
  1.2735 +    "+r"(src_sobely),  // %1
  1.2736 +    "+r"(dst_y),       // %2
  1.2737 +    "+r"(width)        // %3
  1.2738 +  :
  1.2739 +  : "cc", "memory", "q0", "q1"
  1.2740 +  );
  1.2741 +}
  1.2742 +
  1.2743 +// Mixes Sobel X, Sobel Y and Sobel into ARGB.
  1.2744 +// A = 255
  1.2745 +// R = Sobel X
  1.2746 +// G = Sobel
  1.2747 +// B = Sobel Y
  1.2748 +void SobelXYRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
  1.2749 +                     uint8* dst_argb, int width) {
  1.2750 +  asm volatile (
  1.2751 +    "vmov.u8    d3, #255                       \n"  // alpha
  1.2752 +    // 8 pixel loop.
  1.2753 +    ".p2align   2                              \n"
  1.2754 +  "1:                                          \n"
  1.2755 +    "vld1.8     {d2}, [%0]!                    \n"  // load 8 sobelx.
  1.2756 +    "vld1.8     {d0}, [%1]!                    \n"  // load 8 sobely.
  1.2757 +    "subs       %3, %3, #8                     \n"  // 8 processed per loop.
  1.2758 +    "vqadd.u8   d1, d0, d2                     \n"  // add
  1.2759 +    "vst4.8     {d0, d1, d2, d3}, [%2]!        \n"  // store 8 ARGB pixels.
  1.2760 +    "bgt        1b                             \n"
  1.2761 +  : "+r"(src_sobelx),  // %0
  1.2762 +    "+r"(src_sobely),  // %1
  1.2763 +    "+r"(dst_argb),    // %2
  1.2764 +    "+r"(width)        // %3
  1.2765 +  :
  1.2766 +  : "cc", "memory", "q0", "q1"
  1.2767 +  );
  1.2768 +}
  1.2769 +
  1.2770 +// SobelX as a matrix is
  1.2771 +// -1  0  1
  1.2772 +// -2  0  2
  1.2773 +// -1  0  1
  1.2774 +void SobelXRow_NEON(const uint8* src_y0, const uint8* src_y1,
  1.2775 +                    const uint8* src_y2, uint8* dst_sobelx, int width) {
  1.2776 +  asm volatile (
  1.2777 +    ".p2align   2                              \n"
  1.2778 +  "1:                                          \n"
  1.2779 +    "vld1.8     {d0}, [%0],%5                  \n"  // top
  1.2780 +    "vld1.8     {d1}, [%0],%6                  \n"
  1.2781 +    "vsubl.u8   q0, d0, d1                     \n"
  1.2782 +    "vld1.8     {d2}, [%1],%5                  \n"  // center * 2
  1.2783 +    "vld1.8     {d3}, [%1],%6                  \n"
  1.2784 +    "vsubl.u8   q1, d2, d3                     \n"
  1.2785 +    "vadd.s16   q0, q0, q1                     \n"
  1.2786 +    "vadd.s16   q0, q0, q1                     \n"
  1.2787 +    "vld1.8     {d2}, [%2],%5                  \n"  // bottom
  1.2788 +    "vld1.8     {d3}, [%2],%6                  \n"
  1.2789 +    "subs       %4, %4, #8                     \n"  // 8 pixels
  1.2790 +    "vsubl.u8   q1, d2, d3                     \n"
  1.2791 +    "vadd.s16   q0, q0, q1                     \n"
  1.2792 +    "vabs.s16   q0, q0                         \n"
  1.2793 +    "vqmovn.u16 d0, q0                         \n"
  1.2794 +    "vst1.8     {d0}, [%3]!                    \n"  // store 8 sobelx
  1.2795 +    "bgt        1b                             \n"
  1.2796 +  : "+r"(src_y0),      // %0
  1.2797 +    "+r"(src_y1),      // %1
  1.2798 +    "+r"(src_y2),      // %2
  1.2799 +    "+r"(dst_sobelx),  // %3
  1.2800 +    "+r"(width)        // %4
  1.2801 +  : "r"(2),            // %5
  1.2802 +    "r"(6)             // %6
  1.2803 +  : "cc", "memory", "q0", "q1"  // Clobber List
  1.2804 +  );
  1.2805 +}
  1.2806 +
  1.2807 +// SobelY as a matrix is
  1.2808 +// -1 -2 -1
  1.2809 +//  0  0  0
  1.2810 +//  1  2  1
  1.2811 +void SobelYRow_NEON(const uint8* src_y0, const uint8* src_y1,
  1.2812 +                    uint8* dst_sobely, int width) {
  1.2813 +  asm volatile (
  1.2814 +    ".p2align   2                              \n"
  1.2815 +  "1:                                          \n"
  1.2816 +    "vld1.8     {d0}, [%0],%4                  \n"  // left
  1.2817 +    "vld1.8     {d1}, [%1],%4                  \n"
  1.2818 +    "vsubl.u8   q0, d0, d1                     \n"
  1.2819 +    "vld1.8     {d2}, [%0],%4                  \n"  // center * 2
  1.2820 +    "vld1.8     {d3}, [%1],%4                  \n"
  1.2821 +    "vsubl.u8   q1, d2, d3                     \n"
  1.2822 +    "vadd.s16   q0, q0, q1                     \n"
  1.2823 +    "vadd.s16   q0, q0, q1                     \n"
  1.2824 +    "vld1.8     {d2}, [%0],%5                  \n"  // right
  1.2825 +    "vld1.8     {d3}, [%1],%5                  \n"
  1.2826 +    "subs       %3, %3, #8                     \n"  // 8 pixels
  1.2827 +    "vsubl.u8   q1, d2, d3                     \n"
  1.2828 +    "vadd.s16   q0, q0, q1                     \n"
  1.2829 +    "vabs.s16   q0, q0                         \n"
  1.2830 +    "vqmovn.u16 d0, q0                         \n"
  1.2831 +    "vst1.8     {d0}, [%2]!                    \n"  // store 8 sobely
  1.2832 +    "bgt        1b                             \n"
  1.2833 +  : "+r"(src_y0),      // %0
  1.2834 +    "+r"(src_y1),      // %1
  1.2835 +    "+r"(dst_sobely),  // %2
  1.2836 +    "+r"(width)        // %3
  1.2837 +  : "r"(1),            // %4
  1.2838 +    "r"(6)             // %5
  1.2839 +  : "cc", "memory", "q0", "q1"  // Clobber List
  1.2840 +  );
  1.2841 +}
  1.2842 +#endif  // __ARM_NEON__
  1.2843 +
  1.2844 +#ifdef __cplusplus
  1.2845 +}  // extern "C"
  1.2846 +}  // namespace libyuv
  1.2847 +#endif

mercurial