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