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