| Index: source/libvpx/third_party/libyuv/source/scale_neon.cc
|
| diff --git a/source/libvpx/third_party/libyuv/source/scale_neon.cc b/source/libvpx/third_party/libyuv/source/scale_neon.cc
|
| index 7921219b5fa1e238787befa3aec0937a1825a011..7825878e983c1804beceb7427597de89f1b9a097 100644
|
| --- a/source/libvpx/third_party/libyuv/source/scale_neon.cc
|
| +++ b/source/libvpx/third_party/libyuv/source/scale_neon.cc
|
| @@ -43,6 +43,30 @@ void ScaleRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
|
| );
|
| }
|
|
|
| +// Read 32x1 average down and write 16x1.
|
| +void ScaleRowDown2Linear_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
|
| + uint8* dst, int dst_width) {
|
| + asm volatile (
|
| + ".p2align 2 \n"
|
| + "1: \n"
|
| + MEMACCESS(0)
|
| + "vld1.8 {q0, q1}, [%0]! \n" // load pixels and post inc
|
| + "subs %2, %2, #16 \n" // 16 processed per loop
|
| + "vpaddl.u8 q0, q0 \n" // add adjacent
|
| + "vpaddl.u8 q1, q1 \n"
|
| + "vrshrn.u16 d0, q0, #1 \n" // downshift, round and pack
|
| + "vrshrn.u16 d1, q1, #1 \n"
|
| + MEMACCESS(1)
|
| + "vst1.8 {q0}, [%1]! \n"
|
| + "bgt 1b \n"
|
| + : "+r"(src_ptr), // %0
|
| + "+r"(dst), // %1
|
| + "+r"(dst_width) // %2
|
| + :
|
| + : "q0", "q1" // Clobber List
|
| + );
|
| +}
|
| +
|
| // Read 32x2 average down and write 16x1.
|
| void ScaleRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
|
| uint8* dst, int dst_width) {
|
| @@ -517,6 +541,112 @@ void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr,
|
| );
|
| }
|
|
|
| +void ScaleAddRows_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
|
| + uint16* dst_ptr, int src_width, int src_height) {
|
| + const uint8* src_tmp = NULL;
|
| + asm volatile (
|
| + ".p2align 2 \n"
|
| + "1: \n"
|
| + "mov %0, %1 \n"
|
| + "mov r12, %5 \n"
|
| + "veor q2, q2, q2 \n"
|
| + "veor q3, q3, q3 \n"
|
| + "2: \n"
|
| + // load 16 pixels into q0
|
| + MEMACCESS(0)
|
| + "vld1.8 {q0}, [%0], %3 \n"
|
| + "vaddw.u8 q3, q3, d1 \n"
|
| + "vaddw.u8 q2, q2, d0 \n"
|
| + "subs r12, r12, #1 \n"
|
| + "bgt 2b \n"
|
| + MEMACCESS(2)
|
| + "vst1.16 {q2, q3}, [%2]! \n" // store pixels
|
| + "add %1, %1, #16 \n"
|
| + "subs %4, %4, #16 \n" // 16 processed per loop
|
| + "bgt 1b \n"
|
| + : "+r"(src_tmp), // %0
|
| + "+r"(src_ptr), // %1
|
| + "+r"(dst_ptr), // %2
|
| + "+r"(src_stride), // %3
|
| + "+r"(src_width), // %4
|
| + "+r"(src_height) // %5
|
| + :
|
| + : "memory", "cc", "r12", "q0", "q1", "q2", "q3" // Clobber List
|
| + );
|
| +}
|
| +
|
| +// TODO(Yang Zhang): Investigate less load instructions for
|
| +// the x/dx stepping
|
| +#define LOAD2_DATA8_LANE(n) \
|
| + "lsr %5, %3, #16 \n" \
|
| + "add %6, %1, %5 \n" \
|
| + "add %3, %3, %4 \n" \
|
| + MEMACCESS(6) \
|
| + "vld2.8 {d6["#n"], d7["#n"]}, [%6] \n"
|
| +
|
| +void ScaleFilterCols_NEON(uint8* dst_ptr, const uint8* src_ptr,
|
| + int dst_width, int x, int dx) {
|
| + int dx_offset[4] = {0, 1, 2, 3};
|
| + int* tmp = dx_offset;
|
| + const uint8* src_tmp = src_ptr;
|
| + asm volatile (
|
| + ".p2align 2 \n"
|
| + "vdup.32 q0, %3 \n" // x
|
| + "vdup.32 q1, %4 \n" // dx
|
| + "vld1.32 {q2}, [%5] \n" // 0 1 2 3
|
| + "vshl.i32 q3, q1, #2 \n" // 4 * dx
|
| + "vmul.s32 q1, q1, q2 \n"
|
| + // x , x + 1 * dx, x + 2 * dx, x + 3 * dx
|
| + "vadd.s32 q1, q1, q0 \n"
|
| + // x + 4 * dx, x + 5 * dx, x + 6 * dx, x + 7 * dx
|
| + "vadd.s32 q2, q1, q3 \n"
|
| + "vshl.i32 q0, q3, #1 \n" // 8 * dx
|
| + "1: \n"
|
| + LOAD2_DATA8_LANE(0)
|
| + LOAD2_DATA8_LANE(1)
|
| + LOAD2_DATA8_LANE(2)
|
| + LOAD2_DATA8_LANE(3)
|
| + LOAD2_DATA8_LANE(4)
|
| + LOAD2_DATA8_LANE(5)
|
| + LOAD2_DATA8_LANE(6)
|
| + LOAD2_DATA8_LANE(7)
|
| + "vmov q10, q1 \n"
|
| + "vmov q11, q2 \n"
|
| + "vuzp.16 q10, q11 \n"
|
| + "vmovl.u8 q8, d6 \n"
|
| + "vmovl.u8 q9, d7 \n"
|
| + "vsubl.s16 q11, d18, d16 \n"
|
| + "vsubl.s16 q12, d19, d17 \n"
|
| + "vmovl.u16 q13, d20 \n"
|
| + "vmovl.u16 q10, d21 \n"
|
| + "vmul.s32 q11, q11, q13 \n"
|
| + "vmul.s32 q12, q12, q10 \n"
|
| + "vshrn.s32 d18, q11, #16 \n"
|
| + "vshrn.s32 d19, q12, #16 \n"
|
| + "vadd.s16 q8, q8, q9 \n"
|
| + "vmovn.s16 d6, q8 \n"
|
| +
|
| + MEMACCESS(0)
|
| + "vst1.8 {d6}, [%0]! \n" // store pixels
|
| + "vadd.s32 q1, q1, q0 \n"
|
| + "vadd.s32 q2, q2, q0 \n"
|
| + "subs %2, %2, #8 \n" // 8 processed per loop
|
| + "bgt 1b \n"
|
| + : "+r"(dst_ptr), // %0
|
| + "+r"(src_ptr), // %1
|
| + "+r"(dst_width), // %2
|
| + "+r"(x), // %3
|
| + "+r"(dx), // %4
|
| + "+r"(tmp), // %5
|
| + "+r"(src_tmp) // %6
|
| + :
|
| + : "memory", "cc", "q0", "q1", "q2", "q3",
|
| + "q8", "q9", "q10", "q11", "q12", "q13"
|
| + );
|
| +}
|
| +
|
| +#undef LOAD2_DATA8_LANE
|
| +
|
| // 16x2 -> 16x1
|
| void ScaleFilterRows_NEON(uint8* dst_ptr,
|
| const uint8* src_ptr, ptrdiff_t src_stride,
|
| @@ -640,6 +770,35 @@ void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
|
| );
|
| }
|
|
|
| +void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, ptrdiff_t src_stride,
|
| + uint8* dst_argb, int dst_width) {
|
| + asm volatile (
|
| + ".p2align 2 \n"
|
| + "1: \n"
|
| + MEMACCESS(0)
|
| + "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
|
| + MEMACCESS(0)
|
| + "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
|
| + "subs %2, %2, #8 \n" // 8 processed per loop
|
| + "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
|
| + "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
|
| + "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
|
| + "vpaddl.u8 q3, q3 \n" // A 16 bytes -> 8 shorts.
|
| + "vrshrn.u16 d0, q0, #1 \n" // downshift, round and pack
|
| + "vrshrn.u16 d1, q1, #1 \n"
|
| + "vrshrn.u16 d2, q2, #1 \n"
|
| + "vrshrn.u16 d3, q3, #1 \n"
|
| + MEMACCESS(1)
|
| + "vst4.8 {d0, d1, d2, d3}, [%1]! \n"
|
| + "bgt 1b \n"
|
| + : "+r"(src_argb), // %0
|
| + "+r"(dst_argb), // %1
|
| + "+r"(dst_width) // %2
|
| + :
|
| + : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List
|
| + );
|
| +}
|
| +
|
| void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
|
| uint8* dst, int dst_width) {
|
| asm volatile (
|
| @@ -757,6 +916,119 @@ void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, ptrdiff_t src_stride,
|
| );
|
| }
|
|
|
| +// TODO(Yang Zhang): Investigate less load instructions for
|
| +// the x/dx stepping
|
| +#define LOAD1_DATA32_LANE(dn, n) \
|
| + "lsr %5, %3, #16 \n" \
|
| + "add %6, %1, %5, lsl #2 \n" \
|
| + "add %3, %3, %4 \n" \
|
| + MEMACCESS(6) \
|
| + "vld1.32 {"#dn"["#n"]}, [%6] \n"
|
| +
|
| +void ScaleARGBCols_NEON(uint8* dst_argb, const uint8* src_argb,
|
| + int dst_width, int x, int dx) {
|
| + int tmp = 0;
|
| + const uint8* src_tmp = src_argb;
|
| + asm volatile (
|
| + ".p2align 2 \n"
|
| + "1: \n"
|
| + LOAD1_DATA32_LANE(d0, 0)
|
| + LOAD1_DATA32_LANE(d0, 1)
|
| + LOAD1_DATA32_LANE(d1, 0)
|
| + LOAD1_DATA32_LANE(d1, 1)
|
| + LOAD1_DATA32_LANE(d2, 0)
|
| + LOAD1_DATA32_LANE(d2, 1)
|
| + LOAD1_DATA32_LANE(d3, 0)
|
| + LOAD1_DATA32_LANE(d3, 1)
|
| +
|
| + MEMACCESS(0)
|
| + "vst1.32 {q0, q1}, [%0]! \n" // store pixels
|
| + "subs %2, %2, #8 \n" // 8 processed per loop
|
| + "bgt 1b \n"
|
| + : "+r"(dst_argb), // %0
|
| + "+r"(src_argb), // %1
|
| + "+r"(dst_width), // %2
|
| + "+r"(x), // %3
|
| + "+r"(dx), // %4
|
| + "+r"(tmp), // %5
|
| + "+r"(src_tmp) // %6
|
| + :
|
| + : "memory", "cc", "q0", "q1"
|
| + );
|
| +}
|
| +
|
| +#undef LOAD1_DATA32_LANE
|
| +
|
| +// TODO(Yang Zhang): Investigate less load instructions for
|
| +// the x/dx stepping
|
| +#define LOAD2_DATA32_LANE(dn1, dn2, n) \
|
| + "lsr %5, %3, #16 \n" \
|
| + "add %6, %1, %5, lsl #2 \n" \
|
| + "add %3, %3, %4 \n" \
|
| + MEMACCESS(6) \
|
| + "vld2.32 {"#dn1"["#n"], "#dn2"["#n"]}, [%6] \n"
|
| +
|
| +void ScaleARGBFilterCols_NEON(uint8* dst_argb, const uint8* src_argb,
|
| + int dst_width, int x, int dx) {
|
| + int dx_offset[4] = {0, 1, 2, 3};
|
| + int* tmp = dx_offset;
|
| + const uint8* src_tmp = src_argb;
|
| + asm volatile (
|
| + ".p2align 2 \n"
|
| + "vdup.32 q0, %3 \n" // x
|
| + "vdup.32 q1, %4 \n" // dx
|
| + "vld1.32 {q2}, [%5] \n" // 0 1 2 3
|
| + "vshl.i32 q9, q1, #2 \n" // 4 * dx
|
| + "vmul.s32 q1, q1, q2 \n"
|
| + "vmov.i8 q3, #0x7f \n" // 0x7F
|
| + "vmov.i16 q15, #0x7f \n" // 0x7F
|
| + // x , x + 1 * dx, x + 2 * dx, x + 3 * dx
|
| + "vadd.s32 q8, q1, q0 \n"
|
| + "1: \n"
|
| + // d0, d1: a
|
| + // d2, d3: b
|
| + LOAD2_DATA32_LANE(d0, d2, 0)
|
| + LOAD2_DATA32_LANE(d0, d2, 1)
|
| + LOAD2_DATA32_LANE(d1, d3, 0)
|
| + LOAD2_DATA32_LANE(d1, d3, 1)
|
| + "vshrn.i32 d22, q8, #9 \n"
|
| + "vand.16 d22, d22, d30 \n"
|
| + "vdup.8 d24, d22[0] \n"
|
| + "vdup.8 d25, d22[2] \n"
|
| + "vdup.8 d26, d22[4] \n"
|
| + "vdup.8 d27, d22[6] \n"
|
| + "vext.8 d4, d24, d25, #4 \n"
|
| + "vext.8 d5, d26, d27, #4 \n" // f
|
| + "veor.8 q10, q2, q3 \n" // 0x7f ^ f
|
| + "vmull.u8 q11, d0, d20 \n"
|
| + "vmull.u8 q12, d1, d21 \n"
|
| + "vmull.u8 q13, d2, d4 \n"
|
| + "vmull.u8 q14, d3, d5 \n"
|
| + "vadd.i16 q11, q11, q13 \n"
|
| + "vadd.i16 q12, q12, q14 \n"
|
| + "vshrn.i16 d0, q11, #7 \n"
|
| + "vshrn.i16 d1, q12, #7 \n"
|
| +
|
| + MEMACCESS(0)
|
| + "vst1.32 {d0, d1}, [%0]! \n" // store pixels
|
| + "vadd.s32 q8, q8, q9 \n"
|
| + "subs %2, %2, #4 \n" // 4 processed per loop
|
| + "bgt 1b \n"
|
| + : "+r"(dst_argb), // %0
|
| + "+r"(src_argb), // %1
|
| + "+r"(dst_width), // %2
|
| + "+r"(x), // %3
|
| + "+r"(dx), // %4
|
| + "+r"(tmp), // %5
|
| + "+r"(src_tmp) // %6
|
| + :
|
| + : "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9",
|
| + "q10", "q11", "q12", "q13", "q14", "q15"
|
| + );
|
| +}
|
| +
|
| +#undef LOAD2_DATA32_LANE
|
| +
|
| #endif // defined(__ARM_NEON__) && !defined(__aarch64__)
|
|
|
| #ifdef __cplusplus
|
|
|