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