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