media/libyuv/source/row_neon.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial