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