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