From 8e50e619dbf904099d2be5f42ae77ea06dd4c503 Mon Sep 17 00:00:00 2001 From: "fbarchard@google.com" Date: Fri, 16 Nov 2012 19:32:16 +0000 Subject: [PATCH] ARGBScale_NEON BUG=none TEST=./libyuv_unittest --gtest_filter=*ARGBScale* Review URL: https://webrtc-codereview.appspot.com/964016 git-svn-id: http://libyuv.googlecode.com/svn/trunk@494 16f28f9a-4ce2-e073-06de-1de4eb20be90 --- README.chromium | 2 +- include/libyuv/version.h | 2 +- source/scale_argb.cc | 17 ++++- source/scale_argb_neon.cc | 55 ++++++++++++++ source/scale_neon.cc | 156 +++++++++++++++++++------------------- 5 files changed, 149 insertions(+), 83 deletions(-) diff --git a/README.chromium b/README.chromium index 18addc7a9..02405e289 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 493 +Version: 494 License: BSD License File: LICENSE diff --git a/include/libyuv/version.h b/include/libyuv/version.h index a3489676c..8a877dcf0 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,6 +11,6 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 493 +#define LIBYUV_VERSION 494 #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT diff --git a/source/scale_argb.cc b/source/scale_argb.cc index 06ec3e20d..ccbb1c467 100644 --- a/source/scale_argb.cc +++ b/source/scale_argb.cc @@ -36,6 +36,14 @@ void ScaleARGBRowDownEven_NEON(const uint8* src_argb, int src_stride, void ScaleARGBRowDownEvenInt_NEON(const uint8* src_argb, int src_stride, int src_stepx, uint8* dst_argb, int dst_width); + + +#define HAS_SCALEARGBROWDOWN2_NEON +void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t /* src_stride */, + uint8* dst, int dst_width); +void ScaleARGBRowDown2Int_NEON(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); + #endif /** @@ -876,13 +884,18 @@ static void ScaleARGBDown2(int /* src_width */, int /* src_height */, uint8* dst_argb, int dst_width) = filtering ? ScaleARGBRowDown2Int_C : ScaleARGBRowDown2_C; #if defined(HAS_SCALEARGBROWDOWN2_SSE2) - if (TestCpuFlag(kCpuHasSSE2) && - IS_ALIGNED(dst_width, 4) && + if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 4) && IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { ScaleARGBRowDown2 = filtering ? ScaleARGBRowDown2Int_SSE2 : ScaleARGBRowDown2_SSE2; } +#elif defined(HAS_SCALEARGBROWDOWN2_NEON) + if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 8) && + IS_ALIGNED(src_argb, 4) && IS_ALIGNED(src_stride, 4)) { + ScaleARGBRowDown2 = filtering ? ScaleARGBRowDown2Int_NEON : + ScaleARGBRowDown2_NEON; + } #endif // TODO(fbarchard): Loop through source height to allow odd height. diff --git a/source/scale_argb_neon.cc b/source/scale_argb_neon.cc index 255ca80d6..edb2df3cf 100644 --- a/source/scale_argb_neon.cc +++ b/source/scale_argb_neon.cc @@ -18,6 +18,61 @@ extern "C" { // This module is for GCC Neon #if !defined(YUV_DISABLE_ASM) && defined(__ARM_NEON__) + + +void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t /* src_stride */, + uint8* dst, int dst_width) { + asm volatile ( + "1: \n" + // load even pixels into q0, odd into q1 + "vld2.u32 {q0, q1}, [%0]! \n" + "vld2.u32 {q2, q3}, [%0]! \n" + "subs %2, %2, #8 \n" // 8 processed per loop + "vst1.u8 {q0}, [%1]! \n" // store even pixels + "vst1.u8 {q2}, [%1]! \n" + "bgt 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst), // %1 + "+r"(dst_width) // %2 + : + : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List + ); +} + +void ScaleARGBRowDown2Int_NEON(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width) { + asm volatile ( + // change the stride to row 2 pointer + "add %1, %0 \n" + "1: \n" + "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. + "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels. + "subs %3, %3, #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. + "vld4.8 {d16, d18, d20, d22}, [%1]! \n" // load 8 more ARGB pixels. + "vld4.8 {d17, d19, d21, d23}, [%1]! \n" // load last 8 ARGB pixels. + "vpadal.u8 q0, q8 \n" // B 16 bytes -> 8 shorts. + "vpadal.u8 q1, q9 \n" // G 16 bytes -> 8 shorts. + "vpadal.u8 q2, q10 \n" // R 16 bytes -> 8 shorts. + "vpadal.u8 q3, q11 \n" // A 16 bytes -> 8 shorts. + "vrshrn.u16 d0, q0, #2 \n" // downshift, round and pack + "vrshrn.u16 d1, q1, #2 \n" + "vrshrn.u16 d2, q2, #2 \n" + "vrshrn.u16 d3, q3, #2 \n" + "vst4.u8 {d0, d1, d2, d3}, [%2]! \n" + "bgt 1b \n" + : "+r"(src_ptr), // %0 + "+r"(src_stride), // %1 + "+r"(dst), // %2 + "+r"(dst_width) // %3 + : + : "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11" + ); +} + // Reads 4 pixels at a time. // Alignment requirement: src_argb 4 byte aligned. void ScaleARGBRowDownEven_NEON(const uint8* src_argb, ptrdiff_t, diff --git a/source/scale_neon.cc b/source/scale_neon.cc index f521c63d8..961e362fc 100644 --- a/source/scale_neon.cc +++ b/source/scale_neon.cc @@ -32,14 +32,14 @@ void ScaleRowDown2_NEON(const uint8* src_ptr, ptrdiff_t /* src_stride */, "1: \n" // load even pixels into q0, odd into q1 "vld2.u8 {q0,q1}, [%0]! \n" - "vst1.u8 {q0}, [%1]! \n" // store even pixels "subs %2, %2, #16 \n" // 16 processed per loop + "vst1.u8 {q0}, [%1]! \n" // store even pixels "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst), // %1 - "+r"(dst_width) // %2 - : - : "q0", "q1" // Clobber List + : "+r"(src_ptr), // %0 + "+r"(dst), // %1 + "+r"(dst_width) // %2 + : + : "q0", "q1" // Clobber List ); } @@ -51,6 +51,7 @@ void ScaleRowDown2Int_NEON(const uint8* src_ptr, ptrdiff_t src_stride, "1: \n" "vld1.u8 {q0,q1}, [%0]! \n" // load row 1 and post inc "vld1.u8 {q2,q3}, [%1]! \n" // load row 2 and post inc + "subs %3, %3, #16 \n" // 16 processed per loop "vpaddl.u8 q0, q0 \n" // row 1 add adjacent "vpaddl.u8 q1, q1 \n" "vpadal.u8 q0, q2 \n" // row 2 add adjacent + row1 @@ -58,15 +59,14 @@ void ScaleRowDown2Int_NEON(const uint8* src_ptr, ptrdiff_t src_stride, "vrshrn.u16 d0, q0, #2 \n" // downshift, round and pack "vrshrn.u16 d1, q1, #2 \n" "vst1.u8 {q0}, [%2]! \n" - "subs %3, %3, #16 \n" // 16 processed per loop "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(src_stride), // %1 - "+r"(dst), // %2 - "+r"(dst_width) // %3 - : - : "q0", "q1", "q2", "q3" // Clobber List - ); + : "+r"(src_ptr), // %0 + "+r"(src_stride), // %1 + "+r"(dst), // %2 + "+r"(dst_width) // %3 + : + : "q0", "q1", "q2", "q3" // Clobber List + ); } void ScaleRowDown4_NEON(const uint8* src_ptr, ptrdiff_t /* src_stride */, @@ -74,16 +74,16 @@ void ScaleRowDown4_NEON(const uint8* src_ptr, ptrdiff_t /* src_stride */, asm volatile ( "1: \n" "vld2.u8 {d0, d1}, [%0]! \n" + "subs %2, #4 \n" "vtrn.u8 d1, d0 \n" "vshrn.u16 d0, q0, #8 \n" "vst1.u32 {d0[1]}, [%1]! \n" - "subs %2, #4 \n" "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst_ptr), // %1 - "+r"(dst_width) // %2 - : - : "q0", "q1", "memory", "cc" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : + : "q0", "q1", "memory", "cc" ); } @@ -98,6 +98,7 @@ void ScaleRowDown4Int_NEON(const uint8* src_ptr, ptrdiff_t src_stride, "vld1.u8 {q1}, [r4]! \n" "vld1.u8 {q2}, [r5]! \n" "vld1.u8 {q3}, [%3]! \n" + "subs %2, #4 \n" "vpaddl.u8 q0, q0 \n" "vpadal.u8 q0, q1 \n" "vpadal.u8 q0, q2 \n" @@ -106,13 +107,12 @@ void ScaleRowDown4Int_NEON(const uint8* src_ptr, ptrdiff_t src_stride, "vrshrn.u32 d0, q0, #4 \n" // divide by 16 w/rounding "vmovn.u16 d0, q0 \n" "vst1.u32 {d0[0]}, [%1]! \n" - "subs %2, #4 \n" "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst_ptr), // %1 - "+r"(dst_width) // %2 - : "r"(src_stride) // %3 - : "r4", "r5", "q0", "q1", "q2", "q3", "memory", "cc" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"(src_stride) // %3 + : "r4", "r5", "q0", "q1", "q2", "q3", "memory", "cc" ); } @@ -125,15 +125,15 @@ void ScaleRowDown34_NEON(const uint8* src_ptr, asm volatile ( "1: \n" "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 + "subs %2, #24 \n" "vmov d2, d3 \n" // order d0, d1, d2 "vst3.u8 {d0, d1, d2}, [%1]! \n" - "subs %2, #24 \n" "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst_ptr), // %1 - "+r"(dst_width) // %2 - : - : "d0", "d1", "d2", "d3", "memory", "cc" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : + : "d0", "d1", "d2", "d3", "memory", "cc" ); } @@ -146,6 +146,7 @@ void ScaleRowDown34_0_Int_NEON(const uint8* src_ptr, "1: \n" "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 "vld4.u8 {d4, d5, d6, d7}, [%3]! \n" // src line 1 + "subs %2, #24 \n" // filter src line 0 with src line 1 // expand chars to shorts to allow for room @@ -182,14 +183,13 @@ void ScaleRowDown34_0_Int_NEON(const uint8* src_ptr, "vst3.u8 {d0, d1, d2}, [%1]! \n" - "subs %2, #24 \n" "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst_ptr), // %1 - "+r"(dst_width), // %2 - "+r"(src_stride) // %3 - : - : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "d24", "memory", "cc" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(src_stride) // %3 + : + : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "d24", "memory", "cc" ); } @@ -202,7 +202,7 @@ void ScaleRowDown34_1_Int_NEON(const uint8* src_ptr, "1: \n" "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 "vld4.u8 {d4, d5, d6, d7}, [%3]! \n" // src line 1 - + "subs %2, #24 \n" // average src line 0 with src line 1 "vrhadd.u8 q0, q0, q2 \n" "vrhadd.u8 q1, q1, q3 \n" @@ -221,15 +221,13 @@ void ScaleRowDown34_1_Int_NEON(const uint8* src_ptr, "vqrshrn.u16 d2, q3, #2 \n" "vst3.u8 {d0, d1, d2}, [%1]! \n" - - "subs %2, #24 \n" "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst_ptr), // %1 - "+r"(dst_width), // %2 - "+r"(src_stride) // %3 - : - : "r4", "q0", "q1", "q2", "q3", "d24", "memory", "cc" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(src_stride) // %3 + : + : "r4", "q0", "q1", "q2", "q3", "d24", "memory", "cc" ); } @@ -253,17 +251,17 @@ void ScaleRowDown38_NEON(const uint8* src_ptr, "vld1.u8 {q3}, [%3] \n" "1: \n" "vld1.u8 {d0, d1, d2, d3}, [%0]! \n" + "subs %2, #12 \n" "vtbl.u8 d4, {d0, d1, d2, d3}, d6 \n" "vtbl.u8 d5, {d0, d1, d2, d3}, d7 \n" "vst1.u8 {d4}, [%1]! \n" "vst1.u32 {d5[0]}, [%1]! \n" - "subs %2, #12 \n" "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst_ptr), // %1 - "+r"(dst_width) // %2 - : "r"(&kShuf38) // %3 - : "d0", "d1", "d2", "d3", "d4", "d5", "memory", "cc" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"(&kShuf38) // %3 + : "d0", "d1", "d2", "d3", "d4", "d5", "memory", "cc" ); } @@ -286,6 +284,7 @@ void OMITFP ScaleRowDown38_3_Int_NEON(const uint8* src_ptr, "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" "vld4.u8 {d4, d5, d6, d7}, [%3]! \n" "vld4.u8 {d16, d17, d18, d19}, [r4]! \n" + "subs %2, #12 \n" // Shuffle the input data around to get align the data // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7 @@ -363,17 +362,16 @@ void OMITFP ScaleRowDown38_3_Int_NEON(const uint8* src_ptr, "vst1.u8 {d3}, [%1]! \n" "vst1.u32 {d4[0]}, [%1]! \n" - "subs %2, #12 \n" "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst_ptr), // %1 - "+r"(dst_width), // %2 - "+r"(src_stride) // %3 - : "r"(&kMult38_Div6), // %4 - "r"(&kShuf38_2), // %5 - "r"(&kMult38_Div9) // %6 - : "r4", "q0", "q1", "q2", "q3", "q8", "q9", - "q13", "q14", "q15", "memory", "cc" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(src_stride) // %3 + : "r"(&kMult38_Div6), // %4 + "r"(&kShuf38_2), // %5 + "r"(&kMult38_Div9) // %6 + : "r4", "q0", "q1", "q2", "q3", "q8", "q9", + "q13", "q14", "q15", "memory", "cc" ); } @@ -393,6 +391,7 @@ void ScaleRowDown38_2_Int_NEON(const uint8* src_ptr, // d3 = 30 70 31 71 32 72 33 73 "vld4.u8 {d0, d1, d2, d3}, [%0]! \n" "vld4.u8 {d4, d5, d6, d7}, [%3]! \n" + "subs %2, #12 \n" // Shuffle the input data around to get align the data // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7 @@ -459,15 +458,14 @@ void ScaleRowDown38_2_Int_NEON(const uint8* src_ptr, "vst1.u8 {d3}, [%1]! \n" "vst1.u32 {d4[0]}, [%1]! \n" - "subs %2, #12 \n" "bgt 1b \n" - : "+r"(src_ptr), // %0 - "+r"(dst_ptr), // %1 - "+r"(dst_width), // %2 - "+r"(src_stride) // %3 - : "r"(&kMult38_Div6), // %4 - "r"(&kShuf38_2) // %5 - : "q0", "q1", "q2", "q3", "q13", "q14", "memory", "cc" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(src_stride) // %3 + : "r"(&kMult38_Div6), // %4 + "r"(&kShuf38_2) // %5 + : "q0", "q1", "q2", "q3", "q13", "q14", "memory", "cc" ); } @@ -545,13 +543,13 @@ void ScaleFilterRows_NEON(uint8* dst_ptr, "99: \n" "vst1.u8 {d1[7]}, [%0] \n" - : "+r"(dst_ptr), // %0 - "+r"(src_ptr), // %1 - "+r"(src_stride), // %2 - "+r"(dst_width), // %3 - "+r"(source_y_fraction) // %4 - : - : "q0", "q1", "d4", "d5", "q13", "q14", "memory", "cc" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(src_stride), // %2 + "+r"(dst_width), // %3 + "+r"(source_y_fraction) // %4 + : + : "q0", "q1", "d4", "d5", "q13", "q14", "memory", "cc" ); }