[libyuv] Add NEON implementations for all remaining C row functions

Implement 32-bit and 64-bit Arm NEON versions (in row_neon.cc and
row_neon64.cc) for the 12 remaining row functions that previously fell
back to C on Arm:
- AR30ToAB30Row_NEON (and AR30ToAB30Row_Any_NEON)
- AR30ToABGRRow_NEON (and AR30ToABGRRow_Any_NEON)
- AR30ToARGBRow_NEON (and AR30ToARGBRow_Any_NEON)
- ARGBAffineRow_NEON
- ARGBColorTableRow_NEON
- ARGBCopyAlphaRow_NEON (and ARGBCopyAlphaRow_Any_NEON)
- ARGBLumaColorTableRow_NEON
- ARGBPolynomialRow_NEON (and ARGBPolynomialRow_Any_NEON)
- ARGBUnattenuateRow_NEON (and ARGBUnattenuateRow_Any_NEON)
- CopyRow_16_NEON (and CopyRow_16_Any_NEON)
- MirrorRow_16_NEON (and MirrorRow_16_Any_NEON)
- RGBColorTableRow_NEON

Add HAS_*_NEON macros, prototypes, _Any wrappers, NEON dispatches in
convert.cc, convert_argb.cc, and planar_functions.cc, and enable unit
tests in planar_test.cc. Arm row function SIMD coverage is now 164/164
(100%).

ARM64 (Apple M6) Benchmark (1280 width, 10000 iterations):
----------------------------------------------------------------
Function                 Before C (ms) After NEON (ms)  Improvement
----------------------------------------------------------------
AR30ToAB30Row                    1.20           0.70        1.72x
AR30ToABGRRow                    1.88           1.03        1.83x
AR30ToARGBRow                    1.88           0.87        2.17x
ARGBAffineRow                    7.96           2.31        3.44x
ARGBColorTableRow                8.17           7.43        1.10x
ARGBCopyAlphaRow                 1.37           0.53        2.58x
ARGBLumaColorTableRow            8.18           5.24        1.56x
ARGBPolynomialRow                8.73           7.55        1.16x
ARGBUnattenuateRow               6.00           2.05        2.93x
CopyRow_16                       0.18           0.18        1.00x
MirrorRow_16                     0.34           0.20        1.73x
RGBColorTableRow                 6.15           5.58        1.10x
----------------------------------------------------------------

Maximum SIMD ISA supported per C row function:
----------------------------------------------------------------
C Row Function              arm32   arm64    x86        riscv
----------------------------------------------------------------
AB64ToARGBRow_C             NEON    NEON     AVX2       RVV
ABGRToAR30Row_C             -       NEON     AVX512BW   -
AR30ToAB30Row_C             NEON    NEON     AVX512BW   -
AR30ToABGRRow_C             NEON    NEON     AVX512BW   -
AR30ToARGBRow_C             NEON    NEON     AVX512BW   -
AR64ShuffleRow_C            NEON    NEON     AVX512BW   RVV
AR64ToAB64Row_C             NEON    NEON     AVX512BW   RVV
AR64ToARGBRow_C             NEON    NEON     AVX2       RVV
ARGB1555ToARGBRow_C         NEON    SVE2     AVX2       -
ARGB1555ToUVMatrixRow_C     NEON    NEON     AVX2       -
ARGB1555ToUVRow_C           NEON    NEON     -          -
ARGB1555ToYMatrixRow_C      NEON    NEON     AVX2       -
ARGB1555ToYRow_C            NEON    NEON     -          -
ARGB4444ToARGBRow_C         NEON    NEON     AVX2       -
ARGB4444ToUVMatrixRow_C     NEON    NEON     AVX2       -
ARGB4444ToUVRow_C           NEON    NEON     -          -
ARGB4444ToYMatrixRow_C      NEON    NEON     AVX2       -
ARGB4444ToYRow_C            NEON    NEON     -          -
ARGBAddRow_C                NEON    NEON     AVX2       -
ARGBAffineRow_C             NEON    NEON     SSE2       -
ARGBAlphaBlendRow_C         NEON    SME      AVX512BW   RVV
ARGBAttenuateRow_C          NEON    NEON     AVX512BW   RVV
ARGBBlendRow_C              NEON    NEON     AVX512BW   RVV
ARGBColorMatrixRow_C        NEON    I8MM     SSSE3      -
ARGBColorTableRow_C         NEON    NEON     X86        -
ARGBCopyAlphaRow_C          NEON    NEON     AVX2       -
ARGBCopyYToAlphaRow_C       NEON    NEON     AVX512BW   RVV
ARGBExtractAlphaRow_C       NEON    NEON     AVX512BW   RVV
ARGBGrayRow_C               NEON    DOTPROD  AVX512VNNI -
ARGBLumaColorTableRow_C     NEON    NEON     SSSE3      -
ARGBMirrorRow_C             NEON    NEON     AVX512BW   RVV
ARGBMultiplyRow_C           NEON    SME      AVX512BW   RVV
ARGBOrRow_C                 NEON    SME      AVX512BW   RVV
ARGBPolynomialRow_C         NEON    NEON     AVX2       -
ARGBQuantizeRow_C           NEON    NEON     SSE2       -
ARGBSepiaRow_C              NEON    DOTPROD  SSSE3      -
ARGBSetRow_C                NEON    NEON     X86        RVV
ARGBShadeRow_C              NEON    NEON     SSE2       -
ARGBShuffleRow_C            NEON    NEON     AVX512BW   RVV
ARGBSubtractRow_C           NEON    NEON     AVX2       -
ARGBToAB64Row_C             NEON    NEON     AVX2       RVV
ARGBToABGRRow_C             NEON    NEON     AVX512BW   RVV
ARGBToAR30Row_C             -       NEON     AVX512BW   -
ARGBToAR64Row_C             NEON    NEON     AVX2       RVV
ARGBToARGB1555Row_C         NEON    NEON     AVX2       -
ARGBToARGB4444Row_C         NEON    NEON     AVX2       -
ARGBToBGRARow_C             NEON    NEON     AVX512BW   RVV
ARGBToRAWRow_C              NEON    SVE2     AVX512BW   RVV
ARGBToRGB24Row_C            NEON    SVE2     AVX512BW   RVV
ARGBToRGB565DitherRow_C     NEON    SVE2     AVX2       -
ARGBToRGB565Row_C           NEON    SVE2     AVX2       -
ARGBToRGBARow_C             NEON    NEON     AVX512BW   RVV
ARGBToUV444MatrixRow_C      NEON    I8MM     AVX512VNNI RVV
ARGBToUVMatrixRow_C         NEON    SME      AVX512VNNI RVV
ARGBToYMatrixRow_C          NEON    SME      AVX512VNNI RVV
ARGBUnattenuateRow_C        NEON    NEON     AVX2       -
AYUVToUVRow_C               NEON    SVE2     AVX512VBMI -
AYUVToVURow_C               NEON    SVE2     AVX512VBMI -
AYUVToYRow_C                NEON    NEON     AVX512VBMI -
BlendPlaneRow_C             NEON    NEON     AVX512BW   RVV
ByteToFloatRow_C            NEON    NEON     -          -
ComputeCumulativeSumRow_C   -       NEON     AVX2       -
Convert16To8Row_C           NEON    SME      AVX512BW   RVV
Convert8To16Row_C           NEON    SME      AVX512BW   RVV
Convert8To8Row_C            NEON    SME      AVX2       -
CopyRow_C                   NEON    SME      AVX512BW   RVV
CopyRow_16_C                NEON    NEON     -          -
CumulativeSumToAverageRow_C -       NEON     AVX2       -
DetileRow_C                 NEON    NEON     SSE2       -
DetileRow_16_C              NEON    NEON     AVX        -
DetileSplitUVRow_C          NEON    NEON     SSSE3      -
DivideRow_16_C              NEON    SVE2     AVX2       -
GaussRow_C                  NEON    NEON     -          -
GaussRow_F32_C              -       NEON     -          -
HalfFloatRow_C              NEON    SVE2     AVX2       -
HalfMergeUVRow_C            NEON    SVE2     AVX512BW   -
HalfRow_16To8_C             NEON    SME      AVX512BW   RVV
HalfWidthRow_16To8_C        NEON    SME      AVX512BW   RVV
I210AlphaToARGBRow_C        -       SME      AVX2       -
I210ToAR30Row_C             -       SME      AVX2       -
I210ToARGBRow_C             -       SME      AVX2       -
I212ToAR30Row_C             -       SME      AVX2       -
I212ToARGBRow_C             -       SME      AVX2       -
I400ToARGBRow_C             NEON    SME      AVX512BW   RVV
I410AlphaToARGBRow_C        -       SME      AVX2       -
I410ToAR30Row_C             -       SME      AVX2       -
I410ToARGBRow_C             -       SME      AVX2       -
I422AlphaToARGBRow_C        NEON    SME      AVX512BW   RVV
I422ToAR30Row_C             -       SME      AVX512BW   RVV
I422ToARGB1555Row_C         NEON    SME      AVX2       -
I422ToARGB4444Row_C         NEON    SME      AVX2       -
I422ToARGBRow_C             NEON    SME      AVX512BW   RVV
I422ToRGB24Row_C            NEON    SME      AVX512VBMI RVV
I422ToRGB565Row_C           NEON    SME      AVX2       -
I422ToRGBARow_C             NEON    SME      AVX2       RVV
I422ToUYVYRow_C             NEON    NEON     AVX2       -
I422ToYUY2Row_C             NEON    NEON     AVX2       -
I444AlphaToARGBRow_C        NEON    SME      AVX2       RVV
I444ToARGBRow_C             NEON    SME      AVX2       RVV
I444ToRGB24Row_C            NEON    SME      AVX2       RVV
InterpolateRow_C            NEON    SME      AVX512BW   RVV
InterpolateRow_16_C         NEON    SME      AVX512BW   -
J400ToARGBRow_C             NEON    NEON     AVX512BW   RVV
MergeAR64Row_C              NEON    NEON     AVX2       -
MergeARGB16To8Row_C         NEON    NEON     AVX2       -
MergeARGBRow_C              NEON    NEON     AVX2       RVV
MergeRGBRow_C               NEON    NEON     AVX512VBMI RVV
MergeUVRow_C                NEON    SME      AVX512BW   RVV
MergeUVRow_16_C             NEON    SME      AVX2       -
MergeXR30Row_C              NEON    NEON     AVX512BW   -
MergeXR64Row_C              NEON    NEON     AVX2       -
MergeXRGB16To8Row_C         NEON    NEON     AVX2       -
MergeXRGBRow_C              NEON    NEON     AVX2       RVV
MirrorRow_C                 NEON    NEON     AVX512BW   -
MirrorRow_16_C              NEON    NEON     AVX512BW   -
MirrorSplitUVRow_C          NEON    NEON     AVX512BW   -
MirrorUVRow_C               NEON    NEON     AVX512BW   RVV
MultiplyRow_16_C            NEON    SME      AVX512BW   RVV
NV12ToARGBRow_C             NEON    SME      AVX512BW   RVV
NV12ToRGB24Row_C            NEON    SME      AVX512VBMI RVV
NV12ToRGB565Row_C           NEON    NEON     AVX2       -
NV21ToARGBRow_C             NEON    SME      AVX512BW   RVV
NV21ToRGB24Row_C            NEON    SME      AVX512VBMI RVV
NV21ToYUV24Row_C            NEON    NEON     AVX2       -
P210ToAR30Row_C             -       SME      AVX2       -
P210ToARGBRow_C             -       SME      AVX2       -
P410ToAR30Row_C             -       SME      AVX2       -
P410ToARGBRow_C             -       SME      AVX2       -
RAWToARGBRow_C              NEON    SVE2     AVX512BW   RVV
RAWToRGB24Row_C             NEON    SVE2     AVX512VBMI RVV
RAWToRGBARow_C              NEON    SVE2     AVX512VBMI RVV
RGB24MirrorRow_C            NEON    NEON     AVX512VBMI -
RGB24ToARGBRow_C            NEON    SVE2     AVX512BW   RVV
RGB565ToARGBRow_C           NEON    NEON     AVX2       -
RGB565ToUVMatrixRow_C       NEON    NEON     AVX2       -
RGB565ToUVRow_C             NEON    NEON     -          -
RGB565ToYMatrixRow_C        NEON    NEON     AVX2       -
RGB565ToYRow_C              NEON    NEON     -          -
RGBAToARGBRow_C             NEON    NEON     AVX512BW   RVV
RGBColorTableRow_C          NEON    NEON     X86        -
RGBToUV444MatrixRow_C       NEON    NEON     AVX512BW   RVV
RGBToUVMatrixRow_C          NEON    NEON     AVX512BW   RVV
RGBToYMatrixRow_C           NEON    DOTPROD  AVX512BW   RVV
SetRow_C                    NEON    NEON     ERMS       -
SobelRow_C                  NEON    NEON     SSE2       -
SobelToPlaneRow_C           NEON    NEON     SSE2       -
SobelXRow_C                 NEON    NEON     SSE2       -
SobelXYRow_C                NEON    NEON     SSE2       -
SobelYRow_C                 NEON    NEON     SSE2       -
SplitARGBRow_C              NEON    NEON     AVX2       RVV
SplitRGBRow_C               NEON    NEON     AVX2       RVV
SplitUVRow_C                NEON    SVE2     AVX512BW   RVV
SplitUVRow_16_C             NEON    NEON     AVX2       -
SplitXRGBRow_C              NEON    NEON     AVX2       RVV
SwapUVRow_C                 NEON    NEON     AVX512BW   RVV
UYVYToARGBRow_C             NEON    SME      AVX2       -
UYVYToUV422Row_C            NEON    NEON     AVX2       -
UYVYToUVRow_C               NEON    SVE2     AVX2       -
UYVYToYRow_C                NEON    SVE2     AVX2       -
YUY2ToARGBRow_C             NEON    SME      AVX2       -
YUY2ToNVUVRow_C             NEON    NEON     AVX2       -
YUY2ToUV422Row_C            NEON    NEON     AVX2       -
YUY2ToUVRow_C               NEON    SVE2     AVX2       -
YUY2ToYRow_C                NEON    SVE2     AVX2       -
----------------------------------------------------------------
SIMD (164/164 100%)         146 89% 164 100% 154 94%    64 39%
----------------------------------------------------------------

Test: libyuv_unittest --gtest_filter=*AR30*:*Affine*:*ColorTable*:*CopyAlpha*:*Polynomial*:*Unattenuate*:*MirrorPlane_16*
Bug: None
Change-Id: Ib8b68beb77b47de6b996d41fd080397c61539ffb
This commit is contained in:
Frank Barchard 2026-10-27 15:52:22 -07:00
parent f506767c5f
commit bad52cccd6
10 changed files with 1244 additions and 27 deletions

View File

@ -1,6 +1,6 @@
Name: libyuv
URL: https://chromium.googlesource.com/libyuv/libyuv/
Version: 1975
Version: 1976
Revision: DEPS
License: BSD-3-Clause
License File: LICENSE

View File

@ -540,6 +540,9 @@ extern "C" {
#if !defined(LIBYUV_DISABLE_NEON) && \
(defined(__aarch64__) || defined(__ARM_NEON__) || defined(LIBYUV_NEON))
#define HAS_AB64TOARGBROW_NEON
#define HAS_AR30TOAB30ROW_NEON
#define HAS_AR30TOABGRROW_NEON
#define HAS_AR30TOARGBROW_NEON
#define HAS_AR64TOARGBROW_NEON
#define HAS_ARGB1555TOARGBROW_NEON
#define HAS_ARGB1555TOUVROW_NEON
@ -547,6 +550,7 @@ extern "C" {
#define HAS_ARGB4444TOARGBROW_NEON
#define HAS_ARGB4444TOUVROW_NEON
#define HAS_ARGB4444TOYROW_NEON
#define HAS_ARGBCOPYALPHAROW_NEON
#define HAS_ARGBCOPYYTOALPHAROW_NEON
#define HAS_ARGBEXTRACTALPHAROW_NEON
#define HAS_ARGBSETROW_NEON
@ -578,6 +582,7 @@ extern "C" {
#define HAS_CONVERT16TO8ROW_NEON
#define HAS_CONVERT8TO16ROW_NEON
#define HAS_CONVERT8TO8ROW_NEON
#define HAS_COPYROW_16_NEON
#define HAS_COPYROW_NEON
#define HAS_DETILEROW_16_NEON
#define HAS_DETILEROW_NEON
@ -614,6 +619,7 @@ extern "C" {
#define HAS_MERGEXR64ROW_NEON
#define HAS_MERGEXRGB16TO8ROW_NEON
#define HAS_MERGEXRGBROW_NEON
#define HAS_MIRRORROW_16_NEON
#define HAS_MIRRORROW_NEON
#define HAS_MIRRORSPLITUVROW_NEON
#define HAS_MIRRORUVROW_NEON
@ -652,21 +658,27 @@ extern "C" {
// Effects:
#define HAS_ARGBADDROW_NEON
#define HAS_ARGBAFFINEROW_NEON
#define HAS_ARGBALPHABLENDROW_NEON
#define HAS_ARGBATTENUATEROW_NEON
#define HAS_ARGBBLENDROW_NEON
#define HAS_BLENDPLANEROW_NEON
#define HAS_ARGBCOLORMATRIXROW_NEON
#define HAS_ARGBCOLORTABLEROW_NEON
#define HAS_ARGBGRAYROW_NEON
#define HAS_ARGBLUMACOLORTABLEROW_NEON
#define HAS_ARGBMIRRORROW_NEON
#define HAS_ARGBMULTIPLYROW_NEON
#define HAS_ARGBORROW_NEON
#define HAS_ARGBPOLYNOMIALROW_NEON
#define HAS_ARGBQUANTIZEROW_NEON
#define HAS_ARGBSEPIAROW_NEON
#define HAS_ARGBSHADEROW_NEON
#define HAS_ARGBSHUFFLEROW_NEON
#define HAS_ARGBSUBTRACTROW_NEON
#define HAS_ARGBUNATTENUATEROW_NEON
#define HAS_RGB24MIRRORROW_NEON
#define HAS_RGBCOLORTABLEROW_NEON
#define HAS_SOBELROW_NEON
#define HAS_SOBELTOPLANEROW_NEON
#define HAS_SOBELXROW_NEON
@ -2838,6 +2850,10 @@ void MirrorSplitUVRow_C(const uint8_t* src_uv,
void MirrorRow_16_C(const uint16_t* src, uint16_t* dst, int width);
void MirrorRow_16_AVX512BW(const uint16_t* src, uint16_t* dst, int width);
void MirrorRow_16_NEON(const uint16_t* src, uint16_t* dst, int width);
void MirrorRow_16_Any_NEON(const uint16_t* src_ptr,
uint16_t* dst_ptr,
int width);
void ARGBMirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width);
void ARGBMirrorRow_AVX512BW(const uint8_t* src, uint8_t* dst, int width);
@ -4014,16 +4030,22 @@ void CopyRow_Any_LSX(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
void CopyRow_Any_LASX(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
void CopyRow_16_C(const uint16_t* src, uint16_t* dst, int count);
void CopyRow_16_NEON(const uint16_t* src, uint16_t* dst, int count);
void CopyRow_16_Any_NEON(const uint16_t* src_ptr, uint16_t* dst_ptr, int width);
void ARGBCopyAlphaRow_C(const uint8_t* src, uint8_t* dst, int width);
void ARGBCopyAlphaRow_SSE2(const uint8_t* src, uint8_t* dst, int width);
void ARGBCopyAlphaRow_AVX2(const uint8_t* src, uint8_t* dst, int width);
void ARGBCopyAlphaRow_NEON(const uint8_t* src, uint8_t* dst, int width);
void ARGBCopyAlphaRow_Any_SSE2(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void ARGBCopyAlphaRow_Any_AVX2(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void ARGBCopyAlphaRow_Any_NEON(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void ARGBExtractAlphaRow_C(const uint8_t* src_argb, uint8_t* dst_a, int width);
void ARGBExtractAlphaRow_SSE2(const uint8_t* src_argb,
@ -4279,6 +4301,18 @@ void AR30ToAB30Row_C(const uint8_t* src_ar30, uint8_t* dst_ab30, int width);
void AR30ToAB30Row_AVX512BW(const uint8_t* src_ar30,
uint8_t* dst_ab30,
int width);
void AR30ToARGBRow_NEON(const uint8_t* src_ar30, uint8_t* dst_argb, int width);
void AR30ToABGRRow_NEON(const uint8_t* src_ar30, uint8_t* dst_abgr, int width);
void AR30ToAB30Row_NEON(const uint8_t* src_ar30, uint8_t* dst_ab30, int width);
void AR30ToARGBRow_Any_NEON(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void AR30ToABGRRow_Any_NEON(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void AR30ToAB30Row_Any_NEON(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void RGB24ToARGBRow_Any_SSSE3(const uint8_t* src_ptr,
uint8_t* dst_ptr,
@ -6928,12 +6962,18 @@ void ARGBUnattenuateRow_SSE2(const uint8_t* src_argb,
void ARGBUnattenuateRow_AVX2(const uint8_t* src_argb,
uint8_t* dst_argb,
int width);
void ARGBUnattenuateRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
int width);
void ARGBUnattenuateRow_Any_SSE2(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void ARGBUnattenuateRow_Any_AVX2(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void ARGBUnattenuateRow_Any_NEON(const uint8_t* src_ptr,
uint8_t* dst_ptr,
int width);
void ARGBGrayRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width);
void ARGBGrayRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_argb, int width);
@ -6988,6 +7028,9 @@ void ARGBColorTableRow_C(uint8_t* dst_argb,
void ARGBColorTableRow_X86(uint8_t* dst_argb,
const uint8_t* table_argb,
int width);
void ARGBColorTableRow_NEON(uint8_t* dst_argb,
const uint8_t* table_argb,
int width);
void RGBColorTableRow_C(uint8_t* dst_argb,
const uint8_t* table_argb,
@ -6995,6 +7038,9 @@ void RGBColorTableRow_C(uint8_t* dst_argb,
void RGBColorTableRow_X86(uint8_t* dst_argb,
const uint8_t* table_argb,
int width);
void RGBColorTableRow_NEON(uint8_t* dst_argb,
const uint8_t* table_argb,
int width);
void ARGBQuantizeRow_C(uint8_t* dst_argb,
int scale,
@ -7098,6 +7144,12 @@ void ARGBAffineRow_SSE2(const uint8_t* src_argb,
uint8_t* dst_argb,
const float* src_dudv,
int width);
LIBYUV_API
void ARGBAffineRow_NEON(const uint8_t* src_argb,
int src_argb_stride,
uint8_t* dst_argb,
const float* src_dudv,
int width);
// Used for I420Scale, ARGBScale, and ARGBInterpolate.
void InterpolateRow_C(uint8_t* dst_ptr,
@ -7351,6 +7403,14 @@ void ARGBPolynomialRow_AVX2(const uint8_t* src_argb,
uint8_t* dst_argb,
const float* poly,
int width);
void ARGBPolynomialRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
const float* poly,
int width);
void ARGBPolynomialRow_Any_NEON(const uint8_t* src_ptr,
uint8_t* dst_ptr,
const float* param,
int width);
// Scale and convert to half float.
void HalfFloatRow_C(const uint16_t* src, uint16_t* dst, float scale, int width);
@ -7442,6 +7502,11 @@ void ARGBLumaColorTableRow_SSSE3(const uint8_t* src_argb,
int width,
const uint8_t* luma,
uint32_t lumacoeff);
void ARGBLumaColorTableRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
int width,
const uint8_t* luma,
uint32_t lumacoeff);
float ScaleMaxSamples_C(const float* src, float* dst, float scale, int width);
float ScaleMaxSamples_NEON(const float* src,

View File

@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 1975
#define LIBYUV_VERSION 1976
#endif // INCLUDE_LIBYUV_VERSION_H_

View File

@ -3538,6 +3538,14 @@ static int AR30ToI420Matrix(const uint8_t* src_ar30,
src_ar30 = src_ar30 + (ptrdiff_t)(height - 1) * src_stride_ar30;
src_stride_ar30 = -src_stride_ar30;
}
#if defined(HAS_AR30TOARGBROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
AR30ToARGBRow = AR30ToARGBRow_Any_NEON;
if (IS_ALIGNED(width, 8)) {
AR30ToARGBRow = AR30ToARGBRow_NEON;
}
}
#endif
#if defined(HAS_AR30TOARGBROW_AVX512BW)
if (TestCpuFlag(kCpuHasAVX512BW)) {
AR30ToARGBRow = AR30ToARGBRow_AVX512BW;

View File

@ -4522,6 +4522,14 @@ int AR30ToARGB(const uint8_t* src_ar30,
}
void (*AR30ToARGBRow)(const uint8_t* src_ar30, uint8_t* dst_argb, int width) =
AR30ToARGBRow_C;
#if defined(HAS_AR30TOARGBROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
AR30ToARGBRow = AR30ToARGBRow_Any_NEON;
if (IS_ALIGNED(width, 8)) {
AR30ToARGBRow = AR30ToARGBRow_NEON;
}
}
#endif
#if defined(HAS_AR30TOARGBROW_AVX512BW)
if (TestCpuFlag(kCpuHasAVX512BW)) {
AR30ToARGBRow = AR30ToARGBRow_AVX512BW;
@ -4563,6 +4571,14 @@ int AR30ToABGR(const uint8_t* src_ar30,
height = 1;
src_stride_ar30 = dst_stride_abgr = 0;
}
#if defined(HAS_AR30TOABGRROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
AR30ToABGRRow = AR30ToABGRRow_Any_NEON;
if (IS_ALIGNED(width, 8)) {
AR30ToABGRRow = AR30ToABGRRow_NEON;
}
}
#endif
#if defined(HAS_AR30TOABGRROW_AVX512BW)
if (TestCpuFlag(kCpuHasAVX512BW)) {
AR30ToABGRRow = AR30ToABGRRow_AVX512BW;
@ -4604,6 +4620,14 @@ int AR30ToAB30(const uint8_t* src_ar30,
height = 1;
src_stride_ar30 = dst_stride_ab30 = 0;
}
#if defined(HAS_AR30TOAB30ROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
AR30ToAB30Row = AR30ToAB30Row_Any_NEON;
if (IS_ALIGNED(width, 8)) {
AR30ToAB30Row = AR30ToAB30Row_NEON;
}
}
#endif
#if defined(HAS_AR30TOAB30ROW_AVX512BW)
if (TestCpuFlag(kCpuHasAVX512BW)) {
AR30ToAB30Row = AR30ToAB30Row_AVX512BW;

View File

@ -126,8 +126,45 @@ void CopyPlane_16(const uint16_t* src_y,
int dst_stride_y,
int width,
int height) {
CopyPlane((const uint8_t*)src_y, src_stride_y * 2, (uint8_t*)dst_y,
dst_stride_y * 2, width * 2, height);
int y;
void (*CopyRow)(const uint16_t* src, uint16_t* dst, int width) = CopyRow_16_C;
if (width <= 0 || height == 0 || height == INT_MIN) {
return;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
dst_y = dst_y + (ptrdiff_t)(height - 1) * dst_stride_y;
dst_stride_y = -dst_stride_y;
}
// Coalesce rows.
if (src_stride_y == width && dst_stride_y == width &&
(ptrdiff_t)width * height <= INT_MAX) {
width *= height;
height = 1;
src_stride_y = dst_stride_y = 0;
}
// Nothing to do.
if (src_y == dst_y && src_stride_y == dst_stride_y) {
return;
}
#if defined(HAS_COPYROW_16_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
CopyRow = IS_ALIGNED(width, 16) ? CopyRow_16_NEON : CopyRow_16_Any_NEON;
}
#endif
#if defined(HAS_COPYROW_16_HVX)
if (TestCpuFlag(kCpuHasHVX)) {
CopyRow = CopyRow_16_HVX;
}
#endif
// Copy plane
for (y = 0; y < height; ++y) {
CopyRow(src_y, dst_y, width);
src_y += src_stride_y;
dst_y += dst_stride_y;
}
}
// Convert a plane of 16 bit data to 8 bit
@ -2926,14 +2963,11 @@ void MirrorPlane_16(const uint16_t* src_y,
src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
src_stride_y = -src_stride_y;
}
#if defined(HAS_MIRRORUVROW_NEON)
#if defined(HAS_MIRRORROW_16_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
MirrorRow_16 = reinterpret_cast<void (*)(const uint16_t*, uint16_t*, int)>(
MirrorUVRow_Any_NEON);
if (IS_ALIGNED(width, 32)) {
MirrorRow_16 =
reinterpret_cast<void (*)(const uint16_t*, uint16_t*, int)>(
MirrorUVRow_NEON);
MirrorRow_16 = MirrorRow_16_Any_NEON;
if (IS_ALIGNED(width, 16)) {
MirrorRow_16 = MirrorRow_16_NEON;
}
}
#endif
@ -4693,7 +4727,14 @@ int ARGBUnattenuate(const uint8_t* src_argb,
}
}
#endif
// TODO(fbarchard): Neon version.
#if defined(HAS_ARGBUNATTENUATEROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
ARGBUnattenuateRow = ARGBUnattenuateRow_Any_NEON;
if (IS_ALIGNED(width, 4)) {
ARGBUnattenuateRow = ARGBUnattenuateRow_NEON;
}
}
#endif
for (y = 0; y < height; ++y) {
ARGBUnattenuateRow(src_argb, dst_argb, width);
@ -5019,6 +5060,11 @@ int ARGBColorTable(uint8_t* dst_argb,
if (TestCpuFlag(kCpuHasX86)) {
ARGBColorTableRow = ARGBColorTableRow_X86;
}
#endif
#if defined(HAS_ARGBCOLORTABLEROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
ARGBColorTableRow = ARGBColorTableRow_NEON;
}
#endif
for (y = 0; y < height; ++y) {
ARGBColorTableRow(dst, table_argb, width);
@ -5055,6 +5101,11 @@ int RGBColorTable(uint8_t* dst_argb,
if (TestCpuFlag(kCpuHasX86)) {
RGBColorTableRow = RGBColorTableRow_X86;
}
#endif
#if defined(HAS_RGBCOLORTABLEROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
RGBColorTableRow = RGBColorTableRow_NEON;
}
#endif
for (y = 0; y < height; ++y) {
RGBColorTableRow(dst, table_argb, width);
@ -6224,6 +6275,14 @@ int ARGBPolynomial(const uint8_t* src_argb,
ARGBPolynomialRow = ARGBPolynomialRow_AVX2;
}
#endif
#if defined(HAS_ARGBPOLYNOMIALROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
ARGBPolynomialRow = ARGBPolynomialRow_Any_NEON;
if (IS_ALIGNED(width, 2)) {
ARGBPolynomialRow = ARGBPolynomialRow_NEON;
}
}
#endif
for (y = 0; y < height; ++y) {
ARGBPolynomialRow(src_argb, dst_argb, poly, width);
@ -6383,6 +6442,11 @@ int ARGBLumaColorTable(const uint8_t* src_argb,
ARGBLumaColorTableRow = ARGBLumaColorTableRow_SSSE3;
}
#endif
#if defined(HAS_ARGBLUMACOLORTABLEROW_NEON)
if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 4)) {
ARGBLumaColorTableRow = ARGBLumaColorTableRow_NEON;
}
#endif
for (y = 0; y < height; ++y) {
ARGBLumaColorTableRow(src_argb, dst_argb, width, luma, 0x00264b0f);
@ -6420,6 +6484,14 @@ int ARGBCopyAlpha(const uint8_t* src_argb,
height = 1;
src_stride_argb = dst_stride_argb = 0;
}
#if defined(HAS_ARGBCOPYALPHAROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
ARGBCopyAlphaRow = ARGBCopyAlphaRow_Any_NEON;
if (IS_ALIGNED(width, 8)) {
ARGBCopyAlphaRow = ARGBCopyAlphaRow_NEON;
}
}
#endif
#if defined(HAS_ARGBCOPYALPHAROW_SSE2)
if (TestCpuFlag(kCpuHasSSE2)) {
ARGBCopyAlphaRow = ARGBCopyAlphaRow_Any_SSE2;

View File

@ -1105,6 +1105,15 @@ ANY11(ABGRToAR30Row_Any_NEON, ABGRToAR30Row_NEON, 0, 4, 4, 7)
#if defined(HAS_ARGBTOAR30ROW_NEON)
ANY11(ARGBToAR30Row_Any_NEON, ARGBToAR30Row_NEON, 0, 4, 4, 7)
#endif
#if defined(HAS_AR30TOARGBROW_NEON)
ANY11(AR30ToARGBRow_Any_NEON, AR30ToARGBRow_NEON, 0, 4, 4, 7)
#endif
#if defined(HAS_AR30TOABGRROW_NEON)
ANY11(AR30ToABGRRow_Any_NEON, AR30ToABGRRow_NEON, 0, 4, 4, 7)
#endif
#if defined(HAS_AR30TOAB30ROW_NEON)
ANY11(AR30ToAB30Row_Any_NEON, AR30ToAB30Row_NEON, 0, 4, 4, 7)
#endif
#if defined(HAS_ARGBTOAR30ROW_SSSE3)
ANY11(ARGBToAR30Row_Any_SSSE3, ARGBToAR30Row_SSSE3, 0, 4, 4, 3)
#endif
@ -1330,6 +1339,9 @@ ANY11(ARGBUnattenuateRow_Any_AVX2, ARGBUnattenuateRow_AVX2, 0, 4, 4, 7)
#ifdef HAS_ARGBATTENUATEROW_NEON
ANY11(ARGBAttenuateRow_Any_NEON, ARGBAttenuateRow_NEON, 0, 4, 4, 7)
#endif
#ifdef HAS_ARGBUNATTENUATEROW_NEON
ANY11(ARGBUnattenuateRow_Any_NEON, ARGBUnattenuateRow_NEON, 0, 4, 4, 3)
#endif
#ifdef HAS_ARGBATTENUATEROW_LSX
ANY11(ARGBAttenuateRow_Any_LSX, ARGBAttenuateRow_LSX, 0, 4, 4, 3)
#endif
@ -1419,6 +1431,9 @@ ANY11B(ARGBCopyAlphaRow_Any_AVX2, ARGBCopyAlphaRow_AVX2, 0, 4, 4, 15)
#ifdef HAS_ARGBCOPYALPHAROW_SSE2
ANY11B(ARGBCopyAlphaRow_Any_SSE2, ARGBCopyAlphaRow_SSE2, 0, 4, 4, 7)
#endif
#ifdef HAS_ARGBCOPYALPHAROW_NEON
ANY11B(ARGBCopyAlphaRow_Any_NEON, ARGBCopyAlphaRow_NEON, 0, 4, 4, 7)
#endif
#ifdef HAS_ARGBCOPYYTOALPHAROW_AVX2
ANY11B(ARGBCopyYToAlphaRow_Any_AVX2, ARGBCopyYToAlphaRow_AVX2, 0, 1, 4, 15)
#endif
@ -1578,6 +1593,14 @@ ANY11P(ARGBOrRow_Any_LASX, ARGBOrRow_LASX, const uint32_t, 4, 4, 7)
#ifdef HAS_ARGBORROW_WASMSIMD
ANY11P(ARGBOrRow_Any_WASMSIMD, ARGBOrRow_WASMSIMD, const uint32_t, 4, 4, 3)
#endif
#ifdef HAS_ARGBPOLYNOMIALROW_NEON
ANY11P(ARGBPolynomialRow_Any_NEON,
ARGBPolynomialRow_NEON,
const float*,
4,
4,
1)
#endif
#undef ANY11P
#undef ANY11P
@ -1647,6 +1670,10 @@ ANY11T(AR64ToARGBRow_Any_NEON, AR64ToARGBRow_NEON, 8, 4, uint16_t, uint8_t, 7)
ANY11T(AB64ToARGBRow_Any_NEON, AB64ToARGBRow_NEON, 8, 4, uint16_t, uint8_t, 7)
#endif
#ifdef HAS_COPYROW_16_NEON
ANY11T(CopyRow_16_Any_NEON, CopyRow_16_NEON, 2, 2, uint16_t, uint16_t, 15)
#endif
#undef ANY11T
// Any 1 to 1 with parameter and shorts. BPP measures in shorts.
@ -2196,6 +2223,31 @@ ANY11M(RGB24MirrorRow_Any_WASMSIMD, RGB24MirrorRow_WASMSIMD, 3, 15)
#endif
#undef ANY11M
// Any 1 to 1 mirror with type.
#define ANY11MT(NAMEANY, ANY_SIMD, T, BPP, MASK) \
void NAMEANY(const T* src_ptr, T* dst_ptr, int width) { \
SIMD_ALIGNED(T vin[64]); \
static_assert((MASK + 1) * BPP <= sizeof(vin), "vin buffer too small"); \
SIMD_ALIGNED(T vout[64]); \
static_assert((MASK + 1) * BPP <= sizeof(vout), "vout buffer too small"); \
MSAN_MEMSET(vin, 0, sizeof(vin)); /* for msan */ \
MSAN_MEMSET(vout, 0, sizeof(vout)); /* for msan */ \
int r = width & MASK; \
int n = width & ~MASK; \
if (n > 0) { \
ANY_SIMD(src_ptr + r, dst_ptr, n); \
} \
ptrdiff_t np = n; \
memcpy(vin, src_ptr, r * BPP); \
ANY_SIMD(vin, vout, MASK + 1); \
memcpy(dst_ptr + np, vout + (MASK + 1 - r), r * BPP); \
}
#ifdef HAS_MIRRORROW_16_NEON
ANY11MT(MirrorRow_16_Any_NEON, MirrorRow_16_NEON, uint16_t, 2, 15)
#endif
#undef ANY11MT
// Any 1 plane. (memset)
#define ANY1(NAMEANY, ANY_SIMD, T, BPP, MASK) \
void NAMEANY(uint8_t* dst_ptr, T v32, int width) { \

View File

@ -3992,6 +3992,433 @@ void Convert8To16Row_NEON(const uint8_t* src_y,
: "cc", "memory", "q0", "q1", "q2");
}
void CopyRow_16_NEON(const uint16_t* src, uint16_t* dst, int count) {
asm volatile(
"1: \n"
"vld1.16 {d0, d1, d2, d3}, [%0]! \n" // load 16
"subs %2, %2, #16 \n" // 16 processed per loop
"vst1.16 {d0, d1, d2, d3}, [%1]! \n" // store 16
"bgt 1b \n"
: "+r"(src), // %0
"+r"(dst), // %1
"+r"(count) // %2
:
: "memory", "cc", "q0", "q1");
}
void MirrorRow_16_NEON(const uint16_t* src, uint16_t* dst, int width) {
asm volatile(
// Start at end of source row.
"add %0, %0, %2, lsl #1 \n"
"sub %0, %0, #32 \n" // 32 bytes per loop
"1: \n"
"vld1.16 {q1, q2}, [%0], %3 \n" // src -= 32
"subs %2, %2, #16 \n" // 16 pixels per loop.
"vrev64.16 q0, q2 \n"
"vrev64.16 q1, q1 \n"
"vswp d0, d1 \n"
"vswp d2, d3 \n"
"vst1.16 {q0, q1}, [%1]! \n" // dst += 32
"bgt 1b \n"
: "+r"(src), // %0
"+r"(dst), // %1
"+r"(width) // %2
: "r"(-32) // %3
: "memory", "cc", "q0", "q1", "q2");
}
void AR30ToARGBRow_NEON(const uint8_t* src_ar30, uint8_t* dst_argb, int width) {
asm volatile(
"vmov.i32 q8, #0x0000ff00 \n"
"vmov.i32 q9, #0x000fffff \n"
"vshl.i32 q9, q9, #8 \n" // 0x0fffff00
"1: \n"
"vld1.8 {q0, q1}, [%0]! \n" // load 8 AR30 pixels
"subs %2, %2, #8 \n" // 8 pixels per loop
"vsri.32 q0, q0, #2 \n"
"vsri.32 q1, q1, #2 \n"
"vshr.u32 q2, q0, #2 \n"
"vshr.u32 q3, q1, #2 \n"
"vshr.u32 q4, q0, #4 \n"
"vshr.u32 q5, q1, #4 \n"
"vbit q0, q4, q9 \n"
"vbit q1, q5, q9 \n"
"vbit q0, q2, q8 \n"
"vbit q1, q3, q8 \n"
"vst1.8 {q0, q1}, [%1]! \n" // store 8 ARGB pixels
"bgt 1b \n"
: "+r"(src_ar30), // %0
"+r"(dst_argb), // %1
"+r"(width) // %2
:
: "memory", "cc", "q0", "q1", "q2", "q3", "q4", "q5", "q8", "q9");
}
void AR30ToABGRRow_NEON(const uint8_t* src_ar30, uint8_t* dst_abgr, int width) {
asm volatile(
"vmov.i64 q8, #0x00ffff0000ffff00 \n"
"1: \n"
"vld1.8 {q0, q1}, [%0]! \n" // load 8 AR30 pixels
"subs %2, %2, #8 \n" // 8 pixels per loop
"vsri.32 q0, q0, #2 \n"
"vsri.32 q1, q1, #2 \n"
"vshr.u32 q2, q0, #2 \n"
"vshr.u32 q3, q1, #2 \n"
"vsli.32 q2, q0, #16 \n"
"vsli.32 q3, q1, #16 \n"
"vsri.32 q0, q0, #4 \n"
"vsri.32 q1, q1, #4 \n"
"vsri.32 q0, q0, #16 \n"
"vsri.32 q1, q1, #16 \n"
"vbit q0, q2, q8 \n"
"vbit q1, q3, q8 \n"
"vst1.8 {q0, q1}, [%1]! \n" // store 8 ABGR pixels
"bgt 1b \n"
: "+r"(src_ar30), // %0
"+r"(dst_abgr), // %1
"+r"(width) // %2
:
: "memory", "cc", "q0", "q1", "q2", "q3", "q8");
}
void AR30ToAB30Row_NEON(const uint8_t* src_ar30, uint8_t* dst_ab30, int width) {
asm volatile(
"vmov.i8 q9, #0xff \n"
"vshr.u32 q9, q9, #22 \n" // 0x000003ff
"vshl.i32 q8, q9, #20 \n" // 0x3ff00000
"1: \n"
"vld1.8 {q0, q1}, [%0]! \n" // load 8 AR30 pixels
"subs %2, %2, #8 \n" // 8 pixels per loop
"vshl.i32 q2, q0, #20 \n"
"vshl.i32 q3, q1, #20 \n"
"vshr.u32 q4, q0, #20 \n"
"vshr.u32 q5, q1, #20 \n"
"vbit q0, q2, q8 \n"
"vbit q1, q3, q8 \n"
"vbit q0, q4, q9 \n"
"vbit q1, q5, q9 \n"
"vst1.8 {q0, q1}, [%1]! \n" // store 8 AB30 pixels
"bgt 1b \n"
: "+r"(src_ar30), // %0
"+r"(dst_ab30), // %1
"+r"(width) // %2
:
: "memory", "cc", "q0", "q1", "q2", "q3", "q4", "q5", "q8", "q9");
}
void ARGBCopyAlphaRow_NEON(const uint8_t* src, uint8_t* dst, int width) {
asm volatile(
"vmov.i32 q4, #0xff000000 \n"
"1: \n"
"vld1.8 {q0, q1}, [%0]! \n" // load 8 src pixels
"vld1.8 {q2, q3}, [%1] \n" // load 8 dst pixels
"subs %2, %2, #8 \n" // 8 pixels per loop
"vbit q2, q0, q4 \n"
"vbit q3, q1, q4 \n"
"vst1.8 {q2, q3}, [%1]! \n" // store 8 dst pixels
"bgt 1b \n"
: "+r"(src), // %0
"+r"(dst), // %1
"+r"(width) // %2
:
: "memory", "cc", "q0", "q1", "q2", "q3", "q4");
}
void ARGBUnattenuateRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
int width) {
uint32_t tmp, addr;
asm volatile(
"vmov.i32 q8, #0xff000000 \n"
"1: \n"
"ldrb %3, [%0, #3] \n"
"add %4, %5, %3, lsl #2 \n"
"vld1.16 {d6[0]}, [%4] \n"
"ldrb %3, [%0, #7] \n"
"add %4, %5, %3, lsl #2 \n"
"vld1.16 {d6[1]}, [%4] \n"
"ldrb %3, [%0, #11] \n"
"add %4, %5, %3, lsl #2 \n"
"vld1.16 {d6[2]}, [%4] \n"
"ldrb %3, [%0, #15] \n"
"add %4, %5, %3, lsl #2 \n"
"vld1.16 {d6[3]}, [%4] \n"
"vld1.8 {q0}, [%0]! \n"
"subs %2, %2, #4 \n"
"vmov q1, q0 \n"
"vmov q2, q0 \n"
"vzip.8 q1, q2 \n"
"vmull.u16 q4, d2, d6[0] \n"
"vmull.u16 q5, d3, d6[1] \n"
"vmull.u16 q6, d4, d6[2] \n"
"vmull.u16 q7, d5, d6[3] \n"
"vshrn.i32 d8, q4, #16 \n"
"vshrn.i32 d9, q5, #16 \n"
"vshrn.i32 d12, q6, #16 \n"
"vshrn.i32 d13, q7, #16 \n"
"vqmovn.u16 d2, q4 \n"
"vqmovn.u16 d3, q6 \n"
"vbit q1, q0, q8 \n"
"vst1.8 {q1}, [%1]! \n"
"bgt 1b \n"
: "+r"(src_argb), // %0
"+r"(dst_argb), // %1
"+r"(width), // %2
"=&r"(tmp), // %3
"=&r"(addr) // %4
: "r"(fixed_invtbl8) // %5
: "memory", "cc", "q0", "q1", "q2", "d6", "q4", "q5", "q6", "q7", "q8");
}
void ARGBPolynomialRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
const float* poly,
int width) {
asm volatile(
"vld1.32 {q8, q9}, [%3]! \n" // c0, c1
"vld1.32 {q10, q11}, [%3] \n" // c2, c3
"1: \n"
"vld1.8 {d0}, [%0]! \n" // load 2 pixels
"subs %2, %2, #2 \n" // 2 pixels per loop
"vmovl.u8 q0, d0 \n"
"vmovl.u16 q1, d0 \n"
"vmovl.u16 q2, d1 \n"
"vcvt.f32.u32 q1, q1 \n" // x0
"vcvt.f32.u32 q2, q2 \n" // x1
"vmul.f32 q3, q9, q1 \n" // c1 * x0
"vmul.f32 q4, q9, q2 \n" // c1 * x1
"vmul.f32 q5, q1, q1 \n" // x0 * x0
"vmul.f32 q6, q2, q2 \n" // x1 * x1
"vadd.f32 q3, q8, q3 \n" // c0 + c1 * x0
"vadd.f32 q4, q8, q4 \n" // c0 + c1 * x1
"vmla.f32 q3, q10, q5 \n" // + c2 * x0^2
"vmla.f32 q4, q10, q6 \n" // + c2 * x1^2
"vmul.f32 q5, q5, q1 \n" // x0^3
"vmul.f32 q6, q6, q2 \n" // x1^3
"vmla.f32 q3, q11, q5 \n" // + c3 * x0^3
"vmla.f32 q4, q11, q6 \n" // + c3 * x1^3
"vcvt.s32.f32 q3, q3 \n"
"vcvt.s32.f32 q4, q4 \n"
"vqmovn.s32 d6, q3 \n"
"vqmovn.s32 d7, q4 \n"
"vqmovun.s16 d6, q3 \n"
"vst1.8 {d6}, [%1]! \n"
"bgt 1b \n"
: "+r"(src_argb), // %0
"+r"(dst_argb), // %1
"+r"(width), // %2
"+r"(poly) // %3
:
: "memory", "cc", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q8", "q9",
"q10", "q11");
}
void ARGBColorTableRow_NEON(uint8_t* dst_argb,
const uint8_t* table_argb,
int width) {
const uint8_t* table_g = table_argb + 1;
const uint8_t* table_r = table_argb + 2;
const uint8_t* table_a = table_argb + 3;
uint32_t b, g, r, a;
asm volatile(
"1: \n"
"ldrb %2, [%0] \n"
"ldrb %3, [%0, #1] \n"
"ldrb %4, [%0, #2] \n"
"ldrb %5, [%0, #3] \n"
"ldrb %2, [%6, %2, lsl #2] \n"
"ldrb %3, [%7, %3, lsl #2] \n"
"ldrb %4, [%8, %4, lsl #2] \n"
"ldrb %5, [%9, %5, lsl #2] \n"
"subs %1, %1, #1 \n"
"strb %2, [%0] \n"
"strb %3, [%0, #1] \n"
"strb %4, [%0, #2] \n"
"strb %5, [%0, #3] \n"
"add %0, %0, #4 \n"
"bgt 1b \n"
: "+r"(dst_argb), // %0
"+r"(width), // %1
"=&r"(b), // %2
"=&r"(g), // %3
"=&r"(r), // %4
"=&r"(a) // %5
: "r"(table_argb), // %6
"r"(table_g), // %7
"r"(table_r), // %8
"r"(table_a) // %9
: "memory", "cc");
}
void RGBColorTableRow_NEON(uint8_t* dst_argb,
const uint8_t* table_argb,
int width) {
const uint8_t* table_g = table_argb + 1;
const uint8_t* table_r = table_argb + 2;
uint32_t b, g, r;
asm volatile(
"1: \n"
"ldrb %2, [%0] \n"
"ldrb %3, [%0, #1] \n"
"ldrb %4, [%0, #2] \n"
"ldrb %2, [%5, %2, lsl #2] \n"
"ldrb %3, [%6, %3, lsl #2] \n"
"ldrb %4, [%7, %4, lsl #2] \n"
"subs %1, %1, #1 \n"
"strb %2, [%0] \n"
"strb %3, [%0, #1] \n"
"strb %4, [%0, #2] \n"
"add %0, %0, #4 \n"
"bgt 1b \n"
: "+r"(dst_argb), // %0
"+r"(width), // %1
"=&r"(b), // %2
"=&r"(g), // %3
"=&r"(r) // %4
: "r"(table_argb), // %5
"r"(table_g), // %6
"r"(table_r) // %7
: "memory", "cc");
}
void ARGBLumaColorTableRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
int width,
const uint8_t* luma,
uint32_t lumacoeff) {
uint32_t idx, addr;
asm volatile(
"vdup.32 q4, %6 \n" // lumacoeff
"1: \n"
"vld1.8 {q0}, [%0]! \n" // load 4 ARGB pixels
"subs %2, %2, #4 \n" // 4 pixels per loop
"vmull.u8 q1, d0, d8 \n"
"vmull.u8 q2, d1, d9 \n"
"vpadd.i16 d2, d2, d3 \n"
"vpadd.i16 d3, d4, d5 \n"
"vpadd.i16 d2, d2, d3 \n"
"vbic.i16 d2, #0x8000 \n" // clear bit 15
"vshrn.i16 d2, q1, #8 \n" // L_k & 0x7f
"vmov d3, d2 \n"
"vzip.8 d2, d3 \n"
"vmov d3, d2 \n"
"vzip.8 d2, d3 \n"
"vmov q2, q0 \n"
"vzip.8 q2, q1 \n" // q2: p0,1; q1: p2,3
"vmov.u16 %3, d4[0] \n"
"add %4, %5, %3 \n"
"vld1.8 {d0[0]}, [%4] \n"
"vmov.u16 %3, d4[1] \n"
"add %4, %5, %3 \n"
"vld1.8 {d0[1]}, [%4] \n"
"vmov.u16 %3, d4[2] \n"
"add %4, %5, %3 \n"
"vld1.8 {d0[2]}, [%4] \n"
"vmov.u16 %3, d5[0] \n"
"add %4, %5, %3 \n"
"vld1.8 {d0[4]}, [%4] \n"
"vmov.u16 %3, d5[1] \n"
"add %4, %5, %3 \n"
"vld1.8 {d0[5]}, [%4] \n"
"vmov.u16 %3, d5[2] \n"
"add %4, %5, %3 \n"
"vld1.8 {d0[6]}, [%4] \n"
"vmov.u16 %3, d2[0] \n"
"add %4, %5, %3 \n"
"vld1.8 {d1[0]}, [%4] \n"
"vmov.u16 %3, d2[1] \n"
"add %4, %5, %3 \n"
"vld1.8 {d1[1]}, [%4] \n"
"vmov.u16 %3, d2[2] \n"
"add %4, %5, %3 \n"
"vld1.8 {d1[2]}, [%4] \n"
"vmov.u16 %3, d3[0] \n"
"add %4, %5, %3 \n"
"vld1.8 {d1[4]}, [%4] \n"
"vmov.u16 %3, d3[1] \n"
"add %4, %5, %3 \n"
"vld1.8 {d1[5]}, [%4] \n"
"vmov.u16 %3, d3[2] \n"
"add %4, %5, %3 \n"
"vld1.8 {d1[6]}, [%4] \n"
"vst1.8 {q0}, [%1]! \n"
"bgt 1b \n"
: "+r"(src_argb), // %0
"+r"(dst_argb), // %1
"+r"(width), // %2
"=&r"(idx), // %3
"=&r"(addr) // %4
: "r"(luma), // %5
"r"(lumacoeff) // %6
: "memory", "cc", "q0", "q1", "q2", "q4");
}
void ARGBAffineRow_NEON(const uint8_t* src_argb,
int src_argb_stride,
uint8_t* dst_argb,
const float* uv_dudv,
int width) {
uint32_t off0, off1;
asm volatile(
"vld1.32 {d4, d5}, [%5] \n" // d4=[u,v], d5=[du,dv]
"vmov d12, d5 \n" // d12=[du,dv]
"vdup.32 d10, %4 \n" // [stride, stride]
"vmov.i32 d11, #4 \n" // [4, 4]
"vtrn.32 d11, d10 \n" // q5=[4, stride, 4,
// stride]
"subs %1, %1, #4 \n"
"blt 2f \n"
"vmov d13, d12 \n" // q6=[du, dv, du, dv]
"vadd.f32 q4, q6, q6 \n" // 2 * [du, dv, du, dv]
"vadd.f32 d5, d4, d12 \n" // [u+du, v+dv]
"vadd.f32 q3, q2, q4 \n" // [u+2du, v+2dv, u+3du,
// v+3dv]
"vadd.f32 q4, q4, q4 \n" // 4 * [du, dv, du, dv]
"1: \n"
"vcvt.s32.f32 q0, q2 \n"
"vcvt.s32.f32 q1, q3 \n"
"vadd.f32 q2, q2, q4 \n"
"vadd.f32 q3, q3, q4 \n"
"vmul.i32 q0, q0, q5 \n"
"vmul.i32 q1, q1, q5 \n"
"vpadd.i32 d14, d0, d1 \n"
"vpadd.i32 d15, d2, d3 \n"
"vmov %2, %3, d14 \n"
"ldr %2, [%6, %2] \n"
"ldr %3, [%6, %3] \n"
"str %2, [%0], #4 \n"
"str %3, [%0], #4 \n"
"vmov %2, %3, d15 \n"
"ldr %2, [%6, %2] \n"
"ldr %3, [%6, %3] \n"
"str %2, [%0], #4 \n"
"str %3, [%0], #4 \n"
"subs %1, %1, #4 \n"
"bge 1b \n"
"2: \n"
"adds %1, %1, #4 \n"
"beq 4f \n"
"3: \n"
"vcvt.s32.f32 d0, d4 \n"
"vadd.f32 d4, d4, d12 \n"
"vmul.i32 d0, d0, d10 \n"
"vpadd.i32 d0, d0, d0 \n"
"vmov.32 %2, d0[0] \n"
"ldr %2, [%6, %2] \n"
"str %2, [%0], #4 \n"
"subs %1, %1, #1 \n"
"bgt 3b \n"
"4: \n"
: "+r"(dst_argb), // %0
"+r"(width), // %1
"=&r"(off0), // %2
"=&r"(off1) // %3
: "r"(src_argb_stride), // %4
"r"(uv_dudv), // %5
"r"(src_argb) // %6
: "memory", "cc", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7");
}
#endif // !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)..
#ifdef __cplusplus

View File

@ -5642,6 +5642,471 @@ void Convert8To16Row_NEON(const uint8_t* src_y,
: "cc", "memory", "v0", "v1", "v2");
}
void CopyRow_16_NEON(const uint16_t* src, uint16_t* dst, int count) {
asm volatile(
"1: \n"
"ldp q0, q1, [%0], #32 \n"
"subs %w2, %w2, #16 \n" // 16 processed per loop
"stp q0, q1, [%1], #32 \n"
"b.gt 1b \n"
: "+r"(src), // %0
"+r"(dst), // %1
"+r"(count) // %2
:
: "memory", "cc", "v0", "v1");
}
void MirrorRow_16_NEON(const uint16_t* src, uint16_t* dst, int width) {
asm volatile(
// Start at end of source row.
"ld1 {v4.16b}, [%3] \n" // shuffler
"add %0, %0, %w2, sxtw #1 \n"
"sub %0, %0, #32 \n"
"1: \n"
"ldr q1, [%0, 16] \n"
"ldr q0, [%0], -32 \n" // src -= 32
"subs %w2, %w2, #16 \n" // 16 pixels per loop.
"tbl v2.16b, {v1.16b}, v4.16b \n"
"tbl v3.16b, {v0.16b}, v4.16b \n"
"stp q2, q3, [%1], #32 \n" // dst += 32
"b.gt 1b \n"
: "+r"(src), // %0
"+r"(dst), // %1
"+r"(width) // %2
: "r"(&kShuffleMirrorUV) // %3
: "memory", "cc", "v0", "v1", "v2", "v3", "v4");
}
void AR30ToARGBRow_NEON(const uint8_t* src_ar30, uint8_t* dst_argb, int width) {
asm volatile(
"movi v16.4s, #0xff, lsl #8 \n" // 0x0000ff00
"movi v17.4s, #0x0f, msl #16 \n" // 0x000fffff
"shl v17.4s, v17.4s, #8 \n" // 0x0fffff00
"1: \n"
"ldp q0, q1, [%0], #32 \n" // load 8 AR30 pixels
"subs %w2, %w2, #8 \n" // 8 pixels per loop
"sri v0.4s, v0.4s, #2 \n"
"sri v1.4s, v1.4s, #2 \n"
"ushr v2.4s, v0.4s, #2 \n"
"ushr v3.4s, v1.4s, #2 \n"
"ushr v4.4s, v0.4s, #4 \n"
"ushr v5.4s, v1.4s, #4 \n"
"bit v0.16b, v4.16b, v17.16b \n"
"bit v1.16b, v5.16b, v17.16b \n"
"bit v0.16b, v2.16b, v16.16b \n"
"bit v1.16b, v3.16b, v16.16b \n"
"stp q0, q1, [%1], #32 \n" // store 8 ARGB pixels
"b.gt 1b \n"
: "+r"(src_ar30), // %0
"+r"(dst_argb), // %1
"+r"(width) // %2
:
: "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v16", "v17");
}
void AR30ToABGRRow_NEON(const uint8_t* src_ar30, uint8_t* dst_abgr, int width) {
asm volatile(
"movi v16.2d, #0x00ffff0000ffff00 \n"
"1: \n"
"ldp q0, q1, [%0], #32 \n" // load 8 AR30 pixels
"subs %w2, %w2, #8 \n" // 8 pixels per loop
"sri v0.4s, v0.4s, #2 \n"
"sri v1.4s, v1.4s, #2 \n"
"ushr v2.4s, v0.4s, #2 \n"
"ushr v3.4s, v1.4s, #2 \n"
"sli v2.4s, v0.4s, #16 \n"
"sli v3.4s, v1.4s, #16 \n"
"sri v0.4s, v0.4s, #4 \n"
"sri v1.4s, v1.4s, #4 \n"
"sri v0.4s, v0.4s, #16 \n"
"sri v1.4s, v1.4s, #16 \n"
"bit v0.16b, v2.16b, v16.16b \n"
"bit v1.16b, v3.16b, v16.16b \n"
"stp q0, q1, [%1], #32 \n" // store 8 ABGR pixels
"b.gt 1b \n"
: "+r"(src_ar30), // %0
"+r"(dst_abgr), // %1
"+r"(width) // %2
:
: "memory", "cc", "v0", "v1", "v2", "v3", "v16");
}
void AR30ToAB30Row_NEON(const uint8_t* src_ar30, uint8_t* dst_ab30, int width) {
asm volatile(
"movi v17.16b, #0xff \n"
"ushr v17.4s, v17.4s, #22 \n" // 0x000003ff
"shl v16.4s, v17.4s, #20 \n" // 0x3ff00000
"1: \n"
"ldp q0, q1, [%0], #32 \n" // load 8 AR30 pixels
"subs %w2, %w2, #8 \n" // 8 pixels per loop
"shl v2.4s, v0.4s, #20 \n"
"shl v3.4s, v1.4s, #20 \n"
"ushr v4.4s, v0.4s, #20 \n"
"ushr v5.4s, v1.4s, #20 \n"
"bit v0.16b, v2.16b, v16.16b \n"
"bit v1.16b, v3.16b, v16.16b \n"
"bit v0.16b, v4.16b, v17.16b \n"
"bit v1.16b, v5.16b, v17.16b \n"
"stp q0, q1, [%1], #32 \n" // store 8 AB30 pixels
"b.gt 1b \n"
: "+r"(src_ar30), // %0
"+r"(dst_ab30), // %1
"+r"(width) // %2
:
: "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v16", "v17");
}
void ARGBCopyAlphaRow_NEON(const uint8_t* src, uint8_t* dst, int width) {
asm volatile(
"movi v4.4s, #0xff, lsl #24 \n" // 0xff000000
"1: \n"
"ldp q0, q1, [%0], #32 \n" // load 8 src pixels
"ldp q2, q3, [%1] \n" // load 8 dst pixels
"subs %w2, %w2, #8 \n" // 8 pixels per loop
"bit v2.16b, v0.16b, v4.16b \n"
"bit v3.16b, v1.16b, v4.16b \n"
"stp q2, q3, [%1], #32 \n" // store 8 dst pixels
"b.gt 1b \n"
: "+r"(src), // %0
"+r"(dst), // %1
"+r"(width) // %2
:
: "memory", "cc", "v0", "v1", "v2", "v3", "v4");
}
void ARGBUnattenuateRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
int width) {
uint64_t tmp;
asm volatile(
"movi v16.4s, #0xff, lsl #24 \n" // 0xff000000
"1: \n"
"ldrb %w3, [%0, #3] \n"
"ldr s4, [%4, %w3, uxtw #2] \n"
"ldrb %w3, [%0, #7] \n"
"ldr s5, [%4, %w3, uxtw #2] \n"
"ldrb %w3, [%0, #11] \n"
"ldr s6, [%4, %w3, uxtw #2] \n"
"ldrb %w3, [%0, #15] \n"
"ldr s7, [%4, %w3, uxtw #2] \n"
"ldr q0, [%0], #16 \n"
"subs %w2, %w2, #4 \n"
"zip1 v1.16b, v0.16b, v0.16b \n"
"zip2 v2.16b, v0.16b, v0.16b \n"
"umull v3.4s, v1.4h, v4.h[0] \n"
"umull2 v5.4s, v1.8h, v5.h[0] \n"
"umull v6.4s, v2.4h, v6.h[0] \n"
"umull2 v7.4s, v2.8h, v7.h[0] \n"
"uzp2 v3.8h, v3.8h, v5.8h \n"
"uzp2 v6.8h, v6.8h, v7.8h \n"
"uqxtn v1.8b, v3.8h \n"
"uqxtn2 v1.16b, v6.8h \n"
"bit v1.16b, v0.16b, v16.16b \n"
"str q1, [%1], #16 \n"
"b.gt 1b \n"
: "+r"(src_argb), // %0
"+r"(dst_argb), // %1
"+r"(width), // %2
"=&r"(tmp) // %3
: "r"(fixed_invtbl8) // %4
: "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16");
}
void ARGBPolynomialRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
const float* poly,
int width) {
asm volatile(
"ldp q16, q17, [%3] \n" // c0, c1
"ldp q18, q19, [%3, #32] \n" // c2, c3
"subs %w2, %w2, #4 \n"
"b.lt 2f \n"
"1: \n"
"ldr q0, [%0], #16 \n" // load 4 pixels
"subs %w2, %w2, #4 \n"
"uxtl v1.8h, v0.8b \n"
"uxtl2 v3.8h, v0.16b \n"
"uxtl v0.4s, v1.4h \n"
"uxtl2 v1.4s, v1.8h \n"
"uxtl v2.4s, v3.4h \n"
"uxtl2 v3.4s, v3.8h \n"
"ucvtf v0.4s, v0.4s \n" // x0
"ucvtf v1.4s, v1.4s \n" // x1
"ucvtf v2.4s, v2.4s \n" // x2
"ucvtf v3.4s, v3.4s \n" // x3
"fmul v20.4s, v0.4s, v0.4s \n" // x0^2
"fmul v21.4s, v1.4s, v1.4s \n" // x1^2
"fmul v22.4s, v2.4s, v2.4s \n" // x2^2
"fmul v23.4s, v3.4s, v3.4s \n" // x3^2
"fmul v4.4s, v17.4s, v0.4s \n" // c1 * x0
"fmul v5.4s, v17.4s, v1.4s \n" // c1 * x1
"fmul v6.4s, v17.4s, v2.4s \n" // c1 * x2
"fmul v7.4s, v17.4s, v3.4s \n" // c1 * x3
"fmul v0.4s, v20.4s, v0.4s \n" // x0^3
"fmul v1.4s, v21.4s, v1.4s \n" // x1^3
"fmul v2.4s, v22.4s, v2.4s \n" // x2^3
"fmul v3.4s, v23.4s, v3.4s \n" // x3^3
"fadd v4.4s, v16.4s, v4.4s \n" // c0 + c1 * x0
"fadd v5.4s, v16.4s, v5.4s \n" // c0 + c1 * x1
"fadd v6.4s, v16.4s, v6.4s \n" // c0 + c1 * x2
"fadd v7.4s, v16.4s, v7.4s \n" // c0 + c1 * x3
"fmla v4.4s, v18.4s, v20.4s \n" // + c2 * x0^2
"fmla v5.4s, v18.4s, v21.4s \n" // + c2 * x1^2
"fmla v6.4s, v18.4s, v22.4s \n" // + c2 * x2^2
"fmla v7.4s, v18.4s, v23.4s \n" // + c2 * x3^2
"fmla v4.4s, v19.4s, v0.4s \n" // + c3 * x0^3
"fmla v5.4s, v19.4s, v1.4s \n" // + c3 * x1^3
"fmla v6.4s, v19.4s, v2.4s \n" // + c3 * x2^3
"fmla v7.4s, v19.4s, v3.4s \n" // + c3 * x3^3
"fcvtzs v4.4s, v4.4s \n"
"fcvtzs v5.4s, v5.4s \n"
"fcvtzs v6.4s, v6.4s \n"
"fcvtzs v7.4s, v7.4s \n"
"sqxtn v4.4h, v4.4s \n"
"sqxtn2 v4.8h, v5.4s \n"
"sqxtn v6.4h, v6.4s \n"
"sqxtn2 v6.8h, v7.4s \n"
"sqxtun v4.8b, v4.8h \n"
"sqxtun2 v4.16b, v6.8h \n"
"str q4, [%1], #16 \n"
"b.ge 1b \n"
"2: \n"
"adds %w2, %w2, #4 \n"
"b.eq 3f \n"
"ldr d0, [%0], #8 \n" // load 2 pixels
"uxtl v0.8h, v0.8b \n"
"uxtl v1.4s, v0.4h \n"
"uxtl2 v2.4s, v0.8h \n"
"ucvtf v1.4s, v1.4s \n" // x0
"ucvtf v2.4s, v2.4s \n" // x1
"fmul v5.4s, v1.4s, v1.4s \n" // x0^2
"fmul v6.4s, v2.4s, v2.4s \n" // x1^2
"fmul v3.4s, v17.4s, v1.4s \n" // c1 * x0
"fmul v4.4s, v17.4s, v2.4s \n" // c1 * x1
"fmul v1.4s, v5.4s, v1.4s \n" // x0^3
"fmul v2.4s, v6.4s, v2.4s \n" // x1^3
"fadd v3.4s, v16.4s, v3.4s \n" // c0 + c1 * x0
"fadd v4.4s, v16.4s, v4.4s \n" // c0 + c1 * x1
"fmla v3.4s, v18.4s, v5.4s \n" // + c2 * x0^2
"fmla v4.4s, v18.4s, v6.4s \n" // + c2 * x1^2
"fmla v3.4s, v19.4s, v1.4s \n" // + c3 * x0^3
"fmla v4.4s, v19.4s, v2.4s \n" // + c3 * x1^3
"fcvtzs v3.4s, v3.4s \n"
"fcvtzs v4.4s, v4.4s \n"
"sqxtn v3.4h, v3.4s \n"
"sqxtn2 v3.8h, v4.4s \n"
"sqxtun v3.8b, v3.8h \n"
"str d3, [%1], #8 \n"
"3: \n"
: "+r"(src_argb), // %0
"+r"(dst_argb), // %1
"+r"(width) // %2
: "r"(poly) // %3
: "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
"v17", "v18", "v19", "v20", "v21", "v22", "v23");
}
void ARGBColorTableRow_NEON(uint8_t* dst_argb,
const uint8_t* table_argb,
int width) {
uint64_t b, g, r, a;
asm volatile(
"1: \n"
"ldrb %w2, [%0] \n"
"ldrb %w3, [%0, #1] \n"
"ldrb %w4, [%0, #2] \n"
"ldrb %w5, [%0, #3] \n"
"subs %w1, %w1, #1 \n"
"ldr %w2, [%6, %w2, uxtw #2] \n"
"ldr %w3, [%6, %w3, uxtw #2] \n"
"ldr %w4, [%6, %w4, uxtw #2] \n"
"ldr %w5, [%6, %w5, uxtw #2] \n"
"bfi %w3, %w2, #0, #8 \n"
"lsr %w4, %w4, #16 \n"
"lsr %w5, %w5, #24 \n"
"strh %w3, [%0] \n"
"strb %w4, [%0, #2] \n"
"strb %w5, [%0, #3] \n"
"add %0, %0, #4 \n"
"b.gt 1b \n"
: "+r"(dst_argb), // %0
"+r"(width), // %1
"=&r"(b), // %2
"=&r"(g), // %3
"=&r"(r), // %4
"=&r"(a) // %5
: "r"(table_argb) // %6
: "memory", "cc");
}
void RGBColorTableRow_NEON(uint8_t* dst_argb,
const uint8_t* table_argb,
int width) {
uint64_t b, g, r;
asm volatile(
"1: \n"
"ldrb %w2, [%0] \n"
"ldrb %w3, [%0, #1] \n"
"ldrb %w4, [%0, #2] \n"
"subs %w1, %w1, #1 \n"
"ldr %w2, [%5, %w2, uxtw #2] \n"
"ldr %w3, [%5, %w3, uxtw #2] \n"
"ldr %w4, [%5, %w4, uxtw #2] \n"
"bfi %w3, %w2, #0, #8 \n"
"lsr %w4, %w4, #16 \n"
"strh %w3, [%0] \n"
"strb %w4, [%0, #2] \n"
"add %0, %0, #4 \n"
"b.gt 1b \n"
: "+r"(dst_argb), // %0
"+r"(width), // %1
"=&r"(b), // %2
"=&r"(g), // %3
"=&r"(r) // %4
: "r"(table_argb) // %5
: "memory", "cc");
}
static const uvec8 kLumaTblIdx = {1, 1, 1, 1, 3, 3, 3, 3,
5, 5, 5, 5, 7, 7, 7, 7};
void ARGBLumaColorTableRow_NEON(const uint8_t* src_argb,
uint8_t* dst_argb,
int width,
const uint8_t* luma,
uint32_t lumacoeff) {
uint64_t p0, p1, t0, t1;
asm volatile(
"dup v4.4s, %w8 \n" // broadcast 4 byte coeffs
"ldr q5, [%9] \n"
"movi v6.4s, #0xff, lsl #24 \n"
"1: \n"
"ldr q0, [%0], #16 \n" // load 4 ARGB pixels
"subs %w2, %w2, #4 \n" // 4 pixels per loop
"umull v1.8h, v0.8b, v4.8b \n"
"umull2 v2.8h, v0.16b, v4.16b \n"
"addp v1.8h, v1.8h, v2.8h \n"
"addp v1.8h, v1.8h, v1.8h \n"
"bic v1.8h, #0x80, lsl #8 \n" // clear bit 15
"tbl v1.16b, {v1.16b}, v5.16b \n"
"zip2 v2.16b, v0.16b, v1.16b \n" // offsets pixels 2, 3
"zip1 v1.16b, v0.16b, v1.16b \n" // offsets pixels 0, 1
"umov %3, v1.d[0] \n"
"umov %4, v1.d[1] \n"
"add %5, %7, %w3, uxth \n"
"ubfx %6, %3, #16, #16 \n"
"ldr b3, [%5] \n"
"add %6, %7, %6 \n"
"ubfx %5, %3, #32, #16 \n"
"ld1 {v3.b}[1], [%6] \n"
"add %5, %7, %5 \n"
"add %6, %7, %w4, uxth \n"
"ld1 {v3.b}[2], [%5] \n"
"ld1 {v3.b}[4], [%6] \n"
"ubfx %5, %4, #16, #16 \n"
"ubfx %6, %4, #32, #16 \n"
"add %5, %7, %5 \n"
"add %6, %7, %6 \n"
"ld1 {v3.b}[5], [%5] \n"
"ld1 {v3.b}[6], [%6] \n"
"umov %3, v2.d[0] \n"
"umov %4, v2.d[1] \n"
"add %5, %7, %w3, uxth \n"
"ubfx %6, %3, #16, #16 \n"
"ld1 {v3.b}[8], [%5] \n"
"add %6, %7, %6 \n"
"ubfx %5, %3, #32, #16 \n"
"ld1 {v3.b}[9], [%6] \n"
"add %5, %7, %5 \n"
"add %6, %7, %w4, uxth \n"
"ld1 {v3.b}[10], [%5] \n"
"ld1 {v3.b}[12], [%6] \n"
"ubfx %5, %4, #16, #16 \n"
"ubfx %6, %4, #32, #16 \n"
"add %5, %7, %5 \n"
"add %6, %7, %6 \n"
"ld1 {v3.b}[13], [%5] \n"
"ld1 {v3.b}[14], [%6] \n"
"bit v3.16b, v0.16b, v6.16b \n"
"str q3, [%1], #16 \n"
"b.gt 1b \n"
: "+r"(src_argb), // %0
"+r"(dst_argb), // %1
"+r"(width), // %2
"=&r"(p0), // %3
"=&r"(p1), // %4
"=&r"(t0), // %5
"=&r"(t1) // %6
: "r"(luma), // %7
"r"(lumacoeff), // %8
"r"(&kLumaTblIdx) // %9
: "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6");
}
void ARGBAffineRow_NEON(const uint8_t* src_argb,
int src_argb_stride,
uint8_t* dst_argb,
const float* uv_dudv,
int width) {
int64_t off0, off1;
asm volatile(
"ld1r {v2.2d}, [%2], #8 \n" // [u, v, u, v]
"ld1r {v6.2d}, [%2] \n" // [du, dv, du, dv]
"dup v5.2s, %w5 \n" // [stride, stride]
"movi v4.2s, #4 \n" // [4, 4]
"zip1 v5.4s, v4.4s, v5.4s \n" // [4, stride, 4, stride]
"subs %w1, %w1, #4 \n"
"b.lt 2f \n"
"fadd v4.4s, v6.4s, v6.4s \n" // 2 * [du, dv, du, dv]
"fadd v3.2s, v2.2s, v6.2s \n" // [u+du, v+dv]
"ins v2.d[1], v3.d[0] \n" // [u, v, u+du, v+dv]
"fadd v3.4s, v2.4s, v4.4s \n" // [u+2du, v+2dv, u+3du,
// v+3dv]
"fadd v4.4s, v4.4s, v4.4s \n" // 4 * [du, dv, du, dv]
"1: \n"
"fcvtzs v0.4s, v2.4s \n"
"fcvtzs v1.4s, v3.4s \n"
"fadd v2.4s, v2.4s, v4.4s \n"
"fadd v3.4s, v3.4s, v4.4s \n"
"mul v0.4s, v0.4s, v5.4s \n"
"mul v1.4s, v1.4s, v5.4s \n"
"addp v7.4s, v0.4s, v1.4s \n"
"smov %3, v7.s[0] \n"
"smov %4, v7.s[1] \n"
"ldr %w3, [%6, %3] \n"
"ldr %w4, [%6, %4] \n"
"stp %w3, %w4, [%0], #8 \n"
"smov %3, v7.s[2] \n"
"smov %4, v7.s[3] \n"
"ldr %w3, [%6, %3] \n"
"ldr %w4, [%6, %4] \n"
"stp %w3, %w4, [%0], #8 \n"
"subs %w1, %w1, #4 \n"
"b.ge 1b \n"
"2: \n"
"adds %w1, %w1, #4 \n"
"b.eq 4f \n"
"3: \n"
"fcvtzs v0.2s, v2.2s \n"
"fadd v2.2s, v2.2s, v6.2s \n"
"mul v0.2s, v0.2s, v5.2s \n"
"addp v0.2s, v0.2s, v0.2s \n"
"smov %3, v0.s[0] \n"
"ldr %w3, [%6, %3] \n"
"str %w3, [%0], #4 \n"
"subs %w1, %w1, #1 \n"
"b.gt 3b \n"
"4: \n"
: "+r"(dst_argb), // %0
"+r"(width), // %1
"+r"(uv_dudv), // %2
"=&r"(off0), // %3
"=&r"(off1) // %4
: "r"(src_argb_stride), // %5
"r"(src_argb) // %6
: "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7");
}
#endif // !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
#ifdef __cplusplus

View File

@ -1543,34 +1543,61 @@ TEST_F(LibYUVPlanarTest, I420Blend_Invert) {
#ifdef ENABLE_ROW_TESTS
TEST_F(LibYUVPlanarTest, TestAffine) {
SIMD_ALIGNED(uint8_t orig_pixels_0[1280][4]);
SIMD_ALIGNED(uint8_t orig_pixels_0[2][1280][4]);
SIMD_ALIGNED(uint8_t interpolate_pixels_C[1280][4]);
for (int i = 0; i < 1280; ++i) {
for (int j = 0; j < 4; ++j) {
orig_pixels_0[i][j] = i;
for (int r = 0; r < 2; ++r) {
for (int i = 0; i < 1280; ++i) {
for (int j = 0; j < 4; ++j) {
orig_pixels_0[r][i][j] = i + r * 17;
}
}
}
float uv_step[4] = {0.f, 0.f, 0.75f, 0.f};
float uv_step[4] = {0.f, 0.f, 0.75f, 1.f / 1280.f};
const int stride = 1280 * 4;
ARGBAffineRow_C(&orig_pixels_0[0][0], 0, &interpolate_pixels_C[0][0], uv_step,
1280);
ARGBAffineRow_C(&orig_pixels_0[0][0][0], stride, &interpolate_pixels_C[0][0],
uv_step, 1280);
ASSERT_EQ(0u, interpolate_pixels_C[0][0]);
ASSERT_EQ(96u, interpolate_pixels_C[128][0]);
ASSERT_EQ(191u, interpolate_pixels_C[255][3]);
#if defined(HAS_ARGBAFFINEROW_SSE2)
SIMD_ALIGNED(uint8_t interpolate_pixels_Opt[1280][4]);
ARGBAffineRow_SSE2(&orig_pixels_0[0][0], 0, &interpolate_pixels_Opt[0][0],
uv_step, 1280);
ASSERT_EQ(0, memcmp(interpolate_pixels_Opt, interpolate_pixels_C, 1280 * 4));
int has_sse2 = TestCpuFlag(kCpuHasSSE2);
if (has_sse2) {
SIMD_ALIGNED(uint8_t interpolate_pixels_Opt[1280][4]);
ARGBAffineRow_SSE2(&orig_pixels_0[0][0][0], stride,
&interpolate_pixels_Opt[0][0], uv_step, 1280);
ASSERT_EQ(0,
memcmp(interpolate_pixels_Opt, interpolate_pixels_C, 1280 * 4));
ARGBAffineRow_SSE2(&orig_pixels_0[0][0][0], stride,
&interpolate_pixels_Opt[0][0], uv_step, 1279);
ASSERT_EQ(0,
memcmp(interpolate_pixels_Opt, interpolate_pixels_C, 1279 * 4));
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBAffineRow_SSE2(&orig_pixels_0[0][0], 0, &interpolate_pixels_Opt[0][0],
uv_step, 1280);
ARGBAffineRow_SSE2(&orig_pixels_0[0][0][0], stride,
&interpolate_pixels_Opt[0][0], uv_step, 1280);
}
}
#endif
#if defined(HAS_ARGBAFFINEROW_NEON)
int has_neon = TestCpuFlag(kCpuHasNEON);
if (has_neon) {
SIMD_ALIGNED(uint8_t interpolate_pixels_Opt[1280][4]);
ARGBAffineRow_NEON(&orig_pixels_0[0][0][0], stride,
&interpolate_pixels_Opt[0][0], uv_step, 1280);
ASSERT_EQ(0,
memcmp(interpolate_pixels_Opt, interpolate_pixels_C, 1280 * 4));
ARGBAffineRow_NEON(&orig_pixels_0[0][0][0], stride,
&interpolate_pixels_Opt[0][0], uv_step, 1279);
ASSERT_EQ(0,
memcmp(interpolate_pixels_Opt, interpolate_pixels_C, 1279 * 4));
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBAffineRow_NEON(&orig_pixels_0[0][0][0], stride,
&interpolate_pixels_Opt[0][0], uv_step, 1280);
}
}
#endif
@ -1686,6 +1713,83 @@ TEST_F(LibYUVPlanarTest, TestCopyPlaneZero) {
ASSERT_EQ(dst, 0);
}
static int TestCopyPlane_16(int benchmark_width,
int benchmark_height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
const int y_plane_size = benchmark_width * benchmark_height;
align_buffer_page_end(orig_y, (y_plane_size + off) * 2);
align_buffer_page_end(dst_c, y_plane_size * 2);
align_buffer_page_end(dst_opt, y_plane_size * 2);
uint16_t* orig_y_16 = reinterpret_cast<uint16_t*>(orig_y) + off;
uint16_t* dst_c_16 = reinterpret_cast<uint16_t*>(dst_c);
uint16_t* dst_opt_16 = reinterpret_cast<uint16_t*>(dst_opt);
MemRandomize(orig_y, (y_plane_size + off) * 2);
memset(dst_c, 1, y_plane_size * 2);
memset(dst_opt, 2, y_plane_size * 2);
// Disable all optimizations.
MaskCpuFlags(disable_cpu_flags);
for (int i = 0; i < benchmark_iterations; i++) {
CopyPlane_16(orig_y_16, benchmark_width, dst_c_16, benchmark_width,
benchmark_width, benchmark_height * invert);
}
// Enable optimizations.
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; i++) {
CopyPlane_16(orig_y_16, benchmark_width, dst_opt_16, benchmark_width,
benchmark_width, benchmark_height * invert);
}
int max_diff = 0;
for (int i = 0; i < y_plane_size; ++i) {
int abs_diff =
abs(static_cast<int>(dst_c_16[i]) - static_cast<int>(dst_opt_16[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(orig_y);
free_aligned_buffer_page_end(dst_c);
free_aligned_buffer_page_end(dst_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, CopyPlane_16_Any) {
int max_diff = TestCopyPlane_16(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, CopyPlane_16_Unaligned) {
int max_diff = TestCopyPlane_16(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 1);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, CopyPlane_16_Invert) {
int max_diff = TestCopyPlane_16(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, -1, 0);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, CopyPlane_16_Opt) {
int max_diff = TestCopyPlane_16(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, TestDetilePlane) {
int i, j;
@ -2417,7 +2521,7 @@ TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlurSmall_Opt)) {
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, DISABLED_ARM(TestARGBPolynomial)) {
TEST_F(LibYUVPlanarTest, TestARGBPolynomial) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
SIMD_ALIGNED(uint8_t dst_pixels_opt[1280][4]);
SIMD_ALIGNED(uint8_t dst_pixels_c[1280][4]);