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