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