2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
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.
11 #include "libyuv/row.h"
18 // This module is for GCC Neon
19 #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)
21 // Read 8 Y, 4 U and 4 V from 422
24 "vld1.8 {d0}, [%0]! \n" \
26 "vld1.32 {d2[0]}, [%1]! \n" \
28 "vld1.32 {d2[1]}, [%2]! \n"
30 // Read 8 Y, 2 U and 2 V from 422
33 "vld1.8 {d0}, [%0]! \n" \
35 "vld1.16 {d2[0]}, [%1]! \n" \
37 "vld1.16 {d2[1]}, [%2]! \n" \
41 // Read 8 Y, 8 U and 8 V from 444
44 "vld1.8 {d0}, [%0]! \n" \
46 "vld1.8 {d2}, [%1]! \n" \
48 "vld1.8 {d3}, [%2]! \n" \
49 "vpaddl.u8 q1, q1 \n" \
50 "vrshrn.u16 d2, q1, #1 \n"
52 // Read 8 Y, and set 4 U and 4 V to 128
55 "vld1.8 {d0}, [%0]! \n" \
58 // Read 8 Y and 4 UV from NV12
61 "vld1.8 {d0}, [%0]! \n" \
63 "vld1.8 {d2}, [%1]! \n" \
64 "vmov.u8 d3, d2 \n"/* split odd/even uv apart */\
68 // Read 8 Y and 4 VU from NV21
71 "vld1.8 {d0}, [%0]! \n" \
73 "vld1.8 {d2}, [%1]! \n" \
74 "vmov.u8 d3, d2 \n"/* split odd/even uv apart */\
81 "vld2.8 {d0, d2}, [%0]! \n" \
89 "vld2.8 {d2, d3}, [%0]! \n" \
96 "veor.u8 d2, d26 \n"/*subtract 128 from u and v*/\
97 "vmull.s8 q8, d2, d24 \n"/* u/v B/R component */\
98 "vmull.s8 q9, d2, d25 \n"/* u/v G component */\
99 "vmov.u8 d1, #0 \n"/* split odd/even y apart */\
100 "vtrn.u8 d0, d1 \n" \
101 "vsub.s16 q0, q0, q15 \n"/* offset y */\
102 "vmul.s16 q0, q0, q14 \n" \
103 "vadd.s16 d18, d19 \n" \
104 "vqadd.s16 d20, d0, d16 \n" /* B */ \
105 "vqadd.s16 d21, d1, d16 \n" \
106 "vqadd.s16 d22, d0, d17 \n" /* R */ \
107 "vqadd.s16 d23, d1, d17 \n" \
108 "vqadd.s16 d16, d0, d18 \n" /* G */ \
109 "vqadd.s16 d17, d1, d18 \n" \
110 "vqshrun.s16 d0, q10, #6 \n" /* B */ \
111 "vqshrun.s16 d1, q11, #6 \n" /* G */ \
112 "vqshrun.s16 d2, q8, #6 \n" /* R */ \
113 "vmovl.u8 q10, d0 \n"/* set up for reinterleave*/\
114 "vmovl.u8 q11, d1 \n" \
115 "vmovl.u8 q8, d2 \n" \
116 "vtrn.u8 d20, d21 \n" \
117 "vtrn.u8 d22, d23 \n" \
118 "vtrn.u8 d16, d17 \n" \
119 "vmov.u8 d21, d16 \n"
121 static vec8 kUVToRB = { 127, 127, 127, 127, 102, 102, 102, 102,
122 0, 0, 0, 0, 0, 0, 0, 0 };
123 static vec8 kUVToG = { -25, -25, -25, -25, -52, -52, -52, -52,
124 0, 0, 0, 0, 0, 0, 0, 0 };
126 void I444ToARGBRow_NEON(const uint8* src_y,
133 "vld1.8 {d24}, [%5] \n"
135 "vld1.8 {d25}, [%6] \n"
136 "vmov.u8 d26, #128 \n"
137 "vmov.u16 q14, #74 \n"
138 "vmov.u16 q15, #16 \n"
144 "vmov.u8 d23, #255 \n"
146 "vst4.8 {d20, d21, d22, d23}, [%3]! \n"
151 "+r"(dst_argb), // %3
153 : "r"(&kUVToRB), // %5
155 : "cc", "memory", "q0", "q1", "q2", "q3",
156 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
160 void I422ToARGBRow_NEON(const uint8* src_y,
167 "vld1.8 {d24}, [%5] \n"
169 "vld1.8 {d25}, [%6] \n"
170 "vmov.u8 d26, #128 \n"
171 "vmov.u16 q14, #74 \n"
172 "vmov.u16 q15, #16 \n"
178 "vmov.u8 d23, #255 \n"
180 "vst4.8 {d20, d21, d22, d23}, [%3]! \n"
185 "+r"(dst_argb), // %3
187 : "r"(&kUVToRB), // %5
189 : "cc", "memory", "q0", "q1", "q2", "q3",
190 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
194 void I411ToARGBRow_NEON(const uint8* src_y,
201 "vld1.8 {d24}, [%5] \n"
203 "vld1.8 {d25}, [%6] \n"
204 "vmov.u8 d26, #128 \n"
205 "vmov.u16 q14, #74 \n"
206 "vmov.u16 q15, #16 \n"
212 "vmov.u8 d23, #255 \n"
214 "vst4.8 {d20, d21, d22, d23}, [%3]! \n"
219 "+r"(dst_argb), // %3
221 : "r"(&kUVToRB), // %5
223 : "cc", "memory", "q0", "q1", "q2", "q3",
224 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
228 void I422ToBGRARow_NEON(const uint8* src_y,
235 "vld1.8 {d24}, [%5] \n"
237 "vld1.8 {d25}, [%6] \n"
238 "vmov.u8 d26, #128 \n"
239 "vmov.u16 q14, #74 \n"
240 "vmov.u16 q15, #16 \n"
246 "vswp.u8 d20, d22 \n"
247 "vmov.u8 d19, #255 \n"
249 "vst4.8 {d19, d20, d21, d22}, [%3]! \n"
254 "+r"(dst_bgra), // %3
256 : "r"(&kUVToRB), // %5
258 : "cc", "memory", "q0", "q1", "q2", "q3",
259 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
263 void I422ToABGRRow_NEON(const uint8* src_y,
270 "vld1.8 {d24}, [%5] \n"
272 "vld1.8 {d25}, [%6] \n"
273 "vmov.u8 d26, #128 \n"
274 "vmov.u16 q14, #74 \n"
275 "vmov.u16 q15, #16 \n"
281 "vswp.u8 d20, d22 \n"
282 "vmov.u8 d23, #255 \n"
284 "vst4.8 {d20, d21, d22, d23}, [%3]! \n"
289 "+r"(dst_abgr), // %3
291 : "r"(&kUVToRB), // %5
293 : "cc", "memory", "q0", "q1", "q2", "q3",
294 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
298 void I422ToRGBARow_NEON(const uint8* src_y,
305 "vld1.8 {d24}, [%5] \n"
307 "vld1.8 {d25}, [%6] \n"
308 "vmov.u8 d26, #128 \n"
309 "vmov.u16 q14, #74 \n"
310 "vmov.u16 q15, #16 \n"
316 "vmov.u8 d19, #255 \n"
318 "vst4.8 {d19, d20, d21, d22}, [%3]! \n"
323 "+r"(dst_rgba), // %3
325 : "r"(&kUVToRB), // %5
327 : "cc", "memory", "q0", "q1", "q2", "q3",
328 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
332 void I422ToRGB24Row_NEON(const uint8* src_y,
339 "vld1.8 {d24}, [%5] \n"
341 "vld1.8 {d25}, [%6] \n"
342 "vmov.u8 d26, #128 \n"
343 "vmov.u16 q14, #74 \n"
344 "vmov.u16 q15, #16 \n"
351 "vst3.8 {d20, d21, d22}, [%3]! \n"
356 "+r"(dst_rgb24), // %3
358 : "r"(&kUVToRB), // %5
360 : "cc", "memory", "q0", "q1", "q2", "q3",
361 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
365 void I422ToRAWRow_NEON(const uint8* src_y,
372 "vld1.8 {d24}, [%5] \n"
374 "vld1.8 {d25}, [%6] \n"
375 "vmov.u8 d26, #128 \n"
376 "vmov.u16 q14, #74 \n"
377 "vmov.u16 q15, #16 \n"
383 "vswp.u8 d20, d22 \n"
385 "vst3.8 {d20, d21, d22}, [%3]! \n"
392 : "r"(&kUVToRB), // %5
394 : "cc", "memory", "q0", "q1", "q2", "q3",
395 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
399 #define ARGBTORGB565 \
400 "vshr.u8 d20, d20, #3 \n" /* B */ \
401 "vshr.u8 d21, d21, #2 \n" /* G */ \
402 "vshr.u8 d22, d22, #3 \n" /* R */ \
403 "vmovl.u8 q8, d20 \n" /* B */ \
404 "vmovl.u8 q9, d21 \n" /* G */ \
405 "vmovl.u8 q10, d22 \n" /* R */ \
406 "vshl.u16 q9, q9, #5 \n" /* G */ \
407 "vshl.u16 q10, q10, #11 \n" /* R */ \
408 "vorr q0, q8, q9 \n" /* BG */ \
409 "vorr q0, q0, q10 \n" /* BGR */
411 void I422ToRGB565Row_NEON(const uint8* src_y,
418 "vld1.8 {d24}, [%5] \n"
420 "vld1.8 {d25}, [%6] \n"
421 "vmov.u8 d26, #128 \n"
422 "vmov.u16 q14, #74 \n"
423 "vmov.u16 q15, #16 \n"
431 "vst1.8 {q0}, [%3]! \n" // store 8 pixels RGB565.
436 "+r"(dst_rgb565), // %3
438 : "r"(&kUVToRB), // %5
440 : "cc", "memory", "q0", "q1", "q2", "q3",
441 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
445 #define ARGBTOARGB1555 \
446 "vshr.u8 q10, q10, #3 \n" /* B */ \
447 "vshr.u8 d22, d22, #3 \n" /* R */ \
448 "vshr.u8 d23, d23, #7 \n" /* A */ \
449 "vmovl.u8 q8, d20 \n" /* B */ \
450 "vmovl.u8 q9, d21 \n" /* G */ \
451 "vmovl.u8 q10, d22 \n" /* R */ \
452 "vmovl.u8 q11, d23 \n" /* A */ \
453 "vshl.u16 q9, q9, #5 \n" /* G */ \
454 "vshl.u16 q10, q10, #10 \n" /* R */ \
455 "vshl.u16 q11, q11, #15 \n" /* A */ \
456 "vorr q0, q8, q9 \n" /* BG */ \
457 "vorr q1, q10, q11 \n" /* RA */ \
458 "vorr q0, q0, q1 \n" /* BGRA */
460 void I422ToARGB1555Row_NEON(const uint8* src_y,
467 "vld1.8 {d24}, [%5] \n"
469 "vld1.8 {d25}, [%6] \n"
470 "vmov.u8 d26, #128 \n"
471 "vmov.u16 q14, #74 \n"
472 "vmov.u16 q15, #16 \n"
478 "vmov.u8 d23, #255 \n"
481 "vst1.8 {q0}, [%3]! \n" // store 8 pixels ARGB1555.
486 "+r"(dst_argb1555), // %3
488 : "r"(&kUVToRB), // %5
490 : "cc", "memory", "q0", "q1", "q2", "q3",
491 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
495 #define ARGBTOARGB4444 \
496 "vshr.u8 d20, d20, #4 \n" /* B */ \
497 "vbic.32 d21, d21, d4 \n" /* G */ \
498 "vshr.u8 d22, d22, #4 \n" /* R */ \
499 "vbic.32 d23, d23, d4 \n" /* A */ \
500 "vorr d0, d20, d21 \n" /* BG */ \
501 "vorr d1, d22, d23 \n" /* RA */ \
502 "vzip.u8 d0, d1 \n" /* BGRA */
504 void I422ToARGB4444Row_NEON(const uint8* src_y,
511 "vld1.8 {d24}, [%5] \n"
513 "vld1.8 {d25}, [%6] \n"
514 "vmov.u8 d26, #128 \n"
515 "vmov.u16 q14, #74 \n"
516 "vmov.u16 q15, #16 \n"
517 "vmov.u8 d4, #0x0f \n" // bits to clear with vbic.
523 "vmov.u8 d23, #255 \n"
526 "vst1.8 {q0}, [%3]! \n" // store 8 pixels ARGB4444.
531 "+r"(dst_argb4444), // %3
533 : "r"(&kUVToRB), // %5
535 : "cc", "memory", "q0", "q1", "q2", "q3",
536 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
540 void YToARGBRow_NEON(const uint8* src_y,
545 "vld1.8 {d24}, [%3] \n"
547 "vld1.8 {d25}, [%4] \n"
548 "vmov.u8 d26, #128 \n"
549 "vmov.u16 q14, #74 \n"
550 "vmov.u16 q15, #16 \n"
556 "vmov.u8 d23, #255 \n"
558 "vst4.8 {d20, d21, d22, d23}, [%1]! \n"
561 "+r"(dst_argb), // %1
563 : "r"(&kUVToRB), // %3
565 : "cc", "memory", "q0", "q1", "q2", "q3",
566 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
570 void I400ToARGBRow_NEON(const uint8* src_y,
575 "vmov.u8 d23, #255 \n"
578 "vld1.8 {d20}, [%0]! \n"
583 "vst4.8 {d20, d21, d22, d23}, [%1]! \n"
586 "+r"(dst_argb), // %1
589 : "cc", "memory", "d20", "d21", "d22", "d23"
593 void NV12ToARGBRow_NEON(const uint8* src_y,
599 "vld1.8 {d24}, [%4] \n"
601 "vld1.8 {d25}, [%5] \n"
602 "vmov.u8 d26, #128 \n"
603 "vmov.u16 q14, #74 \n"
604 "vmov.u16 q15, #16 \n"
610 "vmov.u8 d23, #255 \n"
612 "vst4.8 {d20, d21, d22, d23}, [%2]! \n"
616 "+r"(dst_argb), // %2
618 : "r"(&kUVToRB), // %4
620 : "cc", "memory", "q0", "q1", "q2", "q3",
621 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
625 void NV21ToARGBRow_NEON(const uint8* src_y,
631 "vld1.8 {d24}, [%4] \n"
633 "vld1.8 {d25}, [%5] \n"
634 "vmov.u8 d26, #128 \n"
635 "vmov.u16 q14, #74 \n"
636 "vmov.u16 q15, #16 \n"
642 "vmov.u8 d23, #255 \n"
644 "vst4.8 {d20, d21, d22, d23}, [%2]! \n"
648 "+r"(dst_argb), // %2
650 : "r"(&kUVToRB), // %4
652 : "cc", "memory", "q0", "q1", "q2", "q3",
653 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
657 void NV12ToRGB565Row_NEON(const uint8* src_y,
663 "vld1.8 {d24}, [%4] \n"
665 "vld1.8 {d25}, [%5] \n"
666 "vmov.u8 d26, #128 \n"
667 "vmov.u16 q14, #74 \n"
668 "vmov.u16 q15, #16 \n"
676 "vst1.8 {q0}, [%2]! \n" // store 8 pixels RGB565.
680 "+r"(dst_rgb565), // %2
682 : "r"(&kUVToRB), // %4
684 : "cc", "memory", "q0", "q1", "q2", "q3",
685 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
689 void NV21ToRGB565Row_NEON(const uint8* src_y,
695 "vld1.8 {d24}, [%4] \n"
697 "vld1.8 {d25}, [%5] \n"
698 "vmov.u8 d26, #128 \n"
699 "vmov.u16 q14, #74 \n"
700 "vmov.u16 q15, #16 \n"
708 "vst1.8 {q0}, [%2]! \n" // store 8 pixels RGB565.
712 "+r"(dst_rgb565), // %2
714 : "r"(&kUVToRB), // %4
716 : "cc", "memory", "q0", "q1", "q2", "q3",
717 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
721 void YUY2ToARGBRow_NEON(const uint8* src_yuy2,
726 "vld1.8 {d24}, [%3] \n"
728 "vld1.8 {d25}, [%4] \n"
729 "vmov.u8 d26, #128 \n"
730 "vmov.u16 q14, #74 \n"
731 "vmov.u16 q15, #16 \n"
737 "vmov.u8 d23, #255 \n"
739 "vst4.8 {d20, d21, d22, d23}, [%1]! \n"
741 : "+r"(src_yuy2), // %0
742 "+r"(dst_argb), // %1
744 : "r"(&kUVToRB), // %3
746 : "cc", "memory", "q0", "q1", "q2", "q3",
747 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
751 void UYVYToARGBRow_NEON(const uint8* src_uyvy,
756 "vld1.8 {d24}, [%3] \n"
758 "vld1.8 {d25}, [%4] \n"
759 "vmov.u8 d26, #128 \n"
760 "vmov.u16 q14, #74 \n"
761 "vmov.u16 q15, #16 \n"
767 "vmov.u8 d23, #255 \n"
769 "vst4.8 {d20, d21, d22, d23}, [%1]! \n"
771 : "+r"(src_uyvy), // %0
772 "+r"(dst_argb), // %1
774 : "r"(&kUVToRB), // %3
776 : "cc", "memory", "q0", "q1", "q2", "q3",
777 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
781 // Reads 16 pairs of UV and write even values to dst_u and odd to dst_v.
782 void SplitUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
788 "vld2.8 {q0, q1}, [%0]! \n" // load 16 pairs of UV
789 "subs %3, %3, #16 \n" // 16 processed per loop
791 "vst1.8 {q0}, [%1]! \n" // store U
793 "vst1.8 {q1}, [%2]! \n" // store V
795 : "+r"(src_uv), // %0
798 "+r"(width) // %3 // Output registers
800 : "cc", "memory", "q0", "q1" // Clobber List
804 // Reads 16 U's and V's and writes out 16 pairs of UV.
805 void MergeUVRow_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
811 "vld1.8 {q0}, [%0]! \n" // load U
813 "vld1.8 {q1}, [%1]! \n" // load V
814 "subs %3, %3, #16 \n" // 16 processed per loop
816 "vst2.u8 {q0, q1}, [%2]! \n" // store 16 pairs of UV
822 "+r"(width) // %3 // Output registers
824 : "cc", "memory", "q0", "q1" // Clobber List
828 // Copy multiple of 32. vld4.8 allow unaligned and is fastest on a15.
829 void CopyRow_NEON(const uint8* src, uint8* dst, int count) {
834 "vld1.8 {d0, d1, d2, d3}, [%0]! \n" // load 32
835 "subs %2, %2, #32 \n" // 32 processed per loop
837 "vst1.8 {d0, d1, d2, d3}, [%1]! \n" // store 32
841 "+r"(count) // %2 // Output registers
843 : "cc", "memory", "q0", "q1" // Clobber List
847 // SetRow8 writes 'count' bytes using a 32 bit value repeated.
848 void SetRow_NEON(uint8* dst, uint32 v32, int count) {
850 "vdup.u32 q0, %2 \n" // duplicate 4 ints
852 "subs %1, %1, #16 \n" // 16 bytes per loop
854 "vst1.8 {q0}, [%0]! \n" // store
859 : "cc", "memory", "q0"
863 // TODO(fbarchard): Make fully assembler
864 // SetRow32 writes 'count' words using a 32 bit value repeated.
865 void ARGBSetRows_NEON(uint8* dst, uint32 v32, int width,
866 int dst_stride, int height) {
867 for (int y = 0; y < height; ++y) {
868 SetRow_NEON(dst, v32, width << 2);
873 void MirrorRow_NEON(const uint8* src, uint8* dst, int width) {
875 // Start at end of source row.
883 "vld1.8 {q0}, [%0], r3 \n" // src -= 16
884 "subs %2, #16 \n" // 16 pixels per loop.
887 "vst1.8 {d1}, [%1]! \n" // dst += 16
889 "vst1.8 {d0}, [%1]! \n"
895 : "cc", "memory", "r3", "q0"
899 void MirrorUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
902 // Start at end of source row.
904 "add %0, %0, %3, lsl #1 \n"
910 "vld2.8 {d0, d1}, [%0], r12 \n" // src -= 16
911 "subs %3, #8 \n" // 8 pixels per loop.
914 "vst1.8 {d0}, [%1]! \n" // dst += 8
916 "vst1.8 {d1}, [%2]! \n"
918 : "+r"(src_uv), // %0
923 : "cc", "memory", "r12", "q0"
927 void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) {
929 // Start at end of source row.
931 "add %0, %0, %2, lsl #2 \n"
937 "vld1.8 {q0}, [%0], r3 \n" // src -= 16
938 "subs %2, #4 \n" // 4 pixels per loop.
939 "vrev64.32 q0, q0 \n"
941 "vst1.8 {d1}, [%1]! \n" // dst += 16
943 "vst1.8 {d0}, [%1]! \n"
949 : "cc", "memory", "r3", "q0"
953 void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix) {
955 "vmov.u8 d4, #255 \n" // Alpha
959 "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RGB24.
960 "subs %2, %2, #8 \n" // 8 processed per loop.
962 "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB.
964 : "+r"(src_rgb24), // %0
965 "+r"(dst_argb), // %1
968 : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List
972 void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int pix) {
974 "vmov.u8 d4, #255 \n" // Alpha
978 "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RAW.
979 "subs %2, %2, #8 \n" // 8 processed per loop.
980 "vswp.u8 d1, d3 \n" // swap R, B
982 "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB.
984 : "+r"(src_raw), // %0
985 "+r"(dst_argb), // %1
988 : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List
992 #define RGB565TOARGB \
993 "vshrn.u16 d6, q0, #5 \n" /* G xxGGGGGG */ \
994 "vuzp.u8 d0, d1 \n" /* d0 xxxBBBBB RRRRRxxx */ \
995 "vshl.u8 d6, d6, #2 \n" /* G GGGGGG00 upper 6 */ \
996 "vshr.u8 d1, d1, #3 \n" /* R 000RRRRR lower 5 */ \
997 "vshl.u8 q0, q0, #3 \n" /* B,R BBBBB000 upper 5 */ \
998 "vshr.u8 q2, q0, #5 \n" /* B,R 00000BBB lower 3 */ \
999 "vorr.u8 d0, d0, d4 \n" /* B */ \
1000 "vshr.u8 d4, d6, #6 \n" /* G 000000GG lower 2 */ \
1001 "vorr.u8 d2, d1, d5 \n" /* R */ \
1002 "vorr.u8 d1, d4, d6 \n" /* G */
1004 void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int pix) {
1006 "vmov.u8 d3, #255 \n" // Alpha
1010 "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels.
1011 "subs %2, %2, #8 \n" // 8 processed per loop.
1014 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB.
1016 : "+r"(src_rgb565), // %0
1017 "+r"(dst_argb), // %1
1020 : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List
1024 #define ARGB1555TOARGB \
1025 "vshrn.u16 d7, q0, #8 \n" /* A Arrrrrxx */ \
1026 "vshr.u8 d6, d7, #2 \n" /* R xxxRRRRR */ \
1027 "vshrn.u16 d5, q0, #5 \n" /* G xxxGGGGG */ \
1028 "vmovn.u16 d4, q0 \n" /* B xxxBBBBB */ \
1029 "vshr.u8 d7, d7, #7 \n" /* A 0000000A */ \
1030 "vneg.s8 d7, d7 \n" /* A AAAAAAAA upper 8 */ \
1031 "vshl.u8 d6, d6, #3 \n" /* R RRRRR000 upper 5 */ \
1032 "vshr.u8 q1, q3, #5 \n" /* R,A 00000RRR lower 3 */ \
1033 "vshl.u8 q0, q2, #3 \n" /* B,G BBBBB000 upper 5 */ \
1034 "vshr.u8 q2, q0, #5 \n" /* B,G 00000BBB lower 3 */ \
1035 "vorr.u8 q1, q1, q3 \n" /* R,A */ \
1036 "vorr.u8 q0, q0, q2 \n" /* B,G */ \
1038 // RGB555TOARGB is same as ARGB1555TOARGB but ignores alpha.
1039 #define RGB555TOARGB \
1040 "vshrn.u16 d6, q0, #5 \n" /* G xxxGGGGG */ \
1041 "vuzp.u8 d0, d1 \n" /* d0 xxxBBBBB xRRRRRxx */ \
1042 "vshl.u8 d6, d6, #3 \n" /* G GGGGG000 upper 5 */ \
1043 "vshr.u8 d1, d1, #2 \n" /* R 00xRRRRR lower 5 */ \
1044 "vshl.u8 q0, q0, #3 \n" /* B,R BBBBB000 upper 5 */ \
1045 "vshr.u8 q2, q0, #5 \n" /* B,R 00000BBB lower 3 */ \
1046 "vorr.u8 d0, d0, d4 \n" /* B */ \
1047 "vshr.u8 d4, d6, #5 \n" /* G 00000GGG lower 3 */ \
1048 "vorr.u8 d2, d1, d5 \n" /* R */ \
1049 "vorr.u8 d1, d4, d6 \n" /* G */
1051 void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, uint8* dst_argb,
1054 "vmov.u8 d3, #255 \n" // Alpha
1058 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels.
1059 "subs %2, %2, #8 \n" // 8 processed per loop.
1062 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB.
1064 : "+r"(src_argb1555), // %0
1065 "+r"(dst_argb), // %1
1068 : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List
1072 #define ARGB4444TOARGB \
1073 "vuzp.u8 d0, d1 \n" /* d0 BG, d1 RA */ \
1074 "vshl.u8 q2, q0, #4 \n" /* B,R BBBB0000 */ \
1075 "vshr.u8 q1, q0, #4 \n" /* G,A 0000GGGG */ \
1076 "vshr.u8 q0, q2, #4 \n" /* B,R 0000BBBB */ \
1077 "vorr.u8 q0, q0, q2 \n" /* B,R BBBBBBBB */ \
1078 "vshl.u8 q2, q1, #4 \n" /* G,A GGGG0000 */ \
1079 "vorr.u8 q1, q1, q2 \n" /* G,A GGGGGGGG */ \
1080 "vswp.u8 d1, d2 \n" /* B,R,G,A -> B,G,R,A */
1082 void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, uint8* dst_argb,
1085 "vmov.u8 d3, #255 \n" // Alpha
1089 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels.
1090 "subs %2, %2, #8 \n" // 8 processed per loop.
1093 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB.
1095 : "+r"(src_argb4444), // %0
1096 "+r"(dst_argb), // %1
1099 : "cc", "memory", "q0", "q1", "q2" // Clobber List
1103 void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int pix) {
1108 "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB.
1109 "subs %2, %2, #8 \n" // 8 processed per loop.
1111 "vst3.8 {d1, d2, d3}, [%1]! \n" // store 8 pixels of RGB24.
1113 : "+r"(src_argb), // %0
1114 "+r"(dst_rgb24), // %1
1117 : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List
1121 void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int pix) {
1126 "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB.
1127 "subs %2, %2, #8 \n" // 8 processed per loop.
1128 "vswp.u8 d1, d3 \n" // swap R, B
1130 "vst3.8 {d1, d2, d3}, [%1]! \n" // store 8 pixels of RAW.
1132 : "+r"(src_argb), // %0
1133 "+r"(dst_raw), // %1
1136 : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List
1140 void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int pix) {
1145 "vld2.8 {q0, q1}, [%0]! \n" // load 16 pixels of YUY2.
1146 "subs %2, %2, #16 \n" // 16 processed per loop.
1148 "vst1.8 {q0}, [%1]! \n" // store 16 pixels of Y.
1150 : "+r"(src_yuy2), // %0
1154 : "cc", "memory", "q0", "q1" // Clobber List
1158 void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int pix) {
1163 "vld2.8 {q0, q1}, [%0]! \n" // load 16 pixels of UYVY.
1164 "subs %2, %2, #16 \n" // 16 processed per loop.
1166 "vst1.8 {q1}, [%1]! \n" // store 16 pixels of Y.
1168 : "+r"(src_uyvy), // %0
1172 : "cc", "memory", "q0", "q1" // Clobber List
1176 void YUY2ToUV422Row_NEON(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
1182 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of YUY2.
1183 "subs %3, %3, #16 \n" // 16 pixels = 8 UVs.
1185 "vst1.8 {d1}, [%1]! \n" // store 8 U.
1187 "vst1.8 {d3}, [%2]! \n" // store 8 V.
1189 : "+r"(src_yuy2), // %0
1194 : "cc", "memory", "d0", "d1", "d2", "d3" // Clobber List
1198 void UYVYToUV422Row_NEON(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v,
1204 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of UYVY.
1205 "subs %3, %3, #16 \n" // 16 pixels = 8 UVs.
1207 "vst1.8 {d0}, [%1]! \n" // store 8 U.
1209 "vst1.8 {d2}, [%2]! \n" // store 8 V.
1211 : "+r"(src_uyvy), // %0
1216 : "cc", "memory", "d0", "d1", "d2", "d3" // Clobber List
1220 void YUY2ToUVRow_NEON(const uint8* src_yuy2, int stride_yuy2,
1221 uint8* dst_u, uint8* dst_v, int pix) {
1223 "add %1, %0, %1 \n" // stride + src_yuy2
1227 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of YUY2.
1228 "subs %4, %4, #16 \n" // 16 pixels = 8 UVs.
1230 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load next row YUY2.
1231 "vrhadd.u8 d1, d1, d5 \n" // average rows of U
1232 "vrhadd.u8 d3, d3, d7 \n" // average rows of V
1234 "vst1.8 {d1}, [%2]! \n" // store 8 U.
1236 "vst1.8 {d3}, [%3]! \n" // store 8 V.
1238 : "+r"(src_yuy2), // %0
1239 "+r"(stride_yuy2), // %1
1244 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7" // Clobber List
1248 void UYVYToUVRow_NEON(const uint8* src_uyvy, int stride_uyvy,
1249 uint8* dst_u, uint8* dst_v, int pix) {
1251 "add %1, %0, %1 \n" // stride + src_uyvy
1255 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of UYVY.
1256 "subs %4, %4, #16 \n" // 16 pixels = 8 UVs.
1258 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load next row UYVY.
1259 "vrhadd.u8 d0, d0, d4 \n" // average rows of U
1260 "vrhadd.u8 d2, d2, d6 \n" // average rows of V
1262 "vst1.8 {d0}, [%2]! \n" // store 8 U.
1264 "vst1.8 {d2}, [%3]! \n" // store 8 V.
1266 : "+r"(src_uyvy), // %0
1267 "+r"(stride_uyvy), // %1
1272 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7" // Clobber List
1276 void HalfRow_NEON(const uint8* src_uv, int src_uv_stride,
1277 uint8* dst_uv, int pix) {
1279 // change the stride to row 2 pointer
1283 "vld1.8 {q0}, [%0]! \n" // load row 1 16 pixels.
1284 "subs %3, %3, #16 \n" // 16 processed per loop
1286 "vld1.8 {q1}, [%1]! \n" // load row 2 16 pixels.
1287 "vrhadd.u8 q0, q1 \n" // average row 1 and 2
1289 "vst1.8 {q0}, [%2]! \n"
1291 : "+r"(src_uv), // %0
1292 "+r"(src_uv_stride), // %1
1296 : "cc", "memory", "q0", "q1" // Clobber List
1300 // Select 2 channels from ARGB on alternating pixels. e.g. BGBGBGBG
1301 void ARGBToBayerRow_NEON(const uint8* src_argb, uint8* dst_bayer,
1302 uint32 selector, int pix) {
1304 "vmov.u32 d6[0], %3 \n" // selector
1307 "vld1.8 {q0, q1}, [%0]! \n" // load row 8 pixels.
1308 "subs %2, %2, #8 \n" // 8 processed per loop
1309 "vtbl.8 d4, {d0, d1}, d6 \n" // look up 4 pixels
1310 "vtbl.8 d5, {d2, d3}, d6 \n" // look up 4 pixels
1311 "vtrn.u32 d4, d5 \n" // combine 8 pixels
1313 "vst1.8 {d4}, [%1]! \n" // store 8.
1315 : "+r"(src_argb), // %0
1316 "+r"(dst_bayer), // %1
1318 : "r"(selector) // %3
1319 : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List
1323 // Select G channels from ARGB. e.g. GGGGGGGG
1324 void ARGBToBayerGGRow_NEON(const uint8* src_argb, uint8* dst_bayer,
1325 uint32 /*selector*/, int pix) {
1329 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load row 8 pixels.
1330 "subs %2, %2, #8 \n" // 8 processed per loop
1332 "vst1.8 {d1}, [%1]! \n" // store 8 G's.
1334 : "+r"(src_argb), // %0
1335 "+r"(dst_bayer), // %1
1338 : "cc", "memory", "q0", "q1" // Clobber List
1342 // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA.
1343 void ARGBShuffleRow_NEON(const uint8* src_argb, uint8* dst_argb,
1344 const uint8* shuffler, int pix) {
1347 "vld1.8 {q2}, [%3] \n" // shuffler
1350 "vld1.8 {q0}, [%0]! \n" // load 4 pixels.
1351 "subs %2, %2, #4 \n" // 4 processed per loop
1352 "vtbl.8 d2, {d0, d1}, d4 \n" // look up 2 first pixels
1353 "vtbl.8 d3, {d0, d1}, d5 \n" // look up 2 next pixels
1355 "vst1.8 {q1}, [%1]! \n" // store 4.
1357 : "+r"(src_argb), // %0
1358 "+r"(dst_argb), // %1
1360 : "r"(shuffler) // %3
1361 : "cc", "memory", "q0", "q1", "q2" // Clobber List
1365 void I422ToYUY2Row_NEON(const uint8* src_y,
1368 uint8* dst_yuy2, int width) {
1373 "vld2.8 {d0, d2}, [%0]! \n" // load 16 Ys
1375 "vld1.8 {d1}, [%1]! \n" // load 8 Us
1377 "vld1.8 {d3}, [%2]! \n" // load 8 Vs
1378 "subs %4, %4, #16 \n" // 16 pixels
1380 "vst4.8 {d0, d1, d2, d3}, [%3]! \n" // Store 8 YUY2/16 pixels.
1382 : "+r"(src_y), // %0
1385 "+r"(dst_yuy2), // %3
1388 : "cc", "memory", "d0", "d1", "d2", "d3"
1392 void I422ToUYVYRow_NEON(const uint8* src_y,
1395 uint8* dst_uyvy, int width) {
1400 "vld2.8 {d1, d3}, [%0]! \n" // load 16 Ys
1402 "vld1.8 {d0}, [%1]! \n" // load 8 Us
1404 "vld1.8 {d2}, [%2]! \n" // load 8 Vs
1405 "subs %4, %4, #16 \n" // 16 pixels
1407 "vst4.8 {d0, d1, d2, d3}, [%3]! \n" // Store 8 UYVY/16 pixels.
1409 : "+r"(src_y), // %0
1412 "+r"(dst_uyvy), // %3
1415 : "cc", "memory", "d0", "d1", "d2", "d3"
1419 void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int pix) {
1424 "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB.
1425 "subs %2, %2, #8 \n" // 8 processed per loop.
1428 "vst1.8 {q0}, [%1]! \n" // store 8 pixels RGB565.
1430 : "+r"(src_argb), // %0
1431 "+r"(dst_rgb565), // %1
1434 : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
1438 void ARGBToARGB1555Row_NEON(const uint8* src_argb, uint8* dst_argb1555,
1444 "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB.
1445 "subs %2, %2, #8 \n" // 8 processed per loop.
1448 "vst1.8 {q0}, [%1]! \n" // store 8 pixels ARGB1555.
1450 : "+r"(src_argb), // %0
1451 "+r"(dst_argb1555), // %1
1454 : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
1458 void ARGBToARGB4444Row_NEON(const uint8* src_argb, uint8* dst_argb4444,
1461 "vmov.u8 d4, #0x0f \n" // bits to clear with vbic.
1465 "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB.
1466 "subs %2, %2, #8 \n" // 8 processed per loop.
1469 "vst1.8 {q0}, [%1]! \n" // store 8 pixels ARGB4444.
1471 : "+r"(src_argb), // %0
1472 "+r"(dst_argb4444), // %1
1475 : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
1479 void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) {
1481 "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient
1482 "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient
1483 "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient
1484 "vmov.u8 d27, #16 \n" // Add 16 constant
1488 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
1489 "subs %2, %2, #8 \n" // 8 processed per loop.
1490 "vmull.u8 q2, d0, d24 \n" // B
1491 "vmlal.u8 q2, d1, d25 \n" // G
1492 "vmlal.u8 q2, d2, d26 \n" // R
1493 "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y
1494 "vqadd.u8 d0, d27 \n"
1496 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
1498 : "+r"(src_argb), // %0
1502 : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
1506 void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) {
1508 "vmov.u8 d24, #15 \n" // B * 0.11400 coefficient
1509 "vmov.u8 d25, #75 \n" // G * 0.58700 coefficient
1510 "vmov.u8 d26, #38 \n" // R * 0.29900 coefficient
1514 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
1515 "subs %2, %2, #8 \n" // 8 processed per loop.
1516 "vmull.u8 q2, d0, d24 \n" // B
1517 "vmlal.u8 q2, d1, d25 \n" // G
1518 "vmlal.u8 q2, d2, d26 \n" // R
1519 "vqrshrun.s16 d0, q2, #7 \n" // 15 bit to 8 bit Y
1521 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
1523 : "+r"(src_argb), // %0
1527 : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
1532 void ARGBToUV444Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
1535 "vmov.u8 d24, #112 \n" // UB / VR 0.875 coefficient
1536 "vmov.u8 d25, #74 \n" // UG -0.5781 coefficient
1537 "vmov.u8 d26, #38 \n" // UR -0.2969 coefficient
1538 "vmov.u8 d27, #18 \n" // VB -0.1406 coefficient
1539 "vmov.u8 d28, #94 \n" // VG -0.7344 coefficient
1540 "vmov.u16 q15, #0x8080 \n" // 128.5
1544 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
1545 "subs %3, %3, #8 \n" // 8 processed per loop.
1546 "vmull.u8 q2, d0, d24 \n" // B
1547 "vmlsl.u8 q2, d1, d25 \n" // G
1548 "vmlsl.u8 q2, d2, d26 \n" // R
1549 "vadd.u16 q2, q2, q15 \n" // +128 -> unsigned
1551 "vmull.u8 q3, d2, d24 \n" // R
1552 "vmlsl.u8 q3, d1, d28 \n" // G
1553 "vmlsl.u8 q3, d0, d27 \n" // B
1554 "vadd.u16 q3, q3, q15 \n" // +128 -> unsigned
1556 "vqshrn.u16 d0, q2, #8 \n" // 16 bit to 8 bit U
1557 "vqshrn.u16 d1, q3, #8 \n" // 16 bit to 8 bit V
1560 "vst1.8 {d0}, [%1]! \n" // store 8 pixels U.
1562 "vst1.8 {d1}, [%2]! \n" // store 8 pixels V.
1564 : "+r"(src_argb), // %0
1569 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q12", "q13", "q14", "q15"
1573 // 16x1 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
1574 void ARGBToUV422Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
1577 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
1578 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
1579 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
1580 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
1581 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
1582 "vmov.u16 q15, #0x8080 \n" // 128.5
1586 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
1588 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
1590 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
1591 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
1592 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
1594 "subs %3, %3, #16 \n" // 16 processed per loop.
1595 "vmul.s16 q8, q0, q10 \n" // B
1596 "vmls.s16 q8, q1, q11 \n" // G
1597 "vmls.s16 q8, q2, q12 \n" // R
1598 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
1600 "vmul.s16 q9, q2, q10 \n" // R
1601 "vmls.s16 q9, q1, q14 \n" // G
1602 "vmls.s16 q9, q0, q13 \n" // B
1603 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
1605 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
1606 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
1609 "vst1.8 {d0}, [%1]! \n" // store 8 pixels U.
1611 "vst1.8 {d1}, [%2]! \n" // store 8 pixels V.
1613 : "+r"(src_argb), // %0
1618 : "cc", "memory", "q0", "q1", "q2", "q3",
1619 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1623 // 32x1 pixels -> 8x1. pix is number of argb pixels. e.g. 32.
1624 void ARGBToUV411Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
1627 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
1628 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
1629 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
1630 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
1631 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
1632 "vmov.u16 q15, #0x8080 \n" // 128.5
1636 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
1638 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
1639 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
1640 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
1641 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
1643 "vld4.8 {d8, d10, d12, d14}, [%0]! \n" // load 8 more ARGB pixels.
1645 "vld4.8 {d9, d11, d13, d15}, [%0]! \n" // load last 8 ARGB pixels.
1646 "vpaddl.u8 q4, q4 \n" // B 16 bytes -> 8 shorts.
1647 "vpaddl.u8 q5, q5 \n" // G 16 bytes -> 8 shorts.
1648 "vpaddl.u8 q6, q6 \n" // R 16 bytes -> 8 shorts.
1650 "vpadd.u16 d0, d0, d1 \n" // B 16 shorts -> 8 shorts.
1651 "vpadd.u16 d1, d8, d9 \n" // B
1652 "vpadd.u16 d2, d2, d3 \n" // G 16 shorts -> 8 shorts.
1653 "vpadd.u16 d3, d10, d11 \n" // G
1654 "vpadd.u16 d4, d4, d5 \n" // R 16 shorts -> 8 shorts.
1655 "vpadd.u16 d5, d12, d13 \n" // R
1657 "vrshr.u16 q0, q0, #1 \n" // 2x average
1658 "vrshr.u16 q1, q1, #1 \n"
1659 "vrshr.u16 q2, q2, #1 \n"
1661 "subs %3, %3, #32 \n" // 32 processed per loop.
1662 "vmul.s16 q8, q0, q10 \n" // B
1663 "vmls.s16 q8, q1, q11 \n" // G
1664 "vmls.s16 q8, q2, q12 \n" // R
1665 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
1666 "vmul.s16 q9, q2, q10 \n" // R
1667 "vmls.s16 q9, q1, q14 \n" // G
1668 "vmls.s16 q9, q0, q13 \n" // B
1669 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
1670 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
1671 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
1673 "vst1.8 {d0}, [%1]! \n" // store 8 pixels U.
1675 "vst1.8 {d1}, [%2]! \n" // store 8 pixels V.
1677 : "+r"(src_argb), // %0
1682 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1683 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1687 // 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
1688 #define RGBTOUV(QB, QG, QR) \
1689 "vmul.s16 q8, " #QB ", q10 \n" /* B */ \
1690 "vmls.s16 q8, " #QG ", q11 \n" /* G */ \
1691 "vmls.s16 q8, " #QR ", q12 \n" /* R */ \
1692 "vadd.u16 q8, q8, q15 \n" /* +128 -> unsigned */ \
1693 "vmul.s16 q9, " #QR ", q10 \n" /* R */ \
1694 "vmls.s16 q9, " #QG ", q14 \n" /* G */ \
1695 "vmls.s16 q9, " #QB ", q13 \n" /* B */ \
1696 "vadd.u16 q9, q9, q15 \n" /* +128 -> unsigned */ \
1697 "vqshrn.u16 d0, q8, #8 \n" /* 16 bit to 8 bit U */ \
1698 "vqshrn.u16 d1, q9, #8 \n" /* 16 bit to 8 bit V */
1700 // TODO(fbarchard): Consider vhadd vertical, then vpaddl horizontal, avoid shr.
1701 void ARGBToUVRow_NEON(const uint8* src_argb, int src_stride_argb,
1702 uint8* dst_u, uint8* dst_v, int pix) {
1704 "add %1, %0, %1 \n" // src_stride + src_argb
1705 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
1706 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
1707 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
1708 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
1709 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
1710 "vmov.u16 q15, #0x8080 \n" // 128.5
1714 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
1716 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB 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.
1721 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ARGB pixels.
1723 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ARGB 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.
1728 "vrshr.u16 q0, q0, #1 \n" // 2x average
1729 "vrshr.u16 q1, q1, #1 \n"
1730 "vrshr.u16 q2, q2, #1 \n"
1732 "subs %4, %4, #16 \n" // 32 processed per loop.
1735 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
1737 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
1739 : "+r"(src_argb), // %0
1740 "+r"(src_stride_argb), // %1
1745 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1746 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1750 // TODO(fbarchard): Subsample match C code.
1751 void ARGBToUVJRow_NEON(const uint8* src_argb, int src_stride_argb,
1752 uint8* dst_u, uint8* dst_v, int pix) {
1754 "add %1, %0, %1 \n" // src_stride + src_argb
1755 "vmov.s16 q10, #127 / 2 \n" // UB / VR 0.500 coefficient
1756 "vmov.s16 q11, #84 / 2 \n" // UG -0.33126 coefficient
1757 "vmov.s16 q12, #43 / 2 \n" // UR -0.16874 coefficient
1758 "vmov.s16 q13, #20 / 2 \n" // VB -0.08131 coefficient
1759 "vmov.s16 q14, #107 / 2 \n" // VG -0.41869 coefficient
1760 "vmov.u16 q15, #0x8080 \n" // 128.5
1764 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
1766 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
1767 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
1768 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
1769 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
1771 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ARGB pixels.
1773 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ARGB pixels.
1774 "vpadal.u8 q0, q4 \n" // B 16 bytes -> 8 shorts.
1775 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
1776 "vpadal.u8 q2, q6 \n" // R 16 bytes -> 8 shorts.
1778 "vrshr.u16 q0, q0, #1 \n" // 2x average
1779 "vrshr.u16 q1, q1, #1 \n"
1780 "vrshr.u16 q2, q2, #1 \n"
1782 "subs %4, %4, #16 \n" // 32 processed per loop.
1785 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
1787 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
1789 : "+r"(src_argb), // %0
1790 "+r"(src_stride_argb), // %1
1795 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1796 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1800 void BGRAToUVRow_NEON(const uint8* src_bgra, int src_stride_bgra,
1801 uint8* dst_u, uint8* dst_v, int pix) {
1803 "add %1, %0, %1 \n" // src_stride + src_bgra
1804 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
1805 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
1806 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
1807 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
1808 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
1809 "vmov.u16 q15, #0x8080 \n" // 128.5
1813 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 BGRA pixels.
1815 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 BGRA pixels.
1816 "vpaddl.u8 q3, q3 \n" // B 16 bytes -> 8 shorts.
1817 "vpaddl.u8 q2, q2 \n" // G 16 bytes -> 8 shorts.
1818 "vpaddl.u8 q1, q1 \n" // R 16 bytes -> 8 shorts.
1820 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more BGRA pixels.
1822 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 BGRA pixels.
1823 "vpadal.u8 q3, q7 \n" // B 16 bytes -> 8 shorts.
1824 "vpadal.u8 q2, q6 \n" // G 16 bytes -> 8 shorts.
1825 "vpadal.u8 q1, q5 \n" // R 16 bytes -> 8 shorts.
1827 "vrshr.u16 q1, q1, #1 \n" // 2x average
1828 "vrshr.u16 q2, q2, #1 \n"
1829 "vrshr.u16 q3, q3, #1 \n"
1831 "subs %4, %4, #16 \n" // 32 processed per loop.
1834 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
1836 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
1838 : "+r"(src_bgra), // %0
1839 "+r"(src_stride_bgra), // %1
1844 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1845 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1849 void ABGRToUVRow_NEON(const uint8* src_abgr, int src_stride_abgr,
1850 uint8* dst_u, uint8* dst_v, int pix) {
1852 "add %1, %0, %1 \n" // src_stride + src_abgr
1853 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
1854 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
1855 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
1856 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
1857 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
1858 "vmov.u16 q15, #0x8080 \n" // 128.5
1862 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ABGR pixels.
1864 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ABGR pixels.
1865 "vpaddl.u8 q2, q2 \n" // B 16 bytes -> 8 shorts.
1866 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
1867 "vpaddl.u8 q0, q0 \n" // R 16 bytes -> 8 shorts.
1869 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ABGR pixels.
1871 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ABGR pixels.
1872 "vpadal.u8 q2, q6 \n" // B 16 bytes -> 8 shorts.
1873 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
1874 "vpadal.u8 q0, q4 \n" // R 16 bytes -> 8 shorts.
1876 "vrshr.u16 q0, q0, #1 \n" // 2x average
1877 "vrshr.u16 q1, q1, #1 \n"
1878 "vrshr.u16 q2, q2, #1 \n"
1880 "subs %4, %4, #16 \n" // 32 processed per loop.
1883 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
1885 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
1887 : "+r"(src_abgr), // %0
1888 "+r"(src_stride_abgr), // %1
1893 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1894 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1898 void RGBAToUVRow_NEON(const uint8* src_rgba, int src_stride_rgba,
1899 uint8* dst_u, uint8* dst_v, int pix) {
1901 "add %1, %0, %1 \n" // src_stride + src_rgba
1902 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
1903 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
1904 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
1905 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
1906 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
1907 "vmov.u16 q15, #0x8080 \n" // 128.5
1911 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 RGBA pixels.
1913 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 RGBA pixels.
1914 "vpaddl.u8 q0, q1 \n" // B 16 bytes -> 8 shorts.
1915 "vpaddl.u8 q1, q2 \n" // G 16 bytes -> 8 shorts.
1916 "vpaddl.u8 q2, q3 \n" // R 16 bytes -> 8 shorts.
1918 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more RGBA pixels.
1920 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 RGBA pixels.
1921 "vpadal.u8 q0, q5 \n" // B 16 bytes -> 8 shorts.
1922 "vpadal.u8 q1, q6 \n" // G 16 bytes -> 8 shorts.
1923 "vpadal.u8 q2, q7 \n" // R 16 bytes -> 8 shorts.
1925 "vrshr.u16 q0, q0, #1 \n" // 2x average
1926 "vrshr.u16 q1, q1, #1 \n"
1927 "vrshr.u16 q2, q2, #1 \n"
1929 "subs %4, %4, #16 \n" // 32 processed per loop.
1932 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
1934 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
1936 : "+r"(src_rgba), // %0
1937 "+r"(src_stride_rgba), // %1
1942 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1943 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1947 void RGB24ToUVRow_NEON(const uint8* src_rgb24, int src_stride_rgb24,
1948 uint8* dst_u, uint8* dst_v, int pix) {
1950 "add %1, %0, %1 \n" // src_stride + src_rgb24
1951 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
1952 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
1953 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
1954 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
1955 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
1956 "vmov.u16 q15, #0x8080 \n" // 128.5
1960 "vld3.8 {d0, d2, d4}, [%0]! \n" // load 8 RGB24 pixels.
1962 "vld3.8 {d1, d3, d5}, [%0]! \n" // load next 8 RGB24 pixels.
1963 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
1964 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
1965 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
1967 "vld3.8 {d8, d10, d12}, [%1]! \n" // load 8 more RGB24 pixels.
1969 "vld3.8 {d9, d11, d13}, [%1]! \n" // load last 8 RGB24 pixels.
1970 "vpadal.u8 q0, q4 \n" // B 16 bytes -> 8 shorts.
1971 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
1972 "vpadal.u8 q2, q6 \n" // R 16 bytes -> 8 shorts.
1974 "vrshr.u16 q0, q0, #1 \n" // 2x average
1975 "vrshr.u16 q1, q1, #1 \n"
1976 "vrshr.u16 q2, q2, #1 \n"
1978 "subs %4, %4, #16 \n" // 32 processed per loop.
1981 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
1983 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
1985 : "+r"(src_rgb24), // %0
1986 "+r"(src_stride_rgb24), // %1
1991 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
1992 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
1996 void RAWToUVRow_NEON(const uint8* src_raw, int src_stride_raw,
1997 uint8* dst_u, uint8* dst_v, int pix) {
1999 "add %1, %0, %1 \n" // src_stride + src_raw
2000 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
2001 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
2002 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
2003 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
2004 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
2005 "vmov.u16 q15, #0x8080 \n" // 128.5
2009 "vld3.8 {d0, d2, d4}, [%0]! \n" // load 8 RAW pixels.
2011 "vld3.8 {d1, d3, d5}, [%0]! \n" // load next 8 RAW pixels.
2012 "vpaddl.u8 q2, q2 \n" // B 16 bytes -> 8 shorts.
2013 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
2014 "vpaddl.u8 q0, q0 \n" // R 16 bytes -> 8 shorts.
2016 "vld3.8 {d8, d10, d12}, [%1]! \n" // load 8 more RAW pixels.
2018 "vld3.8 {d9, d11, d13}, [%1]! \n" // load last 8 RAW pixels.
2019 "vpadal.u8 q2, q6 \n" // B 16 bytes -> 8 shorts.
2020 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
2021 "vpadal.u8 q0, q4 \n" // R 16 bytes -> 8 shorts.
2023 "vrshr.u16 q0, q0, #1 \n" // 2x average
2024 "vrshr.u16 q1, q1, #1 \n"
2025 "vrshr.u16 q2, q2, #1 \n"
2027 "subs %4, %4, #16 \n" // 32 processed per loop.
2030 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
2032 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
2034 : "+r"(src_raw), // %0
2035 "+r"(src_stride_raw), // %1
2040 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
2041 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
2045 // 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
2046 void RGB565ToUVRow_NEON(const uint8* src_rgb565, int src_stride_rgb565,
2047 uint8* dst_u, uint8* dst_v, int pix) {
2049 "add %1, %0, %1 \n" // src_stride + src_argb
2050 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
2051 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
2052 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
2053 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
2054 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
2055 "vmov.u16 q15, #0x8080 \n" // 128.5
2059 "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels.
2061 "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
2062 "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
2063 "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
2065 "vld1.8 {q0}, [%0]! \n" // next 8 RGB565 pixels.
2067 "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
2068 "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
2069 "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
2072 "vld1.8 {q0}, [%1]! \n" // load 8 RGB565 pixels.
2074 "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
2075 "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
2076 "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
2078 "vld1.8 {q0}, [%1]! \n" // next 8 RGB565 pixels.
2080 "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
2081 "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
2082 "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
2084 "vrshr.u16 q4, q4, #1 \n" // 2x average
2085 "vrshr.u16 q5, q5, #1 \n"
2086 "vrshr.u16 q6, q6, #1 \n"
2088 "subs %4, %4, #16 \n" // 16 processed per loop.
2089 "vmul.s16 q8, q4, q10 \n" // B
2090 "vmls.s16 q8, q5, q11 \n" // G
2091 "vmls.s16 q8, q6, q12 \n" // R
2092 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
2093 "vmul.s16 q9, q6, q10 \n" // R
2094 "vmls.s16 q9, q5, q14 \n" // G
2095 "vmls.s16 q9, q4, q13 \n" // B
2096 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
2097 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
2098 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
2100 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
2102 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
2104 : "+r"(src_rgb565), // %0
2105 "+r"(src_stride_rgb565), // %1
2110 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
2111 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
2115 // 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
2116 void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, int src_stride_argb1555,
2117 uint8* dst_u, uint8* dst_v, int pix) {
2119 "add %1, %0, %1 \n" // src_stride + src_argb
2120 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
2121 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
2122 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
2123 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
2124 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
2125 "vmov.u16 q15, #0x8080 \n" // 128.5
2129 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels.
2131 "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
2132 "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
2133 "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
2135 "vld1.8 {q0}, [%0]! \n" // next 8 ARGB1555 pixels.
2137 "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
2138 "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
2139 "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
2142 "vld1.8 {q0}, [%1]! \n" // load 8 ARGB1555 pixels.
2144 "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
2145 "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
2146 "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
2148 "vld1.8 {q0}, [%1]! \n" // next 8 ARGB1555 pixels.
2150 "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
2151 "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
2152 "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
2154 "vrshr.u16 q4, q4, #1 \n" // 2x average
2155 "vrshr.u16 q5, q5, #1 \n"
2156 "vrshr.u16 q6, q6, #1 \n"
2158 "subs %4, %4, #16 \n" // 16 processed per loop.
2159 "vmul.s16 q8, q4, q10 \n" // B
2160 "vmls.s16 q8, q5, q11 \n" // G
2161 "vmls.s16 q8, q6, q12 \n" // R
2162 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
2163 "vmul.s16 q9, q6, q10 \n" // R
2164 "vmls.s16 q9, q5, q14 \n" // G
2165 "vmls.s16 q9, q4, q13 \n" // B
2166 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
2167 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
2168 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
2170 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
2172 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
2174 : "+r"(src_argb1555), // %0
2175 "+r"(src_stride_argb1555), // %1
2180 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
2181 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
2185 // 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
2186 void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, int src_stride_argb4444,
2187 uint8* dst_u, uint8* dst_v, int pix) {
2189 "add %1, %0, %1 \n" // src_stride + src_argb
2190 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
2191 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
2192 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
2193 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
2194 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
2195 "vmov.u16 q15, #0x8080 \n" // 128.5
2199 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels.
2201 "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
2202 "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
2203 "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
2205 "vld1.8 {q0}, [%0]! \n" // next 8 ARGB4444 pixels.
2207 "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
2208 "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
2209 "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
2212 "vld1.8 {q0}, [%1]! \n" // load 8 ARGB4444 pixels.
2214 "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
2215 "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
2216 "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
2218 "vld1.8 {q0}, [%1]! \n" // next 8 ARGB4444 pixels.
2220 "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
2221 "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
2222 "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
2224 "vrshr.u16 q4, q4, #1 \n" // 2x average
2225 "vrshr.u16 q5, q5, #1 \n"
2226 "vrshr.u16 q6, q6, #1 \n"
2228 "subs %4, %4, #16 \n" // 16 processed per loop.
2229 "vmul.s16 q8, q4, q10 \n" // B
2230 "vmls.s16 q8, q5, q11 \n" // G
2231 "vmls.s16 q8, q6, q12 \n" // R
2232 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
2233 "vmul.s16 q9, q6, q10 \n" // R
2234 "vmls.s16 q9, q5, q14 \n" // G
2235 "vmls.s16 q9, q4, q13 \n" // B
2236 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
2237 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
2238 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
2240 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
2242 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
2244 : "+r"(src_argb4444), // %0
2245 "+r"(src_stride_argb4444), // %1
2250 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
2251 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
2255 void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int pix) {
2257 "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient
2258 "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient
2259 "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient
2260 "vmov.u8 d27, #16 \n" // Add 16 constant
2264 "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels.
2265 "subs %2, %2, #8 \n" // 8 processed per loop.
2267 "vmull.u8 q2, d0, d24 \n" // B
2268 "vmlal.u8 q2, d1, d25 \n" // G
2269 "vmlal.u8 q2, d2, d26 \n" // R
2270 "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y
2271 "vqadd.u8 d0, d27 \n"
2273 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
2275 : "+r"(src_rgb565), // %0
2279 : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
2283 void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int pix) {
2285 "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient
2286 "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient
2287 "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient
2288 "vmov.u8 d27, #16 \n" // Add 16 constant
2292 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels.
2293 "subs %2, %2, #8 \n" // 8 processed per loop.
2295 "vmull.u8 q2, d0, d24 \n" // B
2296 "vmlal.u8 q2, d1, d25 \n" // G
2297 "vmlal.u8 q2, d2, d26 \n" // R
2298 "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y
2299 "vqadd.u8 d0, d27 \n"
2301 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
2303 : "+r"(src_argb1555), // %0
2307 : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
2311 void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int pix) {
2313 "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient
2314 "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient
2315 "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient
2316 "vmov.u8 d27, #16 \n" // Add 16 constant
2320 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels.
2321 "subs %2, %2, #8 \n" // 8 processed per loop.
2323 "vmull.u8 q2, d0, d24 \n" // B
2324 "vmlal.u8 q2, d1, d25 \n" // G
2325 "vmlal.u8 q2, d2, d26 \n" // R
2326 "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y
2327 "vqadd.u8 d0, d27 \n"
2329 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
2331 : "+r"(src_argb4444), // %0
2335 : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
2339 void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int pix) {
2341 "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient
2342 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
2343 "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient
2344 "vmov.u8 d7, #16 \n" // Add 16 constant
2348 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of BGRA.
2349 "subs %2, %2, #8 \n" // 8 processed per loop.
2350 "vmull.u8 q8, d1, d4 \n" // R
2351 "vmlal.u8 q8, d2, d5 \n" // G
2352 "vmlal.u8 q8, d3, d6 \n" // B
2353 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
2354 "vqadd.u8 d0, d7 \n"
2356 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
2358 : "+r"(src_bgra), // %0
2362 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2366 void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int pix) {
2368 "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient
2369 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
2370 "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient
2371 "vmov.u8 d7, #16 \n" // Add 16 constant
2375 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ABGR.
2376 "subs %2, %2, #8 \n" // 8 processed per loop.
2377 "vmull.u8 q8, d0, d4 \n" // R
2378 "vmlal.u8 q8, d1, d5 \n" // G
2379 "vmlal.u8 q8, d2, d6 \n" // B
2380 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
2381 "vqadd.u8 d0, d7 \n"
2383 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
2385 : "+r"(src_abgr), // %0
2389 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2393 void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int pix) {
2395 "vmov.u8 d4, #13 \n" // B * 0.1016 coefficient
2396 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
2397 "vmov.u8 d6, #33 \n" // R * 0.2578 coefficient
2398 "vmov.u8 d7, #16 \n" // Add 16 constant
2402 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of RGBA.
2403 "subs %2, %2, #8 \n" // 8 processed per loop.
2404 "vmull.u8 q8, d1, d4 \n" // B
2405 "vmlal.u8 q8, d2, d5 \n" // G
2406 "vmlal.u8 q8, d3, d6 \n" // R
2407 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
2408 "vqadd.u8 d0, d7 \n"
2410 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
2412 : "+r"(src_rgba), // %0
2416 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2420 void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int pix) {
2422 "vmov.u8 d4, #13 \n" // B * 0.1016 coefficient
2423 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
2424 "vmov.u8 d6, #33 \n" // R * 0.2578 coefficient
2425 "vmov.u8 d7, #16 \n" // Add 16 constant
2429 "vld3.8 {d0, d1, d2}, [%0]! \n" // load 8 pixels of RGB24.
2430 "subs %2, %2, #8 \n" // 8 processed per loop.
2431 "vmull.u8 q8, d0, d4 \n" // B
2432 "vmlal.u8 q8, d1, d5 \n" // G
2433 "vmlal.u8 q8, d2, d6 \n" // R
2434 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
2435 "vqadd.u8 d0, d7 \n"
2437 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
2439 : "+r"(src_rgb24), // %0
2443 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2447 void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int pix) {
2449 "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient
2450 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
2451 "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient
2452 "vmov.u8 d7, #16 \n" // Add 16 constant
2456 "vld3.8 {d0, d1, d2}, [%0]! \n" // load 8 pixels of RAW.
2457 "subs %2, %2, #8 \n" // 8 processed per loop.
2458 "vmull.u8 q8, d0, d4 \n" // B
2459 "vmlal.u8 q8, d1, d5 \n" // G
2460 "vmlal.u8 q8, d2, d6 \n" // R
2461 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
2462 "vqadd.u8 d0, d7 \n"
2464 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
2466 : "+r"(src_raw), // %0
2470 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
2474 // Bilinear filter 16x2 -> 16x1
2475 void InterpolateRow_NEON(uint8* dst_ptr,
2476 const uint8* src_ptr, ptrdiff_t src_stride,
2477 int dst_width, int source_y_fraction) {
2492 // General purpose row blend.
2495 "vld1.8 {q0}, [%1]! \n"
2497 "vld1.8 {q1}, [%2]! \n"
2498 "subs %3, %3, #16 \n"
2499 "vmull.u8 q13, d0, d4 \n"
2500 "vmull.u8 q14, d1, d4 \n"
2501 "vmlal.u8 q13, d2, d5 \n"
2502 "vmlal.u8 q14, d3, d5 \n"
2503 "vrshrn.u16 d0, q13, #8 \n"
2504 "vrshrn.u16 d1, q14, #8 \n"
2506 "vst1.8 {q0}, [%0]! \n"
2513 "vld1.8 {q0}, [%1]! \n"
2515 "vld1.8 {q1}, [%2]! \n"
2516 "subs %3, %3, #16 \n"
2517 "vrhadd.u8 q0, q1 \n"
2518 "vrhadd.u8 q0, q1 \n"
2520 "vst1.8 {q0}, [%0]! \n"
2527 "vld1.8 {q0}, [%1]! \n"
2529 "vld1.8 {q1}, [%2]! \n"
2530 "subs %3, %3, #16 \n"
2531 "vrhadd.u8 q0, q1 \n"
2533 "vst1.8 {q0}, [%0]! \n"
2540 "vld1.8 {q1}, [%1]! \n"
2542 "vld1.8 {q0}, [%2]! \n"
2543 "subs %3, %3, #16 \n"
2544 "vrhadd.u8 q0, q1 \n"
2545 "vrhadd.u8 q0, q1 \n"
2547 "vst1.8 {q0}, [%0]! \n"
2551 // Blend 100 / 0 - Copy row unchanged.
2554 "vld1.8 {q0}, [%1]! \n"
2555 "subs %3, %3, #16 \n"
2557 "vst1.8 {q0}, [%0]! \n"
2561 : "+r"(dst_ptr), // %0
2562 "+r"(src_ptr), // %1
2563 "+r"(src_stride), // %2
2564 "+r"(dst_width), // %3
2565 "+r"(source_y_fraction) // %4
2567 : "cc", "memory", "q0", "q1", "d4", "d5", "q13", "q14"
2571 // dr * (256 - sa) / 256 + sr = dr - dr * sa / 256 + sr
2572 void ARGBBlendRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
2573 uint8* dst_argb, int width) {
2580 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ARGB0.
2582 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 pixels of ARGB1.
2583 "subs %3, %3, #8 \n" // 8 processed per loop.
2584 "vmull.u8 q10, d4, d3 \n" // db * a
2585 "vmull.u8 q11, d5, d3 \n" // dg * a
2586 "vmull.u8 q12, d6, d3 \n" // dr * a
2587 "vqrshrn.u16 d20, q10, #8 \n" // db >>= 8
2588 "vqrshrn.u16 d21, q11, #8 \n" // dg >>= 8
2589 "vqrshrn.u16 d22, q12, #8 \n" // dr >>= 8
2590 "vqsub.u8 q2, q2, q10 \n" // dbg - dbg * a / 256
2591 "vqsub.u8 d6, d6, d22 \n" // dr - dr * a / 256
2592 "vqadd.u8 q0, q0, q2 \n" // + sbg
2593 "vqadd.u8 d2, d2, d6 \n" // + sr
2594 "vmov.u8 d3, #255 \n" // a = 255
2596 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 pixels of ARGB.
2606 "vld4.8 {d0[0],d1[0],d2[0],d3[0]}, [%0]! \n" // load 1 pixel ARGB0.
2608 "vld4.8 {d4[0],d5[0],d6[0],d7[0]}, [%1]! \n" // load 1 pixel ARGB1.
2609 "subs %3, %3, #1 \n" // 1 processed per loop.
2610 "vmull.u8 q10, d4, d3 \n" // db * a
2611 "vmull.u8 q11, d5, d3 \n" // dg * a
2612 "vmull.u8 q12, d6, d3 \n" // dr * a
2613 "vqrshrn.u16 d20, q10, #8 \n" // db >>= 8
2614 "vqrshrn.u16 d21, q11, #8 \n" // dg >>= 8
2615 "vqrshrn.u16 d22, q12, #8 \n" // dr >>= 8
2616 "vqsub.u8 q2, q2, q10 \n" // dbg - dbg * a / 256
2617 "vqsub.u8 d6, d6, d22 \n" // dr - dr * a / 256
2618 "vqadd.u8 q0, q0, q2 \n" // + sbg
2619 "vqadd.u8 d2, d2, d6 \n" // + sr
2620 "vmov.u8 d3, #255 \n" // a = 255
2622 "vst4.8 {d0[0],d1[0],d2[0],d3[0]}, [%2]! \n" // store 1 pixel.
2627 : "+r"(src_argb0), // %0
2628 "+r"(src_argb1), // %1
2629 "+r"(dst_argb), // %2
2632 : "cc", "memory", "q0", "q1", "q2", "q3", "q10", "q11", "q12"
2636 // Attenuate 8 pixels at a time.
2637 void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) {
2639 // Attenuate 8 pixels.
2642 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ARGB.
2643 "subs %2, %2, #8 \n" // 8 processed per loop.
2644 "vmull.u8 q10, d0, d3 \n" // b * a
2645 "vmull.u8 q11, d1, d3 \n" // g * a
2646 "vmull.u8 q12, d2, d3 \n" // r * a
2647 "vqrshrn.u16 d0, q10, #8 \n" // b >>= 8
2648 "vqrshrn.u16 d1, q11, #8 \n" // g >>= 8
2649 "vqrshrn.u16 d2, q12, #8 \n" // r >>= 8
2651 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB.
2653 : "+r"(src_argb), // %0
2654 "+r"(dst_argb), // %1
2657 : "cc", "memory", "q0", "q1", "q10", "q11", "q12"
2661 // Quantize 8 ARGB pixels (32 bytes).
2662 // dst = (dst * scale >> 16) * interval_size + interval_offset;
2663 void ARGBQuantizeRow_NEON(uint8* dst_argb, int scale, int interval_size,
2664 int interval_offset, int width) {
2666 "vdup.u16 q8, %2 \n"
2667 "vshr.u16 q8, q8, #1 \n" // scale >>= 1
2668 "vdup.u16 q9, %3 \n" // interval multiply.
2669 "vdup.u16 q10, %4 \n" // interval add
2675 "vld4.8 {d0, d2, d4, d6}, [%0] \n" // load 8 pixels of ARGB.
2676 "subs %1, %1, #8 \n" // 8 processed per loop.
2677 "vmovl.u8 q0, d0 \n" // b (0 .. 255)
2678 "vmovl.u8 q1, d2 \n"
2679 "vmovl.u8 q2, d4 \n"
2680 "vqdmulh.s16 q0, q0, q8 \n" // b * scale
2681 "vqdmulh.s16 q1, q1, q8 \n" // g
2682 "vqdmulh.s16 q2, q2, q8 \n" // r
2683 "vmul.u16 q0, q0, q9 \n" // b * interval_size
2684 "vmul.u16 q1, q1, q9 \n" // g
2685 "vmul.u16 q2, q2, q9 \n" // r
2686 "vadd.u16 q0, q0, q10 \n" // b + interval_offset
2687 "vadd.u16 q1, q1, q10 \n" // g
2688 "vadd.u16 q2, q2, q10 \n" // r
2689 "vqmovn.u16 d0, q0 \n"
2690 "vqmovn.u16 d2, q1 \n"
2691 "vqmovn.u16 d4, q2 \n"
2693 "vst4.8 {d0, d2, d4, d6}, [%0]! \n" // store 8 pixels of ARGB.
2695 : "+r"(dst_argb), // %0
2698 "r"(interval_size), // %3
2699 "r"(interval_offset) // %4
2700 : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10"
2704 // Shade 8 pixels at a time by specified value.
2705 // NOTE vqrdmulh.s16 q10, q10, d0[0] must use a scaler register from 0 to 8.
2706 // Rounding in vqrdmulh does +1 to high if high bit of low s16 is set.
2707 void ARGBShadeRow_NEON(const uint8* src_argb, uint8* dst_argb, int width,
2710 "vdup.u32 q0, %3 \n" // duplicate scale value.
2711 "vzip.u8 d0, d1 \n" // d0 aarrggbb.
2712 "vshr.u16 q0, q0, #1 \n" // scale / 2.
2718 "vld4.8 {d20, d22, d24, d26}, [%0]! \n" // load 8 pixels of ARGB.
2719 "subs %2, %2, #8 \n" // 8 processed per loop.
2720 "vmovl.u8 q10, d20 \n" // b (0 .. 255)
2721 "vmovl.u8 q11, d22 \n"
2722 "vmovl.u8 q12, d24 \n"
2723 "vmovl.u8 q13, d26 \n"
2724 "vqrdmulh.s16 q10, q10, d0[0] \n" // b * scale * 2
2725 "vqrdmulh.s16 q11, q11, d0[1] \n" // g
2726 "vqrdmulh.s16 q12, q12, d0[2] \n" // r
2727 "vqrdmulh.s16 q13, q13, d0[3] \n" // a
2728 "vqmovn.u16 d20, q10 \n"
2729 "vqmovn.u16 d22, q11 \n"
2730 "vqmovn.u16 d24, q12 \n"
2731 "vqmovn.u16 d26, q13 \n"
2733 "vst4.8 {d20, d22, d24, d26}, [%1]! \n" // store 8 pixels of ARGB.
2735 : "+r"(src_argb), // %0
2736 "+r"(dst_argb), // %1
2739 : "cc", "memory", "q0", "q10", "q11", "q12", "q13"
2743 // Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels
2744 // Similar to ARGBToYJ but stores ARGB.
2745 // C code is (15 * b + 75 * g + 38 * r + 64) >> 7;
2746 void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) {
2748 "vmov.u8 d24, #15 \n" // B * 0.11400 coefficient
2749 "vmov.u8 d25, #75 \n" // G * 0.58700 coefficient
2750 "vmov.u8 d26, #38 \n" // R * 0.29900 coefficient
2754 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
2755 "subs %2, %2, #8 \n" // 8 processed per loop.
2756 "vmull.u8 q2, d0, d24 \n" // B
2757 "vmlal.u8 q2, d1, d25 \n" // G
2758 "vmlal.u8 q2, d2, d26 \n" // R
2759 "vqrshrun.s16 d0, q2, #7 \n" // 15 bit to 8 bit B
2760 "vmov d1, d0 \n" // G
2761 "vmov d2, d0 \n" // R
2763 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 ARGB pixels.
2765 : "+r"(src_argb), // %0
2766 "+r"(dst_argb), // %1
2769 : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
2773 // Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels.
2774 // b = (r * 35 + g * 68 + b * 17) >> 7
2775 // g = (r * 45 + g * 88 + b * 22) >> 7
2776 // r = (r * 50 + g * 98 + b * 24) >> 7
2777 void ARGBSepiaRow_NEON(uint8* dst_argb, int width) {
2779 "vmov.u8 d20, #17 \n" // BB coefficient
2780 "vmov.u8 d21, #68 \n" // BG coefficient
2781 "vmov.u8 d22, #35 \n" // BR coefficient
2782 "vmov.u8 d24, #22 \n" // GB coefficient
2783 "vmov.u8 d25, #88 \n" // GG coefficient
2784 "vmov.u8 d26, #45 \n" // GR coefficient
2785 "vmov.u8 d28, #24 \n" // BB coefficient
2786 "vmov.u8 d29, #98 \n" // BG coefficient
2787 "vmov.u8 d30, #50 \n" // BR coefficient
2791 "vld4.8 {d0, d1, d2, d3}, [%0] \n" // load 8 ARGB pixels.
2792 "subs %1, %1, #8 \n" // 8 processed per loop.
2793 "vmull.u8 q2, d0, d20 \n" // B to Sepia B
2794 "vmlal.u8 q2, d1, d21 \n" // G
2795 "vmlal.u8 q2, d2, d22 \n" // R
2796 "vmull.u8 q3, d0, d24 \n" // B to Sepia G
2797 "vmlal.u8 q3, d1, d25 \n" // G
2798 "vmlal.u8 q3, d2, d26 \n" // R
2799 "vmull.u8 q8, d0, d28 \n" // B to Sepia R
2800 "vmlal.u8 q8, d1, d29 \n" // G
2801 "vmlal.u8 q8, d2, d30 \n" // R
2802 "vqshrn.u16 d0, q2, #7 \n" // 16 bit to 8 bit B
2803 "vqshrn.u16 d1, q3, #7 \n" // 16 bit to 8 bit G
2804 "vqshrn.u16 d2, q8, #7 \n" // 16 bit to 8 bit R
2806 "vst4.8 {d0, d1, d2, d3}, [%0]! \n" // store 8 ARGB pixels.
2808 : "+r"(dst_argb), // %0
2811 : "cc", "memory", "q0", "q1", "q2", "q3",
2812 "q10", "q11", "q12", "q13", "q14", "q15"
2816 // Tranform 8 ARGB pixels (32 bytes) with color matrix.
2817 // TODO(fbarchard): Was same as Sepia except matrix is provided. This function
2818 // needs to saturate. Consider doing a non-saturating version.
2819 void ARGBColorMatrixRow_NEON(const uint8* src_argb, uint8* dst_argb,
2820 const int8* matrix_argb, int width) {
2823 "vld1.8 {q2}, [%3] \n" // load 3 ARGB vectors.
2824 "vmovl.s8 q0, d4 \n" // B,G coefficients s16.
2825 "vmovl.s8 q1, d5 \n" // R,A coefficients s16.
2830 "vld4.8 {d16, d18, d20, d22}, [%0]! \n" // load 8 ARGB pixels.
2831 "subs %2, %2, #8 \n" // 8 processed per loop.
2832 "vmovl.u8 q8, d16 \n" // b (0 .. 255) 16 bit
2833 "vmovl.u8 q9, d18 \n" // g
2834 "vmovl.u8 q10, d20 \n" // r
2835 "vmovl.u8 q15, d22 \n" // a
2836 "vmul.s16 q12, q8, d0[0] \n" // B = B * Matrix B
2837 "vmul.s16 q13, q8, d1[0] \n" // G = B * Matrix G
2838 "vmul.s16 q14, q8, d2[0] \n" // R = B * Matrix R
2839 "vmul.s16 q15, q8, d3[0] \n" // A = B * Matrix A
2840 "vmul.s16 q4, q9, d0[1] \n" // B += G * Matrix B
2841 "vmul.s16 q5, q9, d1[1] \n" // G += G * Matrix G
2842 "vmul.s16 q6, q9, d2[1] \n" // R += G * Matrix R
2843 "vmul.s16 q7, q9, d3[1] \n" // A += G * Matrix A
2844 "vqadd.s16 q12, q12, q4 \n" // Accumulate B
2845 "vqadd.s16 q13, q13, q5 \n" // Accumulate G
2846 "vqadd.s16 q14, q14, q6 \n" // Accumulate R
2847 "vqadd.s16 q15, q15, q7 \n" // Accumulate A
2848 "vmul.s16 q4, q10, d0[2] \n" // B += R * Matrix B
2849 "vmul.s16 q5, q10, d1[2] \n" // G += R * Matrix G
2850 "vmul.s16 q6, q10, d2[2] \n" // R += R * Matrix R
2851 "vmul.s16 q7, q10, d3[2] \n" // A += R * Matrix A
2852 "vqadd.s16 q12, q12, q4 \n" // Accumulate B
2853 "vqadd.s16 q13, q13, q5 \n" // Accumulate G
2854 "vqadd.s16 q14, q14, q6 \n" // Accumulate R
2855 "vqadd.s16 q15, q15, q7 \n" // Accumulate A
2856 "vmul.s16 q4, q15, d0[3] \n" // B += A * Matrix B
2857 "vmul.s16 q5, q15, d1[3] \n" // G += A * Matrix G
2858 "vmul.s16 q6, q15, d2[3] \n" // R += A * Matrix R
2859 "vmul.s16 q7, q15, d3[3] \n" // A += A * Matrix A
2860 "vqadd.s16 q12, q12, q4 \n" // Accumulate B
2861 "vqadd.s16 q13, q13, q5 \n" // Accumulate G
2862 "vqadd.s16 q14, q14, q6 \n" // Accumulate R
2863 "vqadd.s16 q15, q15, q7 \n" // Accumulate A
2864 "vqshrun.s16 d16, q12, #6 \n" // 16 bit to 8 bit B
2865 "vqshrun.s16 d18, q13, #6 \n" // 16 bit to 8 bit G
2866 "vqshrun.s16 d20, q14, #6 \n" // 16 bit to 8 bit R
2867 "vqshrun.s16 d22, q15, #6 \n" // 16 bit to 8 bit A
2869 "vst4.8 {d16, d18, d20, d22}, [%1]! \n" // store 8 ARGB pixels.
2871 : "+r"(src_argb), // %0
2872 "+r"(dst_argb), // %1
2874 : "r"(matrix_argb) // %3
2875 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
2876 "q10", "q11", "q12", "q13", "q14", "q15"
2880 // TODO(fbarchard): fix vqshrun in ARGBMultiplyRow_NEON and reenable.
2881 #ifdef HAS_ARGBMULTIPLYROW_NEON
2882 // Multiply 2 rows of ARGB pixels together, 8 pixels at a time.
2883 void ARGBMultiplyRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
2884 uint8* dst_argb, int width) {
2890 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
2892 "vld4.8 {d1, d3, d5, d7}, [%1]! \n" // load 8 more ARGB pixels.
2893 "subs %3, %3, #8 \n" // 8 processed per loop.
2894 "vmull.u8 q0, d0, d1 \n" // multiply B
2895 "vmull.u8 q1, d2, d3 \n" // multiply G
2896 "vmull.u8 q2, d4, d5 \n" // multiply R
2897 "vmull.u8 q3, d6, d7 \n" // multiply A
2898 "vrshrn.u16 d0, q0, #8 \n" // 16 bit to 8 bit B
2899 "vrshrn.u16 d1, q1, #8 \n" // 16 bit to 8 bit G
2900 "vrshrn.u16 d2, q2, #8 \n" // 16 bit to 8 bit R
2901 "vrshrn.u16 d3, q3, #8 \n" // 16 bit to 8 bit A
2903 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
2906 : "+r"(src_argb0), // %0
2907 "+r"(src_argb1), // %1
2908 "+r"(dst_argb), // %2
2911 : "cc", "memory", "q0", "q1", "q2", "q3"
2914 #endif // HAS_ARGBMULTIPLYROW_NEON
2916 // Add 2 rows of ARGB pixels together, 8 pixels at a time.
2917 void ARGBAddRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
2918 uint8* dst_argb, int width) {
2924 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
2926 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 more ARGB pixels.
2927 "subs %3, %3, #8 \n" // 8 processed per loop.
2928 "vqadd.u8 q0, q0, q2 \n" // add B, G
2929 "vqadd.u8 q1, q1, q3 \n" // add R, A
2931 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
2934 : "+r"(src_argb0), // %0
2935 "+r"(src_argb1), // %1
2936 "+r"(dst_argb), // %2
2939 : "cc", "memory", "q0", "q1", "q2", "q3"
2943 // Subtract 2 rows of ARGB pixels, 8 pixels at a time.
2944 void ARGBSubtractRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
2945 uint8* dst_argb, int width) {
2951 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
2953 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 more ARGB pixels.
2954 "subs %3, %3, #8 \n" // 8 processed per loop.
2955 "vqsub.u8 q0, q0, q2 \n" // subtract B, G
2956 "vqsub.u8 q1, q1, q3 \n" // subtract R, A
2958 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
2961 : "+r"(src_argb0), // %0
2962 "+r"(src_argb1), // %1
2963 "+r"(dst_argb), // %2
2966 : "cc", "memory", "q0", "q1", "q2", "q3"
2970 // Adds Sobel X and Sobel Y and stores Sobel into ARGB.
2975 void SobelRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
2976 uint8* dst_argb, int width) {
2978 "vmov.u8 d3, #255 \n" // alpha
2983 "vld1.8 {d0}, [%0]! \n" // load 8 sobelx.
2985 "vld1.8 {d1}, [%1]! \n" // load 8 sobely.
2986 "subs %3, %3, #8 \n" // 8 processed per loop.
2987 "vqadd.u8 d0, d0, d1 \n" // add
2991 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
2993 : "+r"(src_sobelx), // %0
2994 "+r"(src_sobely), // %1
2995 "+r"(dst_argb), // %2
2998 : "cc", "memory", "q0", "q1"
3002 // Adds Sobel X and Sobel Y and stores Sobel into plane.
3003 void SobelToPlaneRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
3004 uint8* dst_y, int width) {
3010 "vld1.8 {q0}, [%0]! \n" // load 16 sobelx.
3012 "vld1.8 {q1}, [%1]! \n" // load 16 sobely.
3013 "subs %3, %3, #16 \n" // 16 processed per loop.
3014 "vqadd.u8 q0, q0, q1 \n" // add
3016 "vst1.8 {q0}, [%2]! \n" // store 16 pixels.
3018 : "+r"(src_sobelx), // %0
3019 "+r"(src_sobely), // %1
3023 : "cc", "memory", "q0", "q1"
3027 // Mixes Sobel X, Sobel Y and Sobel into ARGB.
3032 void SobelXYRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
3033 uint8* dst_argb, int width) {
3035 "vmov.u8 d3, #255 \n" // alpha
3040 "vld1.8 {d2}, [%0]! \n" // load 8 sobelx.
3042 "vld1.8 {d0}, [%1]! \n" // load 8 sobely.
3043 "subs %3, %3, #8 \n" // 8 processed per loop.
3044 "vqadd.u8 d1, d0, d2 \n" // add
3046 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
3048 : "+r"(src_sobelx), // %0
3049 "+r"(src_sobely), // %1
3050 "+r"(dst_argb), // %2
3053 : "cc", "memory", "q0", "q1"
3057 // SobelX as a matrix is
3061 void SobelXRow_NEON(const uint8* src_y0, const uint8* src_y1,
3062 const uint8* src_y2, uint8* dst_sobelx, int width) {
3067 "vld1.8 {d0}, [%0],%5 \n" // top
3069 "vld1.8 {d1}, [%0],%6 \n"
3070 "vsubl.u8 q0, d0, d1 \n"
3072 "vld1.8 {d2}, [%1],%5 \n" // center * 2
3074 "vld1.8 {d3}, [%1],%6 \n"
3075 "vsubl.u8 q1, d2, d3 \n"
3076 "vadd.s16 q0, q0, q1 \n"
3077 "vadd.s16 q0, q0, q1 \n"
3079 "vld1.8 {d2}, [%2],%5 \n" // bottom
3081 "vld1.8 {d3}, [%2],%6 \n"
3082 "subs %4, %4, #8 \n" // 8 pixels
3083 "vsubl.u8 q1, d2, d3 \n"
3084 "vadd.s16 q0, q0, q1 \n"
3085 "vabs.s16 q0, q0 \n"
3086 "vqmovn.u16 d0, q0 \n"
3088 "vst1.8 {d0}, [%3]! \n" // store 8 sobelx
3090 : "+r"(src_y0), // %0
3093 "+r"(dst_sobelx), // %3
3097 : "cc", "memory", "q0", "q1" // Clobber List
3101 // SobelY as a matrix is
3105 void SobelYRow_NEON(const uint8* src_y0, const uint8* src_y1,
3106 uint8* dst_sobely, int width) {
3111 "vld1.8 {d0}, [%0],%4 \n" // left
3113 "vld1.8 {d1}, [%1],%4 \n"
3114 "vsubl.u8 q0, d0, d1 \n"
3116 "vld1.8 {d2}, [%0],%4 \n" // center * 2
3118 "vld1.8 {d3}, [%1],%4 \n"
3119 "vsubl.u8 q1, d2, d3 \n"
3120 "vadd.s16 q0, q0, q1 \n"
3121 "vadd.s16 q0, q0, q1 \n"
3123 "vld1.8 {d2}, [%0],%5 \n" // right
3125 "vld1.8 {d3}, [%1],%5 \n"
3126 "subs %3, %3, #8 \n" // 8 pixels
3127 "vsubl.u8 q1, d2, d3 \n"
3128 "vadd.s16 q0, q0, q1 \n"
3129 "vabs.s16 q0, q0 \n"
3130 "vqmovn.u16 d0, q0 \n"
3132 "vst1.8 {d0}, [%2]! \n" // store 8 sobely
3134 : "+r"(src_y0), // %0
3136 "+r"(dst_sobely), // %2
3140 : "cc", "memory", "q0", "q1" // Clobber List
3143 #endif // __ARM_NEON__
3147 } // namespace libyuv