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