libyuv/unit_test/planar_test.cc
Frank Barchard d5b76112f8 [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        arm     x86        riscv wasm     loongson hexagon
------------------------------------------------------------------------
AB64ToARGBRow_C       NEON    AVX2       RVV   -        -        HVX
ABGRToAR30Row_C       NEON    AVX512BW   -     -        -        -
AR30ToAB30Row_C       NEON    AVX512BW   -     -        -        -
AR30ToABGRRow_C       NEON    AVX512BW   -     -        -        -
AR30ToARGBRow_C       NEON    AVX512BW   -     -        -        -
AR64ShuffleRow_C      NEON    AVX512BW   RVV   WASMSIMD -        -
AR64ToAB64Row_C       NEON    AVX512BW   RVV   WASMSIMD -        HVX
AR64ToARGBRow_C       NEON    AVX2       RVV   -        -        HVX
ARGB1555ToARGBRow_C   SVE2    AVX2       -     WASMSIMD LASX     -
ARGB1555ToUVMatrixRow_C NEON  AVX2       -     WASMSIMD -        -
ARGB1555ToUVRow_C     NEON    -          -     -        LASX     -
ARGB1555ToYMatrixRow_C NEON   AVX2       -     WASMSIMD -        -
ARGB1555ToYRow_C      NEON    -          -     -        LASX     -
ARGB4444ToARGBRow_C   NEON    AVX2       -     WASMSIMD LASX     -
ARGB4444ToUVMatrixRow_C NEON  AVX2       -     WASMSIMD -        -
ARGB4444ToUVRow_C     NEON    -          -     -        -        -
ARGB4444ToYMatrixRow_C NEON   AVX2       -     WASMSIMD -        -
ARGB4444ToYRow_C      NEON    -          -     -        -        -
ARGBAddRow_C          NEON    AVX2       -     -        LASX     HVX
ARGBAffineRow_C       NEON    SSE2       -     -        -        -
ARGBAlphaBlendRow_C   SME     AVX512BW   RVV   WASMSIMD LASX     HVX
ARGBAttenuateRow_C    NEON    AVX512BW   RVV   -        LASX     HVX
ARGBBlendRow_C        NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
ARGBColorMatrixRow_C  I8MM    SSSE3      -     -        LASX     -
ARGBColorTableRow_C   NEON    X86        -     -        -        -
ARGBCopyAlphaRow_C    NEON    AVX2       -     -        -        HVX
ARGBCopyYToAlphaRow_C NEON    AVX512BW   RVV   WASMSIMD -        HVX
ARGBExtractAlphaRow_C NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
ARGBGrayRow_C         DOTPROD AVX512VNNI -     -        LASX     -
ARGBLumaColorTableRow_C NEON  SSSE3      -     -        -        -
ARGBMirrorRow_C       NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
ARGBMultiplyRow_C     SME     AVX512BW   RVV   -        LASX     HVX
ARGBOrRow_C           SME     AVX512BW   RVV   WASMSIMD LASX     HVX
ARGBPolynomialRow_C   NEON    AVX2       -     -        -        -
ARGBQuantizeRow_C     NEON    SSE2       -     -        LASX     -
ARGBSepiaRow_C        DOTPROD SSSE3      -     -        LASX     -
ARGBSetRow_C          NEON    X86        RVV   -        LASX     HVX
ARGBShadeRow_C        NEON    SSE2       -     -        LASX     -
ARGBShuffleRow_C      NEON    AVX512BW   RVV   WASMSIMD LASX     -
ARGBSubtractRow_C     NEON    AVX2       -     -        LASX     HVX
ARGBToAB64Row_C       NEON    AVX2       RVV   -        -        HVX
ARGBToABGRRow_C       NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
ARGBToAR30Row_C       NEON    AVX512BW   -     -        -        -
ARGBToAR64Row_C       NEON    AVX2       RVV   -        -        HVX
ARGBToARGB1555Row_C   NEON    AVX2       -     WASMSIMD LASX     -
ARGBToARGB4444Row_C   NEON    AVX2       -     WASMSIMD LASX     -
ARGBToBGRARow_C       NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
ARGBToRAWRow_C        SVE2    AVX512BW   RVV   -        LASX     -
ARGBToRGB24Row_C      SVE2    AVX512BW   RVV   -        LASX     -
ARGBToRGB565DitherRow_C SVE2  AVX2       -     WASMSIMD LASX     -
ARGBToRGB565Row_C     SVE2    AVX2       -     WASMSIMD LASX     -
ARGBToRGBARow_C       NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
ARGBToUV444MatrixRow_C I8MM   AVX512VNNI RVV   WASMSIMD -        HVX
ARGBToUVMatrixRow_C   SME     AVX512VNNI RVV   WASMSIMD -        HVX
ARGBToYMatrixRow_C    SME     AVX512VNNI RVV   WASMSIMD LASX     HVX
ARGBUnattenuateRow_C  NEON    AVX2       -     -        -        -
AYUVToUVRow_C         SVE2    AVX512VBMI -     -        -        -
AYUVToVURow_C         SVE2    AVX512VBMI -     -        -        -
AYUVToYRow_C          NEON    AVX512VBMI -     -        -        -
BlendPlaneRow_C       NEON    AVX512BW   RVV   WASMSIMD -        HVX
ByteToFloatRow_C      NEON    -          -     -        -        -
ComputeCumulativeSumRow_C NEON AVX2      -     -        -        -
Convert16To8Row_C     SME     AVX512BW   RVV   -        -        HVX
Convert8To16Row_C     SME     AVX512BW   RVV   WASMSIMD -        HVX
Convert8To8Row_C      SME     AVX2       -     -        -        HVX
CopyRow_C             SME     AVX512BW   RVV   -        LASX     HVX
CopyRow_16_C          NEON    -          -     -        -        HVX
CumulativeSumToAverageRow_C NEON AVX2    -     -        -        -
DetileRow_C           NEON    SSE2       -     -        -        -
DetileRow_16_C        NEON    AVX        -     -        -        -
DetileSplitUVRow_C    NEON    SSSE3      -     -        -        -
DivideRow_16_C        SVE2    AVX2       -     -        -        HVX
GaussRow_C            NEON    -          -     -        -        -
GaussRow_F32_C        NEON    -          -     -        -        -
HalfFloatRow_C        SVE2    AVX2       -     -        LASX     -
HalfMergeUVRow_C      SVE2    AVX512BW   -     -        -        -
HalfRow_16To8_C       SME     AVX512BW   RVV   -        -        HVX
HalfWidthRow_16To8_C  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       SME     AVX512BW   RVV   -        LASX     HVX
I410AlphaToARGBRow_C  SME     AVX2       -     -        -        -
I410ToAR30Row_C       SME     AVX2       -     -        -        -
I410ToARGBRow_C       SME     AVX2       -     -        -        -
I422AlphaToARGBRow_C  SME     AVX512BW   RVV   -        LASX     HVX
I422ToAR30Row_C       SME     AVX512BW   RVV   WASMSIMD -        -
I422ToARGB1555Row_C   SME     AVX2       -     WASMSIMD LASX     -
I422ToARGB4444Row_C   SME     AVX2       -     WASMSIMD LASX     -
I422ToARGBRow_C       SME     AVX512BW   RVV   WASMSIMD LASX     HVX
I422ToRGB24Row_C      SME     AVX512VBMI RVV   WASMSIMD LASX     -
I422ToRGB565Row_C     SME     AVX2       -     WASMSIMD LASX     -
I422ToRGBARow_C       SME     AVX2       RVV   -        LASX     HVX
I422ToUYVYRow_C       NEON    AVX2       -     -        LASX     -
I422ToYUY2Row_C       NEON    AVX2       -     -        LASX     -
I444AlphaToARGBRow_C  SME     AVX2       RVV   -        -        HVX
I444ToARGBRow_C       SME     AVX2       RVV   -        LASX     HVX
I444ToRGB24Row_C      SME     AVX2       RVV   -        -        -
InterpolateRow_C      SME     AVX512BW   RVV   WASMSIMD LASX     HVX
InterpolateRow_16_C   SME     AVX512BW   -     WASMSIMD -        HVX
J400ToARGBRow_C       NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
MergeAR64Row_C        NEON    AVX2       -     -        -        -
MergeARGB16To8Row_C   NEON    AVX2       -     -        -        -
MergeARGBRow_C        NEON    AVX2       RVV   -        -        HVX
MergeRGBRow_C         NEON    AVX512VBMI RVV   -        -        -
MergeUVRow_C          SME     AVX512BW   RVV   WASMSIMD LASX     HVX
MergeUVRow_16_C       SME     AVX2       -     -        -        HVX
MergeXR30Row_C        NEON    AVX512BW   -     -        -        -
MergeXR64Row_C        NEON    AVX2       -     -        -        -
MergeXRGB16To8Row_C   NEON    AVX2       -     -        -        -
MergeXRGBRow_C        NEON    AVX2       RVV   -        -        HVX
MirrorRow_C           NEON    AVX512BW   -     WASMSIMD LASX     HVX
MirrorRow_16_C        NEON    AVX512BW   -     -        -        HVX
MirrorSplitUVRow_C    NEON    AVX512BW   -     WASMSIMD LASX     HVX
MirrorUVRow_C         NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
MultiplyRow_16_C      SME     AVX512BW   RVV   WASMSIMD -        HVX
NV12ToARGBRow_C       SME     AVX512BW   RVV   WASMSIMD LASX     HVX
NV12ToRGB24Row_C      SME     AVX512VBMI RVV   -        -        -
NV12ToRGB565Row_C     NEON    AVX2       -     WASMSIMD LASX     -
NV21ToARGBRow_C       SME     AVX512BW   RVV   WASMSIMD LASX     HVX
NV21ToRGB24Row_C      SME     AVX512VBMI RVV   -        -        -
NV21ToYUV24Row_C      NEON    AVX2       -     -        -        -
P210ToAR30Row_C       SME     AVX2       -     -        -        -
P210ToARGBRow_C       SME     AVX2       -     -        -        -
P410ToAR30Row_C       SME     AVX2       -     -        -        -
P410ToARGBRow_C       SME     AVX2       -     -        -        -
RAWToARGBRow_C        SVE2    AVX512BW   RVV   WASMSIMD LASX     -
RAWToRGB24Row_C       SVE2    AVX512VBMI RVV   WASMSIMD LASX     -
RAWToRGBARow_C        SVE2    AVX512VBMI RVV   -        -        -
RGB24MirrorRow_C      NEON    AVX512VBMI -     WASMSIMD -        -
RGB24ToARGBRow_C      SVE2    AVX512BW   RVV   WASMSIMD LASX     -
RGB565ToARGBRow_C     NEON    AVX2       -     WASMSIMD LASX     -
RGB565ToUVMatrixRow_C NEON    AVX2       -     WASMSIMD -        -
RGB565ToUVRow_C       NEON    -          -     -        LASX     -
RGB565ToYMatrixRow_C  NEON    AVX2       -     WASMSIMD -        -
RGB565ToYRow_C        NEON    -          -     -        LASX     -
RGBAToARGBRow_C       NEON    AVX512BW   RVV   WASMSIMD LASX     HVX
RGBColorTableRow_C    NEON    X86        -     -        -        -
RGBToUV444MatrixRow_C NEON    AVX512BW   RVV   WASMSIMD -        -
RGBToUVMatrixRow_C    NEON    AVX512BW   RVV   WASMSIMD -        -
RGBToYMatrixRow_C     DOTPROD AVX512BW   RVV   WASMSIMD LASX     -
SetRow_C              NEON    ERMS       -     -        LASX     HVX
SobelRow_C            NEON    SSE2       -     -        LASX     -
SobelToPlaneRow_C     NEON    SSE2       -     -        LASX     -
SobelXRow_C           NEON    SSE2       -     -        -        -
SobelXYRow_C          NEON    SSE2       -     -        LASX     -
SobelYRow_C           NEON    SSE2       -     -        -        -
SplitARGBRow_C        NEON    AVX2       RVV   -        -        HVX
SplitRGBRow_C         NEON    AVX2       RVV   -        -        -
SplitUVRow_C          SVE2    AVX512BW   RVV   -        LASX     HVX
SplitUVRow_16_C       NEON    AVX2       -     -        -        HVX
SplitXRGBRow_C        NEON    AVX2       RVV   -        -        HVX
SwapUVRow_C           NEON    AVX512BW   RVV   WASMSIMD -        HVX
UYVYToARGBRow_C       SME     AVX2       -     -        LASX     -
UYVYToUV422Row_C      NEON    AVX2       -     -        LASX     HVX
UYVYToUVRow_C         SVE2    AVX2       -     -        LASX     HVX
UYVYToYRow_C          SVE2    AVX2       -     -        LASX     HVX
YUY2ToARGBRow_C       SME     AVX2       -     -        LASX     -
YUY2ToNVUVRow_C       NEON    AVX2       -     -        -        -
YUY2ToUV422Row_C      NEON    AVX2       -     -        LASX     HVX
YUY2ToUVRow_C         SVE2    AVX2       -     -        LASX     HVX
YUY2ToYRow_C          SVE2    AVX2       -     -        LASX     HVX
------------------------------------------------------------------------
SIMD (164/164 100%)   164 100% 154 94%   64 39% 56 34%   73 45%   64 39%
------------------------------------------------------------------------

Test: libyuv_unittest --gtest_filter=*AR30*:*Affine*:*ColorTable*:*CopyAlpha*:*Polynomial*:*Unattenuate*:*MirrorPlane_16*
Bug: None
Change-Id: Ib8b68beb77b47de6b996d41fd080397c61539ffb
2026-10-27 14:38:21 -07:00

5291 lines
195 KiB
C++

/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include "../unit_test/unit_test.h"
#include "libyuv/compare.h"
#include "libyuv/convert.h"
#include "libyuv/convert_argb.h"
#include "libyuv/convert_from.h"
#include "libyuv/convert_from_argb.h"
#include "libyuv/cpu_id.h"
#include "libyuv/planar_functions.h"
#include "libyuv/rotate.h"
#include "libyuv/scale.h"
#ifdef ENABLE_ROW_TESTS
// row.h defines SIMD_ALIGNED, overriding unit_test.h
// TODO(fbarchard): Remove row.h from unittests. Test public functions.
#include "libyuv/row.h" /* For ScaleSumSamples_Neon */
#endif
#define EXPECTED_UNATTENUATE_DIFF 0
namespace libyuv {
TEST_F(LibYUVPlanarTest, TestAttenuate) {
const int kSize = 1280 * 4;
align_buffer_page_end(orig_pixels, kSize);
align_buffer_page_end(atten_pixels, kSize);
align_buffer_page_end(unatten_pixels, kSize);
align_buffer_page_end(atten2_pixels, kSize);
// Test unattenuation clamps
orig_pixels[0 * 4 + 0] = 200u;
orig_pixels[0 * 4 + 1] = 129u;
orig_pixels[0 * 4 + 2] = 127u;
orig_pixels[0 * 4 + 3] = 128u;
// Test unattenuation transparent and opaque are unaffected
orig_pixels[1 * 4 + 0] = 16u;
orig_pixels[1 * 4 + 1] = 64u;
orig_pixels[1 * 4 + 2] = 192u;
orig_pixels[1 * 4 + 3] = 0u;
orig_pixels[2 * 4 + 0] = 16u;
orig_pixels[2 * 4 + 1] = 64u;
orig_pixels[2 * 4 + 2] = 192u;
orig_pixels[2 * 4 + 3] = 128u;
orig_pixels[3 * 4 + 0] = 16u;
orig_pixels[3 * 4 + 1] = 64u;
orig_pixels[3 * 4 + 2] = 192u;
orig_pixels[3 * 4 + 3] = 255u;
orig_pixels[4 * 4 + 0] = 255u;
orig_pixels[4 * 4 + 1] = 255u;
orig_pixels[4 * 4 + 2] = 255u;
orig_pixels[4 * 4 + 3] = 255u;
ARGBUnattenuate(orig_pixels, 0, unatten_pixels, 0, 5, 1);
ASSERT_EQ(255u, unatten_pixels[0 * 4 + 0]);
ASSERT_EQ(255u, unatten_pixels[0 * 4 + 1]);
ASSERT_EQ(254u, unatten_pixels[0 * 4 + 2]);
ASSERT_EQ(128u, unatten_pixels[0 * 4 + 3]);
ASSERT_EQ(0u, unatten_pixels[1 * 4 + 0]);
ASSERT_EQ(0u, unatten_pixels[1 * 4 + 1]);
ASSERT_EQ(0u, unatten_pixels[1 * 4 + 2]);
ASSERT_EQ(0u, unatten_pixels[1 * 4 + 3]);
ASSERT_EQ(32u, unatten_pixels[2 * 4 + 0]);
ASSERT_EQ(128u, unatten_pixels[2 * 4 + 1]);
ASSERT_EQ(255u, unatten_pixels[2 * 4 + 2]);
ASSERT_EQ(128u, unatten_pixels[2 * 4 + 3]);
ASSERT_EQ(16u, unatten_pixels[3 * 4 + 0]);
ASSERT_EQ(64u, unatten_pixels[3 * 4 + 1]);
ASSERT_EQ(192u, unatten_pixels[3 * 4 + 2]);
ASSERT_EQ(255u, unatten_pixels[3 * 4 + 3]);
ASSERT_EQ(255u, unatten_pixels[4 * 4 + 0]);
ASSERT_EQ(255u, unatten_pixels[4 * 4 + 1]);
ASSERT_EQ(255u, unatten_pixels[4 * 4 + 2]);
ASSERT_EQ(255u, unatten_pixels[4 * 4 + 3]);
ARGBAttenuate(orig_pixels, 0, atten_pixels, 0, 5, 1);
ASSERT_EQ(100u, atten_pixels[0 * 4 + 0]);
ASSERT_EQ(65u, atten_pixels[0 * 4 + 1]);
ASSERT_EQ(64u, atten_pixels[0 * 4 + 2]);
ASSERT_EQ(128u, atten_pixels[0 * 4 + 3]);
ASSERT_EQ(0u, atten_pixels[1 * 4 + 0]);
ASSERT_EQ(0u, atten_pixels[1 * 4 + 1]);
ASSERT_EQ(0u, atten_pixels[1 * 4 + 2]);
ASSERT_EQ(0u, atten_pixels[1 * 4 + 3]);
ASSERT_EQ(8u, atten_pixels[2 * 4 + 0]);
ASSERT_EQ(32u, atten_pixels[2 * 4 + 1]);
ASSERT_EQ(96u, atten_pixels[2 * 4 + 2]);
ASSERT_EQ(128u, atten_pixels[2 * 4 + 3]);
ASSERT_EQ(16u, atten_pixels[3 * 4 + 0]);
ASSERT_EQ(64u, atten_pixels[3 * 4 + 1]);
ASSERT_EQ(192u, atten_pixels[3 * 4 + 2]);
ASSERT_EQ(255u, atten_pixels[3 * 4 + 3]);
ASSERT_EQ(255u, atten_pixels[4 * 4 + 0]);
ASSERT_EQ(255u, atten_pixels[4 * 4 + 1]);
ASSERT_EQ(255u, atten_pixels[4 * 4 + 2]);
ASSERT_EQ(255u, atten_pixels[4 * 4 + 3]);
// test 255
for (int i = 0; i < 256; ++i) {
orig_pixels[i * 4 + 0] = i;
orig_pixels[i * 4 + 1] = 0;
orig_pixels[i * 4 + 2] = 0;
orig_pixels[i * 4 + 3] = 255;
}
ARGBAttenuate(orig_pixels, 0, atten_pixels, 0, 256, 1);
for (int i = 0; i < 256; ++i) {
ASSERT_EQ(orig_pixels[i * 4 + 0], atten_pixels[i * 4 + 0]);
ASSERT_EQ(0, atten_pixels[i * 4 + 1]);
ASSERT_EQ(0, atten_pixels[i * 4 + 2]);
ASSERT_EQ(255, atten_pixels[i * 4 + 3]);
}
for (int i = 0; i < 1280; ++i) {
orig_pixels[i * 4 + 0] = i;
orig_pixels[i * 4 + 1] = i / 2;
orig_pixels[i * 4 + 2] = i / 3;
orig_pixels[i * 4 + 3] = i;
}
ARGBAttenuate(orig_pixels, 0, atten_pixels, 0, 1280, 1);
ARGBUnattenuate(atten_pixels, 0, unatten_pixels, 0, 1280, 1);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBAttenuate(unatten_pixels, 0, atten2_pixels, 0, 1280, 1);
}
for (int i = 0; i < 1280; ++i) {
ASSERT_NEAR(atten_pixels[i * 4 + 0], atten2_pixels[i * 4 + 0], 1);
ASSERT_NEAR(atten_pixels[i * 4 + 1], atten2_pixels[i * 4 + 1], 1);
ASSERT_NEAR(atten_pixels[i * 4 + 2], atten2_pixels[i * 4 + 2], 1);
ASSERT_NEAR(atten_pixels[i * 4 + 3], atten2_pixels[i * 4 + 3], 1);
}
// Make sure transparent, 50% and opaque are fully accurate.
ASSERT_EQ(0, atten_pixels[0 * 4 + 0]);
ASSERT_EQ(0, atten_pixels[0 * 4 + 1]);
ASSERT_EQ(0, atten_pixels[0 * 4 + 2]);
ASSERT_EQ(0, atten_pixels[0 * 4 + 3]);
ASSERT_EQ(64, atten_pixels[128 * 4 + 0]);
ASSERT_EQ(32, atten_pixels[128 * 4 + 1]);
ASSERT_EQ(21, atten_pixels[128 * 4 + 2]);
ASSERT_EQ(128, atten_pixels[128 * 4 + 3]);
ASSERT_EQ(255, atten_pixels[255 * 4 + 0]);
ASSERT_EQ(127, atten_pixels[255 * 4 + 1]);
ASSERT_EQ(85, atten_pixels[255 * 4 + 2]);
ASSERT_EQ(255, atten_pixels[255 * 4 + 3]);
free_aligned_buffer_page_end(atten2_pixels);
free_aligned_buffer_page_end(unatten_pixels);
free_aligned_buffer_page_end(atten_pixels);
free_aligned_buffer_page_end(orig_pixels);
}
static int TestAttenuateI(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb, (size_t)kStride * height + off);
align_buffer_page_end(dst_argb_c, (size_t)kStride * height);
align_buffer_page_end(dst_argb_opt, (size_t)kStride * height);
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
src_argb[i + off] = (fastrand() & 0xff);
}
memset(dst_argb_c, 0, (size_t)kStride * height);
memset(dst_argb_opt, 0, (size_t)kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBAttenuate(src_argb + off, kStride, dst_argb_c, kStride, width,
invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBAttenuate(src_argb + off, kStride, dst_argb_opt, kStride, width,
invert * height);
}
int max_diff = 0;
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBAttenuate_Any) {
int max_diff = TestAttenuateI(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_EQ(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBAttenuate_Unaligned) {
int max_diff =
TestAttenuateI(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
ASSERT_EQ(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBAttenuate_Invert) {
int max_diff =
TestAttenuateI(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
ASSERT_EQ(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBAttenuate_Opt) {
int max_diff =
TestAttenuateI(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_EQ(max_diff, 0);
}
static int TestUnattenuateI(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb, (size_t)kStride * height + off);
align_buffer_page_end(dst_argb_c, (size_t)kStride * height);
align_buffer_page_end(dst_argb_opt, (size_t)kStride * height);
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
src_argb[i + off] = (fastrand() & 0xff);
}
ARGBAttenuate(src_argb + off, kStride, src_argb + off, kStride, width,
height);
memset(dst_argb_c, 0, (size_t)kStride * height);
memset(dst_argb_opt, 0, (size_t)kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBUnattenuate(src_argb + off, kStride, dst_argb_c, kStride, width,
invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBUnattenuate(src_argb + off, kStride, dst_argb_opt, kStride, width,
invert * height);
}
int max_diff = 0;
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBUnattenuate_Any) {
int max_diff = TestUnattenuateI(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_EQ(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBUnattenuate_Unaligned) {
int max_diff = TestUnattenuateI(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 1);
ASSERT_EQ(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBUnattenuate_Invert) {
int max_diff = TestUnattenuateI(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, -1, 0);
ASSERT_EQ(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBUnattenuate_Opt) {
int max_diff = TestUnattenuateI(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_EQ(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, TestARGBComputeCumulativeSum) {
SIMD_ALIGNED(uint8_t orig_pixels[16][16][4]);
SIMD_ALIGNED(int32_t added_pixels[16][16][4]);
for (int y = 0; y < 16; ++y) {
for (int x = 0; x < 16; ++x) {
orig_pixels[y][x][0] = 1u;
orig_pixels[y][x][1] = 2u;
orig_pixels[y][x][2] = 3u;
orig_pixels[y][x][3] = 255u;
}
}
ARGBComputeCumulativeSum(&orig_pixels[0][0][0], 16 * 4,
&added_pixels[0][0][0], 16 * 4, 16, 16);
for (int y = 0; y < 16; ++y) {
for (int x = 0; x < 16; ++x) {
ASSERT_EQ((x + 1) * (y + 1), added_pixels[y][x][0]);
ASSERT_EQ((x + 1) * (y + 1) * 2, added_pixels[y][x][1]);
ASSERT_EQ((x + 1) * (y + 1) * 3, added_pixels[y][x][2]);
ASSERT_EQ((x + 1) * (y + 1) * 255, added_pixels[y][x][3]);
}
}
}
// near is for legacy platforms.
TEST_F(LibYUVPlanarTest, TestARGBGray) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
memset(orig_pixels, 0, sizeof(orig_pixels));
// Test blue
orig_pixels[0][0] = 255u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 128u;
// Test green
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 255u;
orig_pixels[1][2] = 0u;
orig_pixels[1][3] = 0u;
// Test red
orig_pixels[2][0] = 0u;
orig_pixels[2][1] = 0u;
orig_pixels[2][2] = 255u;
orig_pixels[2][3] = 255u;
// Test black
orig_pixels[3][0] = 0u;
orig_pixels[3][1] = 0u;
orig_pixels[3][2] = 0u;
orig_pixels[3][3] = 255u;
// Test white
orig_pixels[4][0] = 255u;
orig_pixels[4][1] = 255u;
orig_pixels[4][2] = 255u;
orig_pixels[4][3] = 255u;
// Test color
orig_pixels[5][0] = 16u;
orig_pixels[5][1] = 64u;
orig_pixels[5][2] = 192u;
orig_pixels[5][3] = 224u;
// Do 16 to test asm version.
ARGBGray(&orig_pixels[0][0], 0, 0, 0, 16, 1);
ASSERT_NEAR(29u, orig_pixels[0][0], 1);
ASSERT_NEAR(29u, orig_pixels[0][1], 1);
ASSERT_NEAR(29u, orig_pixels[0][2], 1);
ASSERT_EQ(128u, orig_pixels[0][3]);
ASSERT_EQ(149u, orig_pixels[1][0]);
ASSERT_EQ(149u, orig_pixels[1][1]);
ASSERT_EQ(149u, orig_pixels[1][2]);
ASSERT_EQ(0u, orig_pixels[1][3]);
ASSERT_NEAR(77u, orig_pixels[2][0], 1);
ASSERT_NEAR(77u, orig_pixels[2][1], 1);
ASSERT_NEAR(77u, orig_pixels[2][2], 1);
ASSERT_EQ(255u, orig_pixels[2][3]);
ASSERT_EQ(0u, orig_pixels[3][0]);
ASSERT_EQ(0u, orig_pixels[3][1]);
ASSERT_EQ(0u, orig_pixels[3][2]);
ASSERT_EQ(255u, orig_pixels[3][3]);
ASSERT_EQ(255u, orig_pixels[4][0]);
ASSERT_EQ(255u, orig_pixels[4][1]);
ASSERT_EQ(255u, orig_pixels[4][2]);
ASSERT_EQ(255u, orig_pixels[4][3]);
ASSERT_NEAR(97u, orig_pixels[5][0], 1);
ASSERT_NEAR(97u, orig_pixels[5][1], 1);
ASSERT_NEAR(97u, orig_pixels[5][2], 1);
ASSERT_EQ(224u, orig_pixels[5][3]);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBGray(&orig_pixels[0][0], 0, 0, 0, 1280, 1);
}
}
TEST_F(LibYUVPlanarTest, TestARGBGrayTo) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
SIMD_ALIGNED(uint8_t gray_pixels[1280][4]);
memset(orig_pixels, 0, sizeof(orig_pixels));
// Test blue
orig_pixels[0][0] = 255u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 128u;
// Test green
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 255u;
orig_pixels[1][2] = 0u;
orig_pixels[1][3] = 0u;
// Test red
orig_pixels[2][0] = 0u;
orig_pixels[2][1] = 0u;
orig_pixels[2][2] = 255u;
orig_pixels[2][3] = 255u;
// Test black
orig_pixels[3][0] = 0u;
orig_pixels[3][1] = 0u;
orig_pixels[3][2] = 0u;
orig_pixels[3][3] = 255u;
// Test white
orig_pixels[4][0] = 255u;
orig_pixels[4][1] = 255u;
orig_pixels[4][2] = 255u;
orig_pixels[4][3] = 255u;
// Test color
orig_pixels[5][0] = 16u;
orig_pixels[5][1] = 64u;
orig_pixels[5][2] = 192u;
orig_pixels[5][3] = 224u;
// Do 16 to test asm version.
ARGBGrayTo(&orig_pixels[0][0], 0, &gray_pixels[0][0], 0, 16, 1);
ASSERT_NEAR(30u, gray_pixels[0][0], 1);
ASSERT_NEAR(30u, gray_pixels[0][1], 1);
ASSERT_NEAR(30u, gray_pixels[0][2], 1);
ASSERT_NEAR(128u, gray_pixels[0][3], 1);
ASSERT_NEAR(149u, gray_pixels[1][0], 1);
ASSERT_NEAR(149u, gray_pixels[1][1], 1);
ASSERT_NEAR(149u, gray_pixels[1][2], 1);
ASSERT_NEAR(0u, gray_pixels[1][3], 1);
ASSERT_NEAR(76u, gray_pixels[2][0], 1);
ASSERT_NEAR(76u, gray_pixels[2][1], 1);
ASSERT_NEAR(76u, gray_pixels[2][2], 1);
ASSERT_NEAR(255u, gray_pixels[2][3], 1);
ASSERT_NEAR(0u, gray_pixels[3][0], 1);
ASSERT_NEAR(0u, gray_pixels[3][1], 1);
ASSERT_NEAR(0u, gray_pixels[3][2], 1);
ASSERT_NEAR(255u, gray_pixels[3][3], 1);
ASSERT_NEAR(255u, gray_pixels[4][0], 1);
ASSERT_NEAR(255u, gray_pixels[4][1], 1);
ASSERT_NEAR(255u, gray_pixels[4][2], 1);
ASSERT_NEAR(255u, gray_pixels[4][3], 1);
ASSERT_NEAR(96u, gray_pixels[5][0], 1);
ASSERT_NEAR(96u, gray_pixels[5][1], 1);
ASSERT_NEAR(96u, gray_pixels[5][2], 1);
ASSERT_NEAR(224u, gray_pixels[5][3], 1);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBGrayTo(&orig_pixels[0][0], 0, &gray_pixels[0][0], 0, 1280, 1);
}
for (int i = 0; i < 256; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i;
orig_pixels[i][2] = i;
orig_pixels[i][3] = i;
}
ARGBGray(&orig_pixels[0][0], 0, 0, 0, 256, 1);
for (int i = 0; i < 256; ++i) {
ASSERT_EQ(i, orig_pixels[i][0]);
ASSERT_EQ(i, orig_pixels[i][1]);
ASSERT_EQ(i, orig_pixels[i][2]);
ASSERT_EQ(i, orig_pixels[i][3]);
}
}
TEST_F(LibYUVPlanarTest, TestARGBSepia) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
memset(orig_pixels, 0, sizeof(orig_pixels));
// Test blue
orig_pixels[0][0] = 255u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 128u;
// Test green
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 255u;
orig_pixels[1][2] = 0u;
orig_pixels[1][3] = 0u;
// Test red
orig_pixels[2][0] = 0u;
orig_pixels[2][1] = 0u;
orig_pixels[2][2] = 255u;
orig_pixels[2][3] = 255u;
// Test black
orig_pixels[3][0] = 0u;
orig_pixels[3][1] = 0u;
orig_pixels[3][2] = 0u;
orig_pixels[3][3] = 255u;
// Test white
orig_pixels[4][0] = 255u;
orig_pixels[4][1] = 255u;
orig_pixels[4][2] = 255u;
orig_pixels[4][3] = 255u;
// Test color
orig_pixels[5][0] = 16u;
orig_pixels[5][1] = 64u;
orig_pixels[5][2] = 192u;
orig_pixels[5][3] = 224u;
// Do 16 to test asm version.
ARGBSepia(&orig_pixels[0][0], 0, 0, 0, 16, 1);
ASSERT_EQ(33u, orig_pixels[0][0]);
ASSERT_EQ(43u, orig_pixels[0][1]);
ASSERT_EQ(47u, orig_pixels[0][2]);
ASSERT_EQ(128u, orig_pixels[0][3]);
ASSERT_EQ(135u, orig_pixels[1][0]);
ASSERT_EQ(175u, orig_pixels[1][1]);
ASSERT_EQ(195u, orig_pixels[1][2]);
ASSERT_EQ(0u, orig_pixels[1][3]);
ASSERT_EQ(69u, orig_pixels[2][0]);
ASSERT_EQ(89u, orig_pixels[2][1]);
ASSERT_EQ(99u, orig_pixels[2][2]);
ASSERT_EQ(255u, orig_pixels[2][3]);
ASSERT_EQ(0u, orig_pixels[3][0]);
ASSERT_EQ(0u, orig_pixels[3][1]);
ASSERT_EQ(0u, orig_pixels[3][2]);
ASSERT_EQ(255u, orig_pixels[3][3]);
ASSERT_EQ(239u, orig_pixels[4][0]);
ASSERT_EQ(255u, orig_pixels[4][1]);
ASSERT_EQ(255u, orig_pixels[4][2]);
ASSERT_EQ(255u, orig_pixels[4][3]);
ASSERT_EQ(88u, orig_pixels[5][0]);
ASSERT_EQ(114u, orig_pixels[5][1]);
ASSERT_EQ(127u, orig_pixels[5][2]);
ASSERT_EQ(224u, orig_pixels[5][3]);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBSepia(&orig_pixels[0][0], 0, 0, 0, 1280, 1);
}
}
TEST_F(LibYUVPlanarTest, TestARGBColorMatrix) {
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]);
// Matrix for Sepia.
SIMD_ALIGNED(static const int8_t kRGBToSepia[]) = {
17 / 2, 68 / 2, 35 / 2, 0, 22 / 2, 88 / 2, 45 / 2, 0,
24 / 2, 98 / 2, 50 / 2, 0, 0, 0, 0, 64, // Copy alpha.
};
memset(orig_pixels, 0, sizeof(orig_pixels));
// Test blue
orig_pixels[0][0] = 255u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 128u;
// Test green
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 255u;
orig_pixels[1][2] = 0u;
orig_pixels[1][3] = 0u;
// Test red
orig_pixels[2][0] = 0u;
orig_pixels[2][1] = 0u;
orig_pixels[2][2] = 255u;
orig_pixels[2][3] = 255u;
// Test color
orig_pixels[3][0] = 16u;
orig_pixels[3][1] = 64u;
orig_pixels[3][2] = 192u;
orig_pixels[3][3] = 224u;
// Do 16 to test asm version.
ARGBColorMatrix(&orig_pixels[0][0], 0, &dst_pixels_opt[0][0], 0,
&kRGBToSepia[0], 16, 1);
ASSERT_EQ(31u, dst_pixels_opt[0][0]);
ASSERT_EQ(43u, dst_pixels_opt[0][1]);
ASSERT_EQ(47u, dst_pixels_opt[0][2]);
ASSERT_EQ(128u, dst_pixels_opt[0][3]);
ASSERT_EQ(135u, dst_pixels_opt[1][0]);
ASSERT_EQ(175u, dst_pixels_opt[1][1]);
ASSERT_EQ(195u, dst_pixels_opt[1][2]);
ASSERT_EQ(0u, dst_pixels_opt[1][3]);
ASSERT_EQ(67u, dst_pixels_opt[2][0]);
ASSERT_EQ(87u, dst_pixels_opt[2][1]);
ASSERT_EQ(99u, dst_pixels_opt[2][2]);
ASSERT_EQ(255u, dst_pixels_opt[2][3]);
ASSERT_EQ(87u, dst_pixels_opt[3][0]);
ASSERT_EQ(112u, dst_pixels_opt[3][1]);
ASSERT_EQ(127u, dst_pixels_opt[3][2]);
ASSERT_EQ(224u, dst_pixels_opt[3][3]);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
MaskCpuFlags(disable_cpu_flags_);
ARGBColorMatrix(&orig_pixels[0][0], 0, &dst_pixels_c[0][0], 0,
&kRGBToSepia[0], 1280, 1);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBColorMatrix(&orig_pixels[0][0], 0, &dst_pixels_opt[0][0], 0,
&kRGBToSepia[0], 1280, 1);
}
for (int i = 0; i < 1280; ++i) {
ASSERT_EQ(dst_pixels_c[i][0], dst_pixels_opt[i][0]);
ASSERT_EQ(dst_pixels_c[i][1], dst_pixels_opt[i][1]);
ASSERT_EQ(dst_pixels_c[i][2], dst_pixels_opt[i][2]);
ASSERT_EQ(dst_pixels_c[i][3], dst_pixels_opt[i][3]);
}
}
TEST_F(LibYUVPlanarTest, TestRGBColorMatrix) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
// Matrix for Sepia.
SIMD_ALIGNED(static const int8_t kRGBToSepia[]) = {
17, 68, 35, 0, 22, 88, 45, 0,
24, 98, 50, 0, 0, 0, 0, 0, // Unused but makes matrix 16 bytes.
};
memset(orig_pixels, 0, sizeof(orig_pixels));
// Test blue
orig_pixels[0][0] = 255u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 128u;
// Test green
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 255u;
orig_pixels[1][2] = 0u;
orig_pixels[1][3] = 0u;
// Test red
orig_pixels[2][0] = 0u;
orig_pixels[2][1] = 0u;
orig_pixels[2][2] = 255u;
orig_pixels[2][3] = 255u;
// Test color
orig_pixels[3][0] = 16u;
orig_pixels[3][1] = 64u;
orig_pixels[3][2] = 192u;
orig_pixels[3][3] = 224u;
// Do 16 to test asm version.
RGBColorMatrix(&orig_pixels[0][0], 0, &kRGBToSepia[0], 0, 0, 16, 1);
ASSERT_EQ(31u, orig_pixels[0][0]);
ASSERT_EQ(43u, orig_pixels[0][1]);
ASSERT_EQ(47u, orig_pixels[0][2]);
ASSERT_EQ(128u, orig_pixels[0][3]);
ASSERT_EQ(135u, orig_pixels[1][0]);
ASSERT_EQ(175u, orig_pixels[1][1]);
ASSERT_EQ(195u, orig_pixels[1][2]);
ASSERT_EQ(0u, orig_pixels[1][3]);
ASSERT_EQ(67u, orig_pixels[2][0]);
ASSERT_EQ(87u, orig_pixels[2][1]);
ASSERT_EQ(99u, orig_pixels[2][2]);
ASSERT_EQ(255u, orig_pixels[2][3]);
ASSERT_EQ(87u, orig_pixels[3][0]);
ASSERT_EQ(112u, orig_pixels[3][1]);
ASSERT_EQ(127u, orig_pixels[3][2]);
ASSERT_EQ(224u, orig_pixels[3][3]);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
RGBColorMatrix(&orig_pixels[0][0], 0, &kRGBToSepia[0], 0, 0, 1280, 1);
}
}
TEST_F(LibYUVPlanarTest, TestARGBColorTable) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
memset(orig_pixels, 0, sizeof(orig_pixels));
// Matrix for Sepia.
static const uint8_t kARGBTable[256 * 4] = {
1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u,
};
orig_pixels[0][0] = 0u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 0u;
orig_pixels[1][0] = 1u;
orig_pixels[1][1] = 1u;
orig_pixels[1][2] = 1u;
orig_pixels[1][3] = 1u;
orig_pixels[2][0] = 2u;
orig_pixels[2][1] = 2u;
orig_pixels[2][2] = 2u;
orig_pixels[2][3] = 2u;
orig_pixels[3][0] = 0u;
orig_pixels[3][1] = 1u;
orig_pixels[3][2] = 2u;
orig_pixels[3][3] = 3u;
// Do 16 to test asm version.
ARGBColorTable(&orig_pixels[0][0], 0, &kARGBTable[0], 0, 0, 16, 1);
ASSERT_EQ(1u, orig_pixels[0][0]);
ASSERT_EQ(2u, orig_pixels[0][1]);
ASSERT_EQ(3u, orig_pixels[0][2]);
ASSERT_EQ(4u, orig_pixels[0][3]);
ASSERT_EQ(5u, orig_pixels[1][0]);
ASSERT_EQ(6u, orig_pixels[1][1]);
ASSERT_EQ(7u, orig_pixels[1][2]);
ASSERT_EQ(8u, orig_pixels[1][3]);
ASSERT_EQ(9u, orig_pixels[2][0]);
ASSERT_EQ(10u, orig_pixels[2][1]);
ASSERT_EQ(11u, orig_pixels[2][2]);
ASSERT_EQ(12u, orig_pixels[2][3]);
ASSERT_EQ(1u, orig_pixels[3][0]);
ASSERT_EQ(6u, orig_pixels[3][1]);
ASSERT_EQ(11u, orig_pixels[3][2]);
ASSERT_EQ(16u, orig_pixels[3][3]);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBColorTable(&orig_pixels[0][0], 0, &kARGBTable[0], 0, 0, 1280, 1);
}
}
// Same as TestARGBColorTable except alpha does not change.
TEST_F(LibYUVPlanarTest, TestRGBColorTable) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
memset(orig_pixels, 0, sizeof(orig_pixels));
// Matrix for Sepia.
static const uint8_t kARGBTable[256 * 4] = {
1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u,
};
orig_pixels[0][0] = 0u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 0u;
orig_pixels[1][0] = 1u;
orig_pixels[1][1] = 1u;
orig_pixels[1][2] = 1u;
orig_pixels[1][3] = 1u;
orig_pixels[2][0] = 2u;
orig_pixels[2][1] = 2u;
orig_pixels[2][2] = 2u;
orig_pixels[2][3] = 2u;
orig_pixels[3][0] = 0u;
orig_pixels[3][1] = 1u;
orig_pixels[3][2] = 2u;
orig_pixels[3][3] = 3u;
// Do 16 to test asm version.
RGBColorTable(&orig_pixels[0][0], 0, &kARGBTable[0], 0, 0, 16, 1);
ASSERT_EQ(1u, orig_pixels[0][0]);
ASSERT_EQ(2u, orig_pixels[0][1]);
ASSERT_EQ(3u, orig_pixels[0][2]);
ASSERT_EQ(0u, orig_pixels[0][3]); // Alpha unchanged.
ASSERT_EQ(5u, orig_pixels[1][0]);
ASSERT_EQ(6u, orig_pixels[1][1]);
ASSERT_EQ(7u, orig_pixels[1][2]);
ASSERT_EQ(1u, orig_pixels[1][3]); // Alpha unchanged.
ASSERT_EQ(9u, orig_pixels[2][0]);
ASSERT_EQ(10u, orig_pixels[2][1]);
ASSERT_EQ(11u, orig_pixels[2][2]);
ASSERT_EQ(2u, orig_pixels[2][3]); // Alpha unchanged.
ASSERT_EQ(1u, orig_pixels[3][0]);
ASSERT_EQ(6u, orig_pixels[3][1]);
ASSERT_EQ(11u, orig_pixels[3][2]);
ASSERT_EQ(3u, orig_pixels[3][3]); // Alpha unchanged.
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
RGBColorTable(&orig_pixels[0][0], 0, &kARGBTable[0], 0, 0, 1280, 1);
}
}
TEST_F(LibYUVPlanarTest, TestARGBQuantize) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
ARGBQuantize(&orig_pixels[0][0], 0, (65536 + (8 / 2)) / 8, 8, 8 / 2, 0, 0,
1280, 1);
for (int i = 0; i < 1280; ++i) {
ASSERT_EQ((i / 8 * 8 + 8 / 2) & 255, orig_pixels[i][0]);
ASSERT_EQ((i / 2 / 8 * 8 + 8 / 2) & 255, orig_pixels[i][1]);
ASSERT_EQ((i / 3 / 8 * 8 + 8 / 2) & 255, orig_pixels[i][2]);
ASSERT_EQ(i & 255, orig_pixels[i][3]);
}
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBQuantize(&orig_pixels[0][0], 0, (65536 + (8 / 2)) / 8, 8, 8 / 2, 0, 0,
1280, 1);
}
}
TEST_F(LibYUVPlanarTest, ARGBMirror_Opt) {
align_buffer_page_end(src_pixels, benchmark_width_ * benchmark_height_ * 4);
align_buffer_page_end(dst_pixels_opt,
benchmark_width_ * benchmark_height_ * 4);
align_buffer_page_end(dst_pixels_c, benchmark_width_ * benchmark_height_ * 4);
MemRandomize(src_pixels, benchmark_width_ * benchmark_height_ * 4);
MaskCpuFlags(disable_cpu_flags_);
ARGBMirror(src_pixels, benchmark_width_ * 4, dst_pixels_c,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
ARGBMirror(src_pixels, benchmark_width_ * 4, dst_pixels_opt,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < benchmark_width_ * benchmark_height_ * 4; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(dst_pixels_c);
}
TEST_F(LibYUVPlanarTest, MirrorPlane_16_Opt) {
align_buffer_page_end(src_pixels_8, benchmark_width_ * benchmark_height_ * 2);
align_buffer_page_end(dst_pixels_opt_8,
benchmark_width_ * benchmark_height_ * 2);
align_buffer_page_end(dst_pixels_c_8,
benchmark_width_ * benchmark_height_ * 2);
uint16_t* src_pixels = reinterpret_cast<uint16_t*>(src_pixels_8);
uint16_t* dst_pixels_opt = reinterpret_cast<uint16_t*>(dst_pixels_opt_8);
uint16_t* dst_pixels_c = reinterpret_cast<uint16_t*>(dst_pixels_c_8);
MemRandomize(src_pixels_8, benchmark_width_ * benchmark_height_ * 2);
MaskCpuFlags(disable_cpu_flags_);
MirrorPlane_16(src_pixels, benchmark_width_, dst_pixels_c, benchmark_width_,
benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
MirrorPlane_16(src_pixels, benchmark_width_, dst_pixels_opt,
benchmark_width_, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels_8);
free_aligned_buffer_page_end(dst_pixels_opt_8);
free_aligned_buffer_page_end(dst_pixels_c_8);
}
TEST_F(LibYUVPlanarTest, MirrorPlane_Opt) {
align_buffer_page_end(src_pixels, benchmark_width_ * benchmark_height_);
align_buffer_page_end(dst_pixels_opt, benchmark_width_ * benchmark_height_);
align_buffer_page_end(dst_pixels_c, benchmark_width_ * benchmark_height_);
MemRandomize(src_pixels, benchmark_width_ * benchmark_height_);
MaskCpuFlags(disable_cpu_flags_);
MirrorPlane(src_pixels, benchmark_width_, dst_pixels_c, benchmark_width_,
benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
MirrorPlane(src_pixels, benchmark_width_, dst_pixels_opt, benchmark_width_,
benchmark_width_, benchmark_height_);
}
for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(dst_pixels_c);
}
TEST_F(LibYUVPlanarTest, MirrorUVPlane_Opt) {
align_buffer_page_end(src_pixels, benchmark_width_ * benchmark_height_ * 2);
align_buffer_page_end(dst_pixels_opt,
benchmark_width_ * benchmark_height_ * 2);
align_buffer_page_end(dst_pixels_c, benchmark_width_ * benchmark_height_ * 2);
MemRandomize(src_pixels, benchmark_width_ * benchmark_height_ * 2);
MaskCpuFlags(disable_cpu_flags_);
MirrorUVPlane(src_pixels, benchmark_width_ * 2, dst_pixels_c,
benchmark_width_ * 2, benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
MirrorUVPlane(src_pixels, benchmark_width_ * 2, dst_pixels_opt,
benchmark_width_ * 2, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < benchmark_width_ * benchmark_height_ * 2; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(dst_pixels_c);
}
TEST_F(LibYUVPlanarTest, TestShade) {
SIMD_ALIGNED(uint8_t orig_pixels[1280][4]);
SIMD_ALIGNED(uint8_t shade_pixels[1280][4]);
memset(orig_pixels, 0, sizeof(orig_pixels));
orig_pixels[0][0] = 10u;
orig_pixels[0][1] = 20u;
orig_pixels[0][2] = 40u;
orig_pixels[0][3] = 80u;
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 0u;
orig_pixels[1][2] = 0u;
orig_pixels[1][3] = 255u;
orig_pixels[2][0] = 0u;
orig_pixels[2][1] = 0u;
orig_pixels[2][2] = 0u;
orig_pixels[2][3] = 0u;
orig_pixels[3][0] = 0u;
orig_pixels[3][1] = 0u;
orig_pixels[3][2] = 0u;
orig_pixels[3][3] = 0u;
// Do 8 pixels to allow opt version to be used.
ARGBShade(&orig_pixels[0][0], 0, &shade_pixels[0][0], 0, 8, 1, 0x80ffffff);
ASSERT_EQ(10u, shade_pixels[0][0]);
ASSERT_EQ(20u, shade_pixels[0][1]);
ASSERT_EQ(40u, shade_pixels[0][2]);
ASSERT_EQ(40u, shade_pixels[0][3]);
ASSERT_EQ(0u, shade_pixels[1][0]);
ASSERT_EQ(0u, shade_pixels[1][1]);
ASSERT_EQ(0u, shade_pixels[1][2]);
ASSERT_EQ(128u, shade_pixels[1][3]);
ASSERT_EQ(0u, shade_pixels[2][0]);
ASSERT_EQ(0u, shade_pixels[2][1]);
ASSERT_EQ(0u, shade_pixels[2][2]);
ASSERT_EQ(0u, shade_pixels[2][3]);
ASSERT_EQ(0u, shade_pixels[3][0]);
ASSERT_EQ(0u, shade_pixels[3][1]);
ASSERT_EQ(0u, shade_pixels[3][2]);
ASSERT_EQ(0u, shade_pixels[3][3]);
ARGBShade(&orig_pixels[0][0], 0, &shade_pixels[0][0], 0, 8, 1, 0x80808080);
ASSERT_EQ(5u, shade_pixels[0][0]);
ASSERT_EQ(10u, shade_pixels[0][1]);
ASSERT_EQ(20u, shade_pixels[0][2]);
ASSERT_EQ(40u, shade_pixels[0][3]);
ARGBShade(&orig_pixels[0][0], 0, &shade_pixels[0][0], 0, 8, 1, 0x10204080);
ASSERT_EQ(5u, shade_pixels[0][0]);
ASSERT_EQ(5u, shade_pixels[0][1]);
ASSERT_EQ(5u, shade_pixels[0][2]);
ASSERT_EQ(5u, shade_pixels[0][3]);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBShade(&orig_pixels[0][0], 0, &shade_pixels[0][0], 0, 1280, 1,
0x80808080);
}
}
TEST_F(LibYUVPlanarTest, TestARGBInterpolate) {
SIMD_ALIGNED(uint8_t orig_pixels_0[1280][4]);
SIMD_ALIGNED(uint8_t orig_pixels_1[1280][4]);
SIMD_ALIGNED(uint8_t interpolate_pixels[1280][4]);
memset(orig_pixels_0, 0, sizeof(orig_pixels_0));
memset(orig_pixels_1, 0, sizeof(orig_pixels_1));
orig_pixels_0[0][0] = 16u;
orig_pixels_0[0][1] = 32u;
orig_pixels_0[0][2] = 64u;
orig_pixels_0[0][3] = 128u;
orig_pixels_0[1][0] = 0u;
orig_pixels_0[1][1] = 0u;
orig_pixels_0[1][2] = 0u;
orig_pixels_0[1][3] = 255u;
orig_pixels_0[2][0] = 0u;
orig_pixels_0[2][1] = 0u;
orig_pixels_0[2][2] = 0u;
orig_pixels_0[2][3] = 0u;
orig_pixels_0[3][0] = 0u;
orig_pixels_0[3][1] = 0u;
orig_pixels_0[3][2] = 0u;
orig_pixels_0[3][3] = 0u;
orig_pixels_1[0][0] = 0u;
orig_pixels_1[0][1] = 0u;
orig_pixels_1[0][2] = 0u;
orig_pixels_1[0][3] = 0u;
orig_pixels_1[1][0] = 0u;
orig_pixels_1[1][1] = 0u;
orig_pixels_1[1][2] = 0u;
orig_pixels_1[1][3] = 0u;
orig_pixels_1[2][0] = 0u;
orig_pixels_1[2][1] = 0u;
orig_pixels_1[2][2] = 0u;
orig_pixels_1[2][3] = 0u;
orig_pixels_1[3][0] = 255u;
orig_pixels_1[3][1] = 255u;
orig_pixels_1[3][2] = 255u;
orig_pixels_1[3][3] = 255u;
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
&interpolate_pixels[0][0], 0, 4, 1, 128);
ASSERT_EQ(8u, interpolate_pixels[0][0]);
ASSERT_EQ(16u, interpolate_pixels[0][1]);
ASSERT_EQ(32u, interpolate_pixels[0][2]);
ASSERT_EQ(64u, interpolate_pixels[0][3]);
ASSERT_EQ(0u, interpolate_pixels[1][0]);
ASSERT_EQ(0u, interpolate_pixels[1][1]);
ASSERT_EQ(0u, interpolate_pixels[1][2]);
ASSERT_EQ(128u, interpolate_pixels[1][3]);
ASSERT_EQ(0u, interpolate_pixels[2][0]);
ASSERT_EQ(0u, interpolate_pixels[2][1]);
ASSERT_EQ(0u, interpolate_pixels[2][2]);
ASSERT_EQ(0u, interpolate_pixels[2][3]);
ASSERT_EQ(128u, interpolate_pixels[3][0]);
ASSERT_EQ(128u, interpolate_pixels[3][1]);
ASSERT_EQ(128u, interpolate_pixels[3][2]);
ASSERT_EQ(128u, interpolate_pixels[3][3]);
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
&interpolate_pixels[0][0], 0, 4, 1, 0);
ASSERT_EQ(16u, interpolate_pixels[0][0]);
ASSERT_EQ(32u, interpolate_pixels[0][1]);
ASSERT_EQ(64u, interpolate_pixels[0][2]);
ASSERT_EQ(128u, interpolate_pixels[0][3]);
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
&interpolate_pixels[0][0], 0, 4, 1, 192);
ASSERT_EQ(4u, interpolate_pixels[0][0]);
ASSERT_EQ(8u, interpolate_pixels[0][1]);
ASSERT_EQ(16u, interpolate_pixels[0][2]);
ASSERT_EQ(32u, interpolate_pixels[0][3]);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
&interpolate_pixels[0][0], 0, 1280, 1, 128);
}
}
TEST_F(LibYUVPlanarTest, TestInterpolatePlane) {
SIMD_ALIGNED(uint8_t orig_pixels_0[1280]);
SIMD_ALIGNED(uint8_t orig_pixels_1[1280]);
SIMD_ALIGNED(uint8_t interpolate_pixels[1280]);
memset(orig_pixels_0, 0, sizeof(orig_pixels_0));
memset(orig_pixels_1, 0, sizeof(orig_pixels_1));
orig_pixels_0[0] = 16u;
orig_pixels_0[1] = 32u;
orig_pixels_0[2] = 64u;
orig_pixels_0[3] = 128u;
orig_pixels_0[4] = 0u;
orig_pixels_0[5] = 0u;
orig_pixels_0[6] = 0u;
orig_pixels_0[7] = 255u;
orig_pixels_0[8] = 0u;
orig_pixels_0[9] = 0u;
orig_pixels_0[10] = 0u;
orig_pixels_0[11] = 0u;
orig_pixels_0[12] = 0u;
orig_pixels_0[13] = 0u;
orig_pixels_0[14] = 0u;
orig_pixels_0[15] = 0u;
orig_pixels_1[0] = 0u;
orig_pixels_1[1] = 0u;
orig_pixels_1[2] = 0u;
orig_pixels_1[3] = 0u;
orig_pixels_1[4] = 0u;
orig_pixels_1[5] = 0u;
orig_pixels_1[6] = 0u;
orig_pixels_1[7] = 0u;
orig_pixels_1[8] = 0u;
orig_pixels_1[9] = 0u;
orig_pixels_1[10] = 0u;
orig_pixels_1[11] = 0u;
orig_pixels_1[12] = 255u;
orig_pixels_1[13] = 255u;
orig_pixels_1[14] = 255u;
orig_pixels_1[15] = 255u;
InterpolatePlane(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 128);
ASSERT_EQ(8u, interpolate_pixels[0]);
ASSERT_EQ(16u, interpolate_pixels[1]);
ASSERT_EQ(32u, interpolate_pixels[2]);
ASSERT_EQ(64u, interpolate_pixels[3]);
ASSERT_EQ(0u, interpolate_pixels[4]);
ASSERT_EQ(0u, interpolate_pixels[5]);
ASSERT_EQ(0u, interpolate_pixels[6]);
ASSERT_EQ(128u, interpolate_pixels[7]);
ASSERT_EQ(0u, interpolate_pixels[8]);
ASSERT_EQ(0u, interpolate_pixels[9]);
ASSERT_EQ(0u, interpolate_pixels[10]);
ASSERT_EQ(0u, interpolate_pixels[11]);
ASSERT_EQ(128u, interpolate_pixels[12]);
ASSERT_EQ(128u, interpolate_pixels[13]);
ASSERT_EQ(128u, interpolate_pixels[14]);
ASSERT_EQ(128u, interpolate_pixels[15]);
InterpolatePlane(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 0);
ASSERT_EQ(16u, interpolate_pixels[0]);
ASSERT_EQ(32u, interpolate_pixels[1]);
ASSERT_EQ(64u, interpolate_pixels[2]);
ASSERT_EQ(128u, interpolate_pixels[3]);
InterpolatePlane(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 192);
ASSERT_EQ(4u, interpolate_pixels[0]);
ASSERT_EQ(8u, interpolate_pixels[1]);
ASSERT_EQ(16u, interpolate_pixels[2]);
ASSERT_EQ(32u, interpolate_pixels[3]);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
InterpolatePlane(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 1280, 1, 123);
}
}
TEST_F(LibYUVPlanarTest, TestInterpolatePlane_16) {
SIMD_ALIGNED(uint16_t orig_pixels_0[1280]);
SIMD_ALIGNED(uint16_t orig_pixels_1[1280]);
SIMD_ALIGNED(uint16_t interpolate_pixels[1280]);
memset(orig_pixels_0, 0, sizeof(orig_pixels_0));
memset(orig_pixels_1, 0, sizeof(orig_pixels_1));
orig_pixels_0[0] = 16u;
orig_pixels_0[1] = 32u;
orig_pixels_0[2] = 64u;
orig_pixels_0[3] = 128u;
orig_pixels_0[4] = 0u;
orig_pixels_0[5] = 0u;
orig_pixels_0[6] = 0u;
orig_pixels_0[7] = 255u;
orig_pixels_0[8] = 0u;
orig_pixels_0[9] = 0u;
orig_pixels_0[10] = 0u;
orig_pixels_0[11] = 0u;
orig_pixels_0[12] = 0u;
orig_pixels_0[13] = 0u;
orig_pixels_0[14] = 0u;
orig_pixels_0[15] = 0u;
orig_pixels_1[0] = 0u;
orig_pixels_1[1] = 0u;
orig_pixels_1[2] = 0u;
orig_pixels_1[3] = 0u;
orig_pixels_1[4] = 0u;
orig_pixels_1[5] = 0u;
orig_pixels_1[6] = 0u;
orig_pixels_1[7] = 0u;
orig_pixels_1[8] = 0u;
orig_pixels_1[9] = 0u;
orig_pixels_1[10] = 0u;
orig_pixels_1[11] = 0u;
orig_pixels_1[12] = 255u;
orig_pixels_1[13] = 255u;
orig_pixels_1[14] = 255u;
orig_pixels_1[15] = 255u;
InterpolatePlane_16(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 128);
ASSERT_EQ(8u, interpolate_pixels[0]);
ASSERT_EQ(16u, interpolate_pixels[1]);
ASSERT_EQ(32u, interpolate_pixels[2]);
ASSERT_EQ(64u, interpolate_pixels[3]);
ASSERT_EQ(0u, interpolate_pixels[4]);
ASSERT_EQ(0u, interpolate_pixels[5]);
ASSERT_EQ(0u, interpolate_pixels[6]);
ASSERT_EQ(128u, interpolate_pixels[7]);
ASSERT_EQ(0u, interpolate_pixels[8]);
ASSERT_EQ(0u, interpolate_pixels[9]);
ASSERT_EQ(0u, interpolate_pixels[10]);
ASSERT_EQ(0u, interpolate_pixels[11]);
ASSERT_EQ(128u, interpolate_pixels[12]);
ASSERT_EQ(128u, interpolate_pixels[13]);
ASSERT_EQ(128u, interpolate_pixels[14]);
ASSERT_EQ(128u, interpolate_pixels[15]);
InterpolatePlane_16(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 0);
ASSERT_EQ(16u, interpolate_pixels[0]);
ASSERT_EQ(32u, interpolate_pixels[1]);
ASSERT_EQ(64u, interpolate_pixels[2]);
ASSERT_EQ(128u, interpolate_pixels[3]);
InterpolatePlane_16(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 192);
ASSERT_EQ(4u, interpolate_pixels[0]);
ASSERT_EQ(8u, interpolate_pixels[1]);
ASSERT_EQ(16u, interpolate_pixels[2]);
ASSERT_EQ(32u, interpolate_pixels[3]);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
InterpolatePlane_16(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 1280, 1, 123);
}
}
#define TESTTERP(FMT_A, BPP_A, STRIDE_A, FMT_B, BPP_B, STRIDE_B, W1280, TERP, \
N, NEG, OFF) \
TEST_F(LibYUVPlanarTest, ARGBInterpolate##TERP##N) { \
const int kWidth = W1280; \
const int kHeight = benchmark_height_; \
const int kStrideA = \
(kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
const int kStrideB = \
(kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
align_buffer_page_end(src_argb_a, kStrideA * kHeight + OFF); \
align_buffer_page_end(src_argb_b, kStrideA * kHeight + OFF); \
align_buffer_page_end(dst_argb_c, kStrideB * kHeight); \
align_buffer_page_end(dst_argb_opt, kStrideB * kHeight); \
for (int i = 0; i < kStrideA * kHeight; ++i) { \
src_argb_a[i + OFF] = (fastrand() & 0xff); \
src_argb_b[i + OFF] = (fastrand() & 0xff); \
} \
MaskCpuFlags(disable_cpu_flags_); \
ARGBInterpolate(src_argb_a + OFF, kStrideA, src_argb_b + OFF, kStrideA, \
dst_argb_c, kStrideB, kWidth, NEG kHeight, TERP); \
MaskCpuFlags(benchmark_cpu_info_); \
for (int i = 0; i < benchmark_iterations_; ++i) { \
ARGBInterpolate(src_argb_a + OFF, kStrideA, src_argb_b + OFF, kStrideA, \
dst_argb_opt, kStrideB, kWidth, NEG kHeight, TERP); \
} \
for (int i = 0; i < kStrideB * kHeight; ++i) { \
ASSERT_EQ(dst_argb_c[i], dst_argb_opt[i]); \
} \
free_aligned_buffer_page_end(src_argb_a); \
free_aligned_buffer_page_end(src_argb_b); \
free_aligned_buffer_page_end(dst_argb_c); \
free_aligned_buffer_page_end(dst_argb_opt); \
}
#define TESTINTERPOLATE(TERP) \
TESTTERP(ARGB, 4, 1, ARGB, 4, 1, benchmark_width_ + 1, TERP, _Any, +, 0) \
TESTTERP(ARGB, 4, 1, ARGB, 4, 1, benchmark_width_, TERP, _Unaligned, +, 1) \
TESTTERP(ARGB, 4, 1, ARGB, 4, 1, benchmark_width_, TERP, _Invert, -, 0) \
TESTTERP(ARGB, 4, 1, ARGB, 4, 1, benchmark_width_, TERP, _Opt, +, 0)
TESTINTERPOLATE(0)
TESTINTERPOLATE(64)
TESTINTERPOLATE(128)
TESTINTERPOLATE(192)
TESTINTERPOLATE(255)
static int TestBlend(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off,
int attenuate) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb_a, kStride * height + off);
align_buffer_page_end(src_argb_b, kStride * height + off);
align_buffer_page_end(dst_argb_c, kStride * height);
align_buffer_page_end(dst_argb_opt, kStride * height);
for (int i = 0; i < kStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
src_argb_b[i + off] = (fastrand() & 0xff);
}
MemRandomize(src_argb_a, kStride * height + off);
MemRandomize(src_argb_b, kStride * height + off);
if (attenuate) {
ARGBAttenuate(src_argb_a + off, kStride, src_argb_a + off, kStride, width,
height);
}
memset(dst_argb_c, 255, kStride * height);
memset(dst_argb_opt, 255, kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBBlend(src_argb_a + off, kStride, src_argb_b + off, kStride, dst_argb_c,
kStride, width, invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBBlend(src_argb_a + off, kStride, src_argb_b + off, kStride,
dst_argb_opt, kStride, width, invert * height);
}
int max_diff = 0;
for (int i = 0; i < kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(src_argb_b);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBBlend_Any) {
int max_diff =
TestBlend(benchmark_width_ + 1, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0, 1);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBBlend_Unaligned) {
int max_diff =
TestBlend(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1, 1);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBBlend_Invert) {
int max_diff =
TestBlend(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0, 1);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBBlend_Unattenuated) {
int max_diff =
TestBlend(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0, 0);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBBlend_Opt) {
int max_diff =
TestBlend(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0, 1);
ASSERT_LE(max_diff, 1);
}
static void TestBlendPlane(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 1;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb_a, kStride * height + off);
align_buffer_page_end(src_argb_b, kStride * height + off);
align_buffer_page_end(src_argb_alpha, kStride * height + off);
align_buffer_page_end(dst_argb_c, kStride * height + off);
align_buffer_page_end(dst_argb_opt, kStride * height + off);
memset(dst_argb_c, 255, kStride * height + off);
memset(dst_argb_opt, 255, kStride * height + off);
// Test source is maintained exactly if alpha is 255.
for (int i = 0; i < width; ++i) {
src_argb_a[i + off] = i & 255;
src_argb_b[i + off] = 255 - (i & 255);
}
memset(src_argb_alpha + off, 255, width);
BlendPlane(src_argb_a + off, width, src_argb_b + off, width,
src_argb_alpha + off, width, dst_argb_opt + off, width, width, 1);
for (int i = 0; i < width; ++i) {
ASSERT_EQ(src_argb_a[i + off], dst_argb_opt[i + off]);
}
// Test destination is maintained exactly if alpha is 0.
memset(src_argb_alpha + off, 0, width);
BlendPlane(src_argb_a + off, width, src_argb_b + off, width,
src_argb_alpha + off, width, dst_argb_opt + off, width, width, 1);
for (int i = 0; i < width; ++i) {
ASSERT_EQ(src_argb_b[i + off], dst_argb_opt[i + off]);
}
for (int i = 0; i < kStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
src_argb_b[i + off] = (fastrand() & 0xff);
src_argb_alpha[i + off] = (fastrand() & 0xff);
}
MaskCpuFlags(disable_cpu_flags);
BlendPlane(src_argb_a + off, width, src_argb_b + off, width,
src_argb_alpha + off, width, dst_argb_c + off, width, width,
invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
BlendPlane(src_argb_a + off, width, src_argb_b + off, width,
src_argb_alpha + off, width, dst_argb_opt + off, width, width,
invert * height);
}
for (int i = 0; i < kStride * height; ++i) {
ASSERT_EQ(dst_argb_c[i + off], dst_argb_opt[i + off]);
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(src_argb_b);
free_aligned_buffer_page_end(src_argb_alpha);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
}
TEST_F(LibYUVPlanarTest, BlendPlane_Opt) {
TestBlendPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
}
TEST_F(LibYUVPlanarTest, BlendPlane_Unaligned) {
TestBlendPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
}
TEST_F(LibYUVPlanarTest, BlendPlane_Any) {
TestBlendPlane(benchmark_width_ + 1, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
}
TEST_F(LibYUVPlanarTest, BlendPlane_Invert) {
TestBlendPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 1);
}
#define SUBSAMPLE(v, a) ((((v) + (a) - 1)) / (a))
static void TestI420Blend(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
width = ((width) > 0) ? (width) : 1;
const int kStrideUV = SUBSAMPLE(width, 2);
const int kSizeUV = kStrideUV * SUBSAMPLE(height, 2);
align_buffer_page_end(src_y0, width * height + off);
align_buffer_page_end(src_u0, kSizeUV + off);
align_buffer_page_end(src_v0, kSizeUV + off);
align_buffer_page_end(src_y1, width * height + off);
align_buffer_page_end(src_u1, kSizeUV + off);
align_buffer_page_end(src_v1, kSizeUV + off);
align_buffer_page_end(src_a, width * height + off);
align_buffer_page_end(dst_y_c, width * height + off);
align_buffer_page_end(dst_u_c, kSizeUV + off);
align_buffer_page_end(dst_v_c, kSizeUV + off);
align_buffer_page_end(dst_y_opt, width * height + off);
align_buffer_page_end(dst_u_opt, kSizeUV + off);
align_buffer_page_end(dst_v_opt, kSizeUV + off);
MemRandomize(src_y0, width * height + off);
MemRandomize(src_u0, kSizeUV + off);
MemRandomize(src_v0, kSizeUV + off);
MemRandomize(src_y1, width * height + off);
MemRandomize(src_u1, kSizeUV + off);
MemRandomize(src_v1, kSizeUV + off);
MemRandomize(src_a, width * height + off);
memset(dst_y_c, 255, width * height + off);
memset(dst_u_c, 255, kSizeUV + off);
memset(dst_v_c, 255, kSizeUV + off);
memset(dst_y_opt, 255, width * height + off);
memset(dst_u_opt, 255, kSizeUV + off);
memset(dst_v_opt, 255, kSizeUV + off);
MaskCpuFlags(disable_cpu_flags);
I420Blend(src_y0 + off, width, src_u0 + off, kStrideUV, src_v0 + off,
kStrideUV, src_y1 + off, width, src_u1 + off, kStrideUV,
src_v1 + off, kStrideUV, src_a + off, width, dst_y_c + off, width,
dst_u_c + off, kStrideUV, dst_v_c + off, kStrideUV, width,
invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
I420Blend(src_y0 + off, width, src_u0 + off, kStrideUV, src_v0 + off,
kStrideUV, src_y1 + off, width, src_u1 + off, kStrideUV,
src_v1 + off, kStrideUV, src_a + off, width, dst_y_opt + off,
width, dst_u_opt + off, kStrideUV, dst_v_opt + off, kStrideUV,
width, invert * height);
}
for (int i = 0; i < width * height; ++i) {
ASSERT_EQ(dst_y_c[i + off], dst_y_opt[i + off]);
}
for (int i = 0; i < kSizeUV; ++i) {
ASSERT_EQ(dst_u_c[i + off], dst_u_opt[i + off]);
ASSERT_EQ(dst_v_c[i + off], dst_v_opt[i + off]);
}
free_aligned_buffer_page_end(src_y0);
free_aligned_buffer_page_end(src_u0);
free_aligned_buffer_page_end(src_v0);
free_aligned_buffer_page_end(src_y1);
free_aligned_buffer_page_end(src_u1);
free_aligned_buffer_page_end(src_v1);
free_aligned_buffer_page_end(src_a);
free_aligned_buffer_page_end(dst_y_c);
free_aligned_buffer_page_end(dst_u_c);
free_aligned_buffer_page_end(dst_v_c);
free_aligned_buffer_page_end(dst_y_opt);
free_aligned_buffer_page_end(dst_u_opt);
free_aligned_buffer_page_end(dst_v_opt);
}
TEST_F(LibYUVPlanarTest, I420Blend_Opt) {
TestI420Blend(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
}
TEST_F(LibYUVPlanarTest, I420Blend_Unaligned) {
TestI420Blend(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
}
// TODO(fbarchard): DISABLED because _Any uses C. Avoid C and re-enable.
TEST_F(LibYUVPlanarTest, DISABLED_I420Blend_Any) {
TestI420Blend(benchmark_width_ + 1, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
}
TEST_F(LibYUVPlanarTest, I420Blend_Invert) {
TestI420Blend(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
}
#ifdef ENABLE_ROW_TESTS
TEST_F(LibYUVPlanarTest, TestAffine) {
SIMD_ALIGNED(uint8_t orig_pixels_0[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;
}
}
float uv_step[4] = {0.f, 0.f, 0.75f, 0.f};
ARGBAffineRow_C(&orig_pixels_0[0][0], 0, &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) {
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);
}
}
#endif
#if defined(HAS_ARGBAFFINEROW_NEON)
SIMD_ALIGNED(uint8_t interpolate_pixels_Opt[1280][4]);
ARGBAffineRow_NEON(&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_neon = TestCpuFlag(kCpuHasNEON);
if (has_neon) {
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBAffineRow_NEON(&orig_pixels_0[0][0], 0, &interpolate_pixels_Opt[0][0],
uv_step, 1280);
}
}
#endif
}
#endif // ENABLE_ROW_TESTS
static int TestCopyPlane(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);
align_buffer_page_end(dst_c, y_plane_size);
align_buffer_page_end(dst_opt, y_plane_size);
MemRandomize(orig_y + off, y_plane_size);
memset(dst_c, 1, y_plane_size);
memset(dst_opt, 2, y_plane_size);
// Disable all optimizations.
MaskCpuFlags(disable_cpu_flags);
for (int i = 0; i < benchmark_iterations; i++) {
CopyPlane(orig_y + off, benchmark_width, dst_c, benchmark_width,
benchmark_width, benchmark_height * invert);
}
// Enable optimizations.
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; i++) {
CopyPlane(orig_y + off, benchmark_width, dst_opt, 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[i]) - static_cast<int>(dst_opt[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_Any) {
int max_diff = TestCopyPlane(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, CopyPlane_Unaligned) {
int max_diff =
TestCopyPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, CopyPlane_Invert) {
int max_diff =
TestCopyPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, CopyPlane_Opt) {
int max_diff =
TestCopyPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, TestCopyPlaneZero) {
// Test to verify copying a rect with a zero height or width does
// not touch destination memory.
uint8_t src = 42;
uint8_t dst = 0;
// Disable all optimizations.
MaskCpuFlags(disable_cpu_flags_);
CopyPlane(&src, 0, &dst, 0, 0, 0);
ASSERT_EQ(src, 42);
ASSERT_EQ(dst, 0);
CopyPlane(&src, 1, &dst, 1, 1, 0);
ASSERT_EQ(src, 42);
ASSERT_EQ(dst, 0);
CopyPlane(&src, 1, &dst, 1, 0, 1);
ASSERT_EQ(src, 42);
ASSERT_EQ(dst, 0);
// Enable optimizations.
MaskCpuFlags(benchmark_cpu_info_);
CopyPlane(&src, 0, &dst, 0, 0, 0);
ASSERT_EQ(src, 42);
ASSERT_EQ(dst, 0);
CopyPlane(&src, 1, &dst, 1, 1, 0);
ASSERT_EQ(src, 42);
ASSERT_EQ(dst, 0);
CopyPlane(&src, 1, &dst, 1, 0, 1);
ASSERT_EQ(src, 42);
ASSERT_EQ(dst, 0);
}
TEST_F(LibYUVPlanarTest, TestDetilePlane) {
int i, j;
// orig is tiled. Allocate enough memory for tiles.
int tile_width = (benchmark_width_ + 15) & ~15;
int tile_height = (benchmark_height_ + 15) & ~15;
int tile_plane_size = tile_width * tile_height;
int y_plane_size = benchmark_width_ * benchmark_height_;
align_buffer_page_end(tile_y, tile_plane_size);
align_buffer_page_end(dst_c, y_plane_size);
align_buffer_page_end(dst_opt, y_plane_size);
MemRandomize(tile_y, tile_plane_size);
memset(dst_c, 0, y_plane_size);
memset(dst_opt, 0, y_plane_size);
// Disable all optimizations.
MaskCpuFlags(disable_cpu_flags_);
for (j = 0; j < benchmark_iterations_; j++) {
DetilePlane(tile_y, tile_width, dst_c, benchmark_width_, benchmark_width_,
benchmark_height_, 16);
}
// Enable optimizations.
MaskCpuFlags(benchmark_cpu_info_);
for (j = 0; j < benchmark_iterations_; j++) {
DetilePlane(tile_y, tile_width, dst_opt, benchmark_width_, benchmark_width_,
benchmark_height_, 16);
}
for (i = 0; i < y_plane_size; ++i) {
ASSERT_EQ(dst_c[i], dst_opt[i]);
}
free_aligned_buffer_page_end(tile_y);
free_aligned_buffer_page_end(dst_c);
free_aligned_buffer_page_end(dst_opt);
}
TEST_F(LibYUVPlanarTest, TestDetilePlane_16) {
int i, j;
// orig is tiled. Allocate enough memory for tiles.
int tile_width = (benchmark_width_ + 15) & ~15;
int tile_height = (benchmark_height_ + 15) & ~15;
int tile_plane_size = tile_width * tile_height * 2;
int y_plane_size = benchmark_width_ * benchmark_height_ * 2;
align_buffer_page_end(tile_y, tile_plane_size);
align_buffer_page_end(dst_c, y_plane_size);
align_buffer_page_end(dst_opt, y_plane_size);
MemRandomize(tile_y, tile_plane_size);
memset(dst_c, 0, y_plane_size);
memset(dst_opt, 0, y_plane_size);
// Disable all optimizations.
MaskCpuFlags(disable_cpu_flags_);
for (j = 0; j < benchmark_iterations_; j++) {
DetilePlane_16((const uint16_t*)tile_y, tile_width, (uint16_t*)dst_c,
benchmark_width_, benchmark_width_, benchmark_height_, 16);
}
// Enable optimizations.
MaskCpuFlags(benchmark_cpu_info_);
for (j = 0; j < benchmark_iterations_; j++) {
DetilePlane_16((const uint16_t*)tile_y, tile_width, (uint16_t*)dst_opt,
benchmark_width_, benchmark_width_, benchmark_height_, 16);
}
for (i = 0; i < y_plane_size; ++i) {
ASSERT_EQ(dst_c[i], dst_opt[i]);
}
free_aligned_buffer_page_end(tile_y);
free_aligned_buffer_page_end(dst_c);
free_aligned_buffer_page_end(dst_opt);
}
// Compares DetileSplitUV to 2 step Detile + SplitUV
TEST_F(LibYUVPlanarTest, TestDetileSplitUVPlane_Correctness) {
int i, j;
// orig is tiled. Allocate enough memory for tiles.
int uv_width = (benchmark_width_ + 1) & ~1;
int tile_width = (uv_width + 15) & ~15;
int tile_height = (benchmark_height_ + 15) & ~15;
int tile_plane_size = tile_width * tile_height;
int uv_plane_size = (uv_width / 2) * benchmark_height_;
align_buffer_page_end(tile_uv, tile_plane_size);
align_buffer_page_end(detiled_uv, tile_plane_size);
align_buffer_page_end(dst_u_two_stage, uv_plane_size);
align_buffer_page_end(dst_u_opt, uv_plane_size);
align_buffer_page_end(dst_v_two_stage, uv_plane_size);
align_buffer_page_end(dst_v_opt, uv_plane_size);
MemRandomize(tile_uv, tile_plane_size);
memset(detiled_uv, 0, tile_plane_size);
memset(dst_u_two_stage, 0, uv_plane_size);
memset(dst_u_opt, 0, uv_plane_size);
memset(dst_v_two_stage, 0, uv_plane_size);
memset(dst_v_opt, 0, uv_plane_size);
DetileSplitUVPlane(tile_uv, tile_width, dst_u_opt, uv_width / 2, dst_v_opt,
uv_width / 2, uv_width, benchmark_height_, 16);
// Benchmark 2 step conversion for comparison.
for (j = 0; j < benchmark_iterations_; j++) {
DetilePlane(tile_uv, tile_width, detiled_uv, uv_width, uv_width,
benchmark_height_, 16);
SplitUVPlane(detiled_uv, uv_width, dst_u_two_stage, uv_width / 2,
dst_v_two_stage, uv_width / 2, uv_width / 2,
benchmark_height_);
}
for (i = 0; i < uv_plane_size; ++i) {
ASSERT_EQ(dst_u_two_stage[i], dst_u_opt[i]);
ASSERT_EQ(dst_v_two_stage[i], dst_v_opt[i]);
}
free_aligned_buffer_page_end(tile_uv);
free_aligned_buffer_page_end(detiled_uv);
free_aligned_buffer_page_end(dst_u_two_stage);
free_aligned_buffer_page_end(dst_u_opt);
free_aligned_buffer_page_end(dst_v_two_stage);
free_aligned_buffer_page_end(dst_v_opt);
}
TEST_F(LibYUVPlanarTest, TestDetileSplitUVPlane_Benchmark) {
int i, j;
// orig is tiled. Allocate enough memory for tiles.
int uv_width = (benchmark_width_ + 1) & ~1;
int tile_width = (uv_width + 15) & ~15;
int tile_height = (benchmark_height_ + 15) & ~15;
int tile_plane_size = tile_width * tile_height;
int uv_plane_size = (uv_width / 2) * benchmark_height_;
align_buffer_page_end(tile_uv, tile_plane_size);
align_buffer_page_end(dst_u_c, uv_plane_size);
align_buffer_page_end(dst_u_opt, uv_plane_size);
align_buffer_page_end(dst_v_c, uv_plane_size);
align_buffer_page_end(dst_v_opt, uv_plane_size);
MemRandomize(tile_uv, tile_plane_size);
memset(dst_u_c, 0, uv_plane_size);
memset(dst_u_opt, 0, uv_plane_size);
memset(dst_v_c, 0, uv_plane_size);
memset(dst_v_opt, 0, uv_plane_size);
// Disable all optimizations.
MaskCpuFlags(disable_cpu_flags_);
DetileSplitUVPlane(tile_uv, tile_width, dst_u_c, uv_width / 2, dst_v_c,
uv_width / 2, uv_width, benchmark_height_, 16);
// Enable optimizations.
MaskCpuFlags(benchmark_cpu_info_);
for (j = 0; j < benchmark_iterations_; j++) {
DetileSplitUVPlane(tile_uv, tile_width, dst_u_opt, uv_width / 2, dst_v_opt,
uv_width / 2, uv_width, benchmark_height_, 16);
}
for (i = 0; i < uv_plane_size; ++i) {
ASSERT_EQ(dst_u_c[i], dst_u_opt[i]);
ASSERT_EQ(dst_v_c[i], dst_v_opt[i]);
}
free_aligned_buffer_page_end(tile_uv);
free_aligned_buffer_page_end(dst_u_c);
free_aligned_buffer_page_end(dst_u_opt);
free_aligned_buffer_page_end(dst_v_c);
free_aligned_buffer_page_end(dst_v_opt);
}
static int TestMultiply(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb_a, (size_t)kStride * height + off);
align_buffer_page_end(src_argb_b, (size_t)kStride * height + off);
align_buffer_page_end(dst_argb_c, (size_t)kStride * height);
align_buffer_page_end(dst_argb_opt, (size_t)kStride * height);
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
src_argb_b[i + off] = (fastrand() & 0xff);
}
memset(dst_argb_c, 0, (size_t)kStride * height);
memset(dst_argb_opt, 0, (size_t)kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBMultiply(src_argb_a + off, kStride, src_argb_b + off, kStride, dst_argb_c,
kStride, width, invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBMultiply(src_argb_a + off, kStride, src_argb_b + off, kStride,
dst_argb_opt, kStride, width, invert * height);
}
int max_diff = 0;
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(src_argb_b);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBMultiply_Any) {
int max_diff = TestMultiply(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBMultiply_Unaligned) {
int max_diff =
TestMultiply(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBMultiply_Invert) {
int max_diff =
TestMultiply(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
ASSERT_LE(max_diff, 0);
}
TEST_F(LibYUVPlanarTest, ARGBMultiply_Opt) {
int max_diff =
TestMultiply(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 0);
}
static int TestAdd(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb_a, (size_t)kStride * height + off);
align_buffer_page_end(src_argb_b, (size_t)kStride * height + off);
align_buffer_page_end(dst_argb_c, (size_t)kStride * height);
align_buffer_page_end(dst_argb_opt, (size_t)kStride * height);
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
src_argb_b[i + off] = (fastrand() & 0xff);
}
memset(dst_argb_c, 0, (size_t)kStride * height);
memset(dst_argb_opt, 0, (size_t)kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBAdd(src_argb_a + off, kStride, src_argb_b + off, kStride, dst_argb_c,
kStride, width, invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBAdd(src_argb_a + off, kStride, src_argb_b + off, kStride, dst_argb_opt,
kStride, width, invert * height);
}
int max_diff = 0;
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(src_argb_b);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBAdd_Any) {
int max_diff =
TestAdd(benchmark_width_ + 1, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBAdd_Unaligned) {
int max_diff =
TestAdd(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBAdd_Invert) {
int max_diff =
TestAdd(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBAdd_Opt) {
int max_diff =
TestAdd(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 1);
}
static int TestSubtract(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb_a, (size_t)kStride * height + off);
align_buffer_page_end(src_argb_b, (size_t)kStride * height + off);
align_buffer_page_end(dst_argb_c, (size_t)kStride * height);
align_buffer_page_end(dst_argb_opt, (size_t)kStride * height);
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
src_argb_b[i + off] = (fastrand() & 0xff);
}
memset(dst_argb_c, 0, (size_t)kStride * height);
memset(dst_argb_opt, 0, (size_t)kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBSubtract(src_argb_a + off, kStride, src_argb_b + off, kStride, dst_argb_c,
kStride, width, invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBSubtract(src_argb_a + off, kStride, src_argb_b + off, kStride,
dst_argb_opt, kStride, width, invert * height);
}
int max_diff = 0;
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(src_argb_b);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBSubtract_Any) {
int max_diff = TestSubtract(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBSubtract_Unaligned) {
int max_diff =
TestSubtract(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBSubtract_Invert) {
int max_diff =
TestSubtract(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, ARGBSubtract_Opt) {
int max_diff =
TestSubtract(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_LE(max_diff, 1);
}
static int TestSobel(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb_a, (size_t)kStride * height + off);
align_buffer_page_end(dst_argb_c, (size_t)kStride * height);
align_buffer_page_end(dst_argb_opt, (size_t)kStride * height);
memset(src_argb_a, 0, (size_t)kStride * height + off);
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
}
memset(dst_argb_c, 0, (size_t)kStride * height);
memset(dst_argb_opt, 0, (size_t)kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBSobel(src_argb_a + off, kStride, dst_argb_c, kStride, width,
invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBSobel(src_argb_a + off, kStride, dst_argb_opt, kStride, width,
invert * height);
}
int max_diff = 0;
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBSobel_Any) {
int max_diff =
TestSobel(benchmark_width_ + 1, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobel_Unaligned) {
int max_diff =
TestSobel(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobel_Invert) {
int max_diff =
TestSobel(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobel_Opt) {
int max_diff =
TestSobel(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_EQ(0, max_diff);
}
static int TestSobelToPlane(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kSrcBpp = 4;
const int kDstBpp = 1;
const int kSrcStride = (width * kSrcBpp + 15) & ~15;
const int kDstStride = (width * kDstBpp + 15) & ~15;
align_buffer_page_end(src_argb_a, kSrcStride * height + off);
align_buffer_page_end(dst_argb_c, kDstStride * height);
align_buffer_page_end(dst_argb_opt, kDstStride * height);
memset(src_argb_a, 0, kSrcStride * height + off);
for (int i = 0; i < kSrcStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
}
memset(dst_argb_c, 0, kDstStride * height);
memset(dst_argb_opt, 0, kDstStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBSobelToPlane(src_argb_a + off, kSrcStride, dst_argb_c, kDstStride, width,
invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBSobelToPlane(src_argb_a + off, kSrcStride, dst_argb_opt, kDstStride,
width, invert * height);
}
int max_diff = 0;
for (int i = 0; i < kDstStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBSobelToPlane_Any) {
int max_diff = TestSobelToPlane(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobelToPlane_Unaligned) {
int max_diff = TestSobelToPlane(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 1);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobelToPlane_Invert) {
int max_diff = TestSobelToPlane(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, -1, 0);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobelToPlane_Opt) {
int max_diff = TestSobelToPlane(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_EQ(0, max_diff);
}
static int TestSobelXY(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb_a, (size_t)kStride * height + off);
align_buffer_page_end(dst_argb_c, (size_t)kStride * height);
align_buffer_page_end(dst_argb_opt, (size_t)kStride * height);
memset(src_argb_a, 0, (size_t)kStride * height + off);
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
}
memset(dst_argb_c, 0, (size_t)kStride * height);
memset(dst_argb_opt, 0, (size_t)kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBSobelXY(src_argb_a + off, kStride, dst_argb_c, kStride, width,
invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBSobelXY(src_argb_a + off, kStride, dst_argb_opt, kStride, width,
invert * height);
}
int max_diff = 0;
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBSobelXY_Any) {
int max_diff = TestSobelXY(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobelXY_Unaligned) {
int max_diff =
TestSobelXY(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobelXY_Invert) {
int max_diff =
TestSobelXY(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBSobelXY_Opt) {
int max_diff =
TestSobelXY(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
ASSERT_EQ(0, max_diff);
}
static int TestBlur(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off,
int radius) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
const int kCumsumHeight = radius * 2 + 2;
align_buffer_page_end(src_argb_a, (size_t)kStride * height + off);
align_buffer_page_end(dst_cumsum, (size_t)width * kCumsumHeight * 16);
align_buffer_page_end(dst_argb_c, (size_t)kStride * height);
align_buffer_page_end(dst_argb_opt, (size_t)kStride * height);
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
src_argb_a[i + off] = (fastrand() & 0xff);
}
memset(dst_argb_c, 0, (size_t)kStride * height);
memset(dst_argb_opt, 0, (size_t)kStride * height);
MaskCpuFlags(disable_cpu_flags);
ARGBBlur(src_argb_a + off, kStride, dst_argb_c, kStride,
reinterpret_cast<int32_t*>(dst_cumsum), width * 4, width,
invert * height, radius);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBBlur(src_argb_a + off, kStride, dst_argb_opt, kStride,
reinterpret_cast<int32_t*>(dst_cumsum), width * 4, width,
invert * height, radius);
}
int max_diff = 0;
for (size_t i = 0; i < (size_t)kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb_a);
free_aligned_buffer_page_end(dst_cumsum);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
#if !defined(DISABLE_SLOW_TESTS) || defined(__x86_64__) || defined(__i386__)
#define DISABLED_ARM(name) name
#else
#define DISABLED_ARM(name) DISABLED_##name
#endif
static const int kBlurSize = 55;
TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlur_Any)) {
int max_diff =
TestBlur(benchmark_width_ + 1, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0, kBlurSize);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlur_Unaligned)) {
int max_diff =
TestBlur(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1, kBlurSize);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlur_Invert)) {
int max_diff =
TestBlur(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0, kBlurSize);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlur_Opt)) {
int max_diff =
TestBlur(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0, kBlurSize);
ASSERT_LE(max_diff, 1);
}
static const int kBlurSmallSize = 1;
TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlurSmall_Any)) {
int max_diff =
TestBlur((benchmark_width_ + 3) / 4 + 1, (benchmark_height_ + 3) / 4,
benchmark_iterations_, disable_cpu_flags_, benchmark_cpu_info_,
+1, 0, kBlurSmallSize);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlurSmall_Unaligned)) {
int max_diff =
TestBlur((benchmark_width_ + 3) / 4, (benchmark_height_ + 3) / 4,
benchmark_iterations_, disable_cpu_flags_, benchmark_cpu_info_,
+1, 1, kBlurSmallSize);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlurSmall_Invert)) {
int max_diff =
TestBlur((benchmark_width_ + 3) / 4, (benchmark_height_ + 3) / 4,
benchmark_iterations_, disable_cpu_flags_, benchmark_cpu_info_,
-1, 0, kBlurSmallSize);
ASSERT_LE(max_diff, 1);
}
TEST_F(LibYUVPlanarTest, DISABLED_ARM(ARGBBlurSmall_Opt)) {
int max_diff =
TestBlur((benchmark_width_ + 3) / 4, (benchmark_height_ + 3) / 4,
benchmark_iterations_, disable_cpu_flags_, benchmark_cpu_info_,
+1, 0, kBlurSmallSize);
ASSERT_LE(max_diff, 1);
}
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]);
memset(orig_pixels, 0, sizeof(orig_pixels));
SIMD_ALIGNED(static const float kWarmifyPolynomial[16]) = {
0.94230f, -3.03300f, -2.92500f, 0.f, // C0
0.584500f, 1.112000f, 1.535000f, 1.f, // C1 x
0.001313f, -0.002503f, -0.004496f, 0.f, // C2 x * x
0.0f, 0.000006965f, 0.000008781f, 0.f, // C3 x * x * x
};
// Test blue
orig_pixels[0][0] = 255u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 128u;
// Test green
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 255u;
orig_pixels[1][2] = 0u;
orig_pixels[1][3] = 0u;
// Test red
orig_pixels[2][0] = 0u;
orig_pixels[2][1] = 0u;
orig_pixels[2][2] = 255u;
orig_pixels[2][3] = 255u;
// Test white
orig_pixels[3][0] = 255u;
orig_pixels[3][1] = 255u;
orig_pixels[3][2] = 255u;
orig_pixels[3][3] = 255u;
// Test color
orig_pixels[4][0] = 16u;
orig_pixels[4][1] = 64u;
orig_pixels[4][2] = 192u;
orig_pixels[4][3] = 224u;
// Do 16 to test asm version.
ARGBPolynomial(&orig_pixels[0][0], 0, &dst_pixels_opt[0][0], 0,
&kWarmifyPolynomial[0], 16, 1);
ASSERT_EQ(235u, dst_pixels_opt[0][0]);
ASSERT_EQ(0u, dst_pixels_opt[0][1]);
ASSERT_EQ(0u, dst_pixels_opt[0][2]);
ASSERT_EQ(128u, dst_pixels_opt[0][3]);
ASSERT_EQ(0u, dst_pixels_opt[1][0]);
ASSERT_EQ(233u, dst_pixels_opt[1][1]);
ASSERT_EQ(0u, dst_pixels_opt[1][2]);
ASSERT_EQ(0u, dst_pixels_opt[1][3]);
ASSERT_EQ(0u, dst_pixels_opt[2][0]);
ASSERT_EQ(0u, dst_pixels_opt[2][1]);
ASSERT_EQ(241u, dst_pixels_opt[2][2]);
ASSERT_EQ(255u, dst_pixels_opt[2][3]);
ASSERT_EQ(235u, dst_pixels_opt[3][0]);
ASSERT_EQ(233u, dst_pixels_opt[3][1]);
ASSERT_EQ(241u, dst_pixels_opt[3][2]);
ASSERT_EQ(255u, dst_pixels_opt[3][3]);
ASSERT_EQ(10u, dst_pixels_opt[4][0]);
ASSERT_EQ(59u, dst_pixels_opt[4][1]);
ASSERT_EQ(188u, dst_pixels_opt[4][2]);
ASSERT_EQ(224u, dst_pixels_opt[4][3]);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
MaskCpuFlags(disable_cpu_flags_);
ARGBPolynomial(&orig_pixels[0][0], 0, &dst_pixels_c[0][0], 0,
&kWarmifyPolynomial[0], 1280, 1);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBPolynomial(&orig_pixels[0][0], 0, &dst_pixels_opt[0][0], 0,
&kWarmifyPolynomial[0], 1280, 1);
}
for (int i = 0; i < 1280; ++i) {
ASSERT_EQ(dst_pixels_c[i][0], dst_pixels_opt[i][0]);
ASSERT_EQ(dst_pixels_c[i][1], dst_pixels_opt[i][1]);
ASSERT_EQ(dst_pixels_c[i][2], dst_pixels_opt[i][2]);
ASSERT_EQ(dst_pixels_c[i][3], dst_pixels_opt[i][3]);
}
}
static int TestHalfFloatPlane(int benchmark_width,
int benchmark_height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
float scale,
int mask,
int invert,
int off) {
int i, j;
const int y_plane_size = benchmark_width * benchmark_height * 2;
align_buffer_page_end(orig_y, y_plane_size + off);
align_buffer_page_end(dst_c, y_plane_size);
align_buffer_page_end(dst_opt, y_plane_size);
MemRandomize(orig_y + off, y_plane_size);
memset(dst_c, 1, y_plane_size);
memset(dst_opt, 2, y_plane_size);
for (i = 0; i < y_plane_size / 2; ++i) {
reinterpret_cast<uint16_t*>(orig_y + off)[i] &= mask;
}
// Disable all optimizations.
MaskCpuFlags(disable_cpu_flags);
for (j = 0; j < benchmark_iterations; j++) {
HalfFloatPlane(reinterpret_cast<uint16_t*>(orig_y + off),
benchmark_width * 2, reinterpret_cast<uint16_t*>(dst_c),
benchmark_width * 2, scale, benchmark_width,
benchmark_height * invert);
}
// Enable optimizations.
MaskCpuFlags(benchmark_cpu_info);
for (j = 0; j < benchmark_iterations; j++) {
HalfFloatPlane(reinterpret_cast<uint16_t*>(orig_y + off),
benchmark_width * 2, reinterpret_cast<uint16_t*>(dst_opt),
benchmark_width * 2, scale, benchmark_width,
benchmark_height * invert);
}
int max_diff = 0;
for (i = 0; i < y_plane_size / 2; ++i) {
int abs_diff =
abs(static_cast<int>(reinterpret_cast<uint16_t*>(dst_c)[i]) -
static_cast<int>(reinterpret_cast<uint16_t*>(dst_opt)[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, TestHalfFloatPlane_16bit_One) {
int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, 1.0f, 65535, +1, 0);
ASSERT_LE(diff, 1);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_16bit_Opt) {
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 65535.0f, 65535, +1, 0);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_12bit_Opt) {
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4095.0f, 4095, +1, 0);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_10bit_Opt) {
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 1023.0f, 1023, +1, 0);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_9bit_Opt) {
int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, 1.0f / 511.0f, 511, +1, 0);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Any) {
int diff = TestHalfFloatPlane(
benchmark_width_ + 1, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4096.0f, 4095, +1, 0);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Unaligned) {
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4096.0f, 4095, +1, 2);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Invert) {
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4096.0f, 4095, -1, 0);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Opt) {
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4096.0f, 4095, +1, 0);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_16bit_denormal) {
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 65535.0f, 65535, +1, 0);
ASSERT_EQ(0, diff);
}
#if defined(__arm__) && !defined(__SOFTFP__)
static void EnableFlushDenormalToZero(void) {
uint32_t cw;
asm volatile(
"vmrs %0, fpscr \n"
"orr %0, %0, #0x1000000 \n"
"vmsr fpscr, %0 \n"
: "=r"(cw)::"memory", "cc"); // Clobber List
}
static void DisableFlushDenormalToZero(void) {
uint32_t cw;
asm volatile(
"vmrs %0, fpscr \n"
"bic %0, %0, #0x1000000 \n"
"vmsr fpscr, %0 \n"
: "=r"(cw)::"memory", "cc"); // Clobber List
}
// 5 bit exponent with bias of 15 will underflow to a denormal if scale causes
// exponent to be less than 0. 15 - log2(65536) = -1/ This shouldnt normally
// happen since scale is 1/(1<<bits) where bits is 9, 10 or 12.
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_16bit_flush_denormal) {
// 32 bit arm rounding on denormal case is off by 1 compared to C.
EnableFlushDenormalToZero();
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 65535.0f, 65535, +1, 0);
DisableFlushDenormalToZero();
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_10bit_flush_denormal) {
EnableFlushDenormalToZero();
int diff = TestHalfFloatPlane(
benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 1023.0f, 1023, +1, 0);
DisableFlushDenormalToZero();
ASSERT_EQ(0, diff);
}
#endif // defined(__arm__) && !defined(__SOFTFP__)
static float TestByteToFloat(int benchmark_width,
int benchmark_height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
float scale) {
int i, j;
const int y_plane_size = benchmark_width * benchmark_height;
align_buffer_page_end(orig_y, y_plane_size * (1 + 4 + 4));
float* dst_opt = reinterpret_cast<float*>(orig_y + y_plane_size);
float* dst_c = reinterpret_cast<float*>(orig_y + y_plane_size * 5);
MemRandomize(orig_y, y_plane_size);
memset(dst_c, 0, y_plane_size * 4);
memset(dst_opt, 1, y_plane_size * 4);
// Disable all optimizations.
MaskCpuFlags(disable_cpu_flags);
ByteToFloat(orig_y, dst_c, scale, y_plane_size);
// Enable optimizations.
MaskCpuFlags(benchmark_cpu_info);
for (j = 0; j < benchmark_iterations; j++) {
ByteToFloat(orig_y, dst_opt, scale, y_plane_size);
}
float max_diff = 0;
for (i = 0; i < y_plane_size; ++i) {
float abs_diff = fabs(dst_c[i] - dst_opt[i]);
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(orig_y);
return max_diff;
}
TEST_F(LibYUVPlanarTest, TestByteToFloat) {
float diff = TestByteToFloat(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, 1.0f);
ASSERT_EQ(0.f, diff);
}
TEST_F(LibYUVPlanarTest, TestARGBLumaColorTable) {
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]);
memset(orig_pixels, 0, sizeof(orig_pixels));
align_buffer_page_end(lumacolortable, 32768);
int v = 0;
for (int i = 0; i < 32768; ++i) {
lumacolortable[i] = v;
v += 3;
}
// Test blue
orig_pixels[0][0] = 255u;
orig_pixels[0][1] = 0u;
orig_pixels[0][2] = 0u;
orig_pixels[0][3] = 128u;
// Test green
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 255u;
orig_pixels[1][2] = 0u;
orig_pixels[1][3] = 0u;
// Test red
orig_pixels[2][0] = 0u;
orig_pixels[2][1] = 0u;
orig_pixels[2][2] = 255u;
orig_pixels[2][3] = 255u;
// Test color
orig_pixels[3][0] = 16u;
orig_pixels[3][1] = 64u;
orig_pixels[3][2] = 192u;
orig_pixels[3][3] = 224u;
// Do 16 to test asm version.
ARGBLumaColorTable(&orig_pixels[0][0], 0, &dst_pixels_opt[0][0], 0,
&lumacolortable[0], 16, 1);
ASSERT_EQ(253u, dst_pixels_opt[0][0]);
ASSERT_EQ(0u, dst_pixels_opt[0][1]);
ASSERT_EQ(0u, dst_pixels_opt[0][2]);
ASSERT_EQ(128u, dst_pixels_opt[0][3]);
ASSERT_EQ(0u, dst_pixels_opt[1][0]);
ASSERT_EQ(253u, dst_pixels_opt[1][1]);
ASSERT_EQ(0u, dst_pixels_opt[1][2]);
ASSERT_EQ(0u, dst_pixels_opt[1][3]);
ASSERT_EQ(0u, dst_pixels_opt[2][0]);
ASSERT_EQ(0u, dst_pixels_opt[2][1]);
ASSERT_EQ(253u, dst_pixels_opt[2][2]);
ASSERT_EQ(255u, dst_pixels_opt[2][3]);
ASSERT_EQ(48u, dst_pixels_opt[3][0]);
ASSERT_EQ(192u, dst_pixels_opt[3][1]);
ASSERT_EQ(64u, dst_pixels_opt[3][2]);
ASSERT_EQ(224u, dst_pixels_opt[3][3]);
for (int i = 0; i < 1280; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
MaskCpuFlags(disable_cpu_flags_);
ARGBLumaColorTable(&orig_pixels[0][0], 0, &dst_pixels_c[0][0], 0,
lumacolortable, 1280, 1);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
ARGBLumaColorTable(&orig_pixels[0][0], 0, &dst_pixels_opt[0][0], 0,
lumacolortable, 1280, 1);
}
for (int i = 0; i < 1280; ++i) {
ASSERT_EQ(dst_pixels_c[i][0], dst_pixels_opt[i][0]);
ASSERT_EQ(dst_pixels_c[i][1], dst_pixels_opt[i][1]);
ASSERT_EQ(dst_pixels_c[i][2], dst_pixels_opt[i][2]);
ASSERT_EQ(dst_pixels_c[i][3], dst_pixels_opt[i][3]);
}
free_aligned_buffer_page_end(lumacolortable);
}
TEST_F(LibYUVPlanarTest, TestARGBCopyAlpha) {
const int kSize = benchmark_width_ * benchmark_height_ * 4;
align_buffer_page_end(orig_pixels, kSize);
align_buffer_page_end(dst_pixels_opt, kSize);
align_buffer_page_end(dst_pixels_c, kSize);
MemRandomize(orig_pixels, kSize);
MemRandomize(dst_pixels_opt, kSize);
memcpy(dst_pixels_c, dst_pixels_opt, kSize);
MaskCpuFlags(disable_cpu_flags_);
ARGBCopyAlpha(orig_pixels, benchmark_width_ * 4, dst_pixels_c,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
ARGBCopyAlpha(orig_pixels, benchmark_width_ * 4, dst_pixels_opt,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < kSize; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(orig_pixels);
}
TEST_F(LibYUVPlanarTest, TestARGBExtractAlpha) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 4);
align_buffer_page_end(dst_pixels_opt, kPixels);
align_buffer_page_end(dst_pixels_c, kPixels);
MemRandomize(src_pixels, kPixels * 4);
MemRandomize(dst_pixels_opt, kPixels);
memcpy(dst_pixels_c, dst_pixels_opt, kPixels);
MaskCpuFlags(disable_cpu_flags_);
ARGBExtractAlpha(src_pixels, benchmark_width_ * 4, dst_pixels_c,
benchmark_width_, benchmark_width_, benchmark_height_);
double c_time = get_time();
ARGBExtractAlpha(src_pixels, benchmark_width_ * 4, dst_pixels_c,
benchmark_width_, benchmark_width_, benchmark_height_);
c_time = (get_time() - c_time);
MaskCpuFlags(benchmark_cpu_info_);
ARGBExtractAlpha(src_pixels, benchmark_width_ * 4, dst_pixels_opt,
benchmark_width_, benchmark_width_, benchmark_height_);
double opt_time = get_time();
for (int i = 0; i < benchmark_iterations_; ++i) {
ARGBExtractAlpha(src_pixels, benchmark_width_ * 4, dst_pixels_opt,
benchmark_width_, benchmark_width_, benchmark_height_);
}
opt_time = (get_time() - opt_time) / benchmark_iterations_;
// Report performance of C vs OPT
printf("%8d us C - %8d us OPT\n", static_cast<int>(c_time * 1e6),
static_cast<int>(opt_time * 1e6));
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(src_pixels);
}
TEST_F(LibYUVPlanarTest, TestARGBCopyYToAlpha) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(orig_pixels, kPixels);
align_buffer_page_end(dst_pixels_opt, kPixels * 4);
align_buffer_page_end(dst_pixels_c, kPixels * 4);
MemRandomize(orig_pixels, kPixels);
MemRandomize(dst_pixels_opt, kPixels * 4);
memcpy(dst_pixels_c, dst_pixels_opt, kPixels * 4);
MaskCpuFlags(disable_cpu_flags_);
ARGBCopyYToAlpha(orig_pixels, benchmark_width_, dst_pixels_c,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
double c_time = get_time();
ARGBCopyYToAlpha(orig_pixels, benchmark_width_, dst_pixels_c,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
c_time = (get_time() - c_time);
MaskCpuFlags(benchmark_cpu_info_);
ARGBCopyYToAlpha(orig_pixels, benchmark_width_, dst_pixels_opt,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
double opt_time = get_time();
for (int i = 0; i < benchmark_iterations_; ++i) {
ARGBCopyYToAlpha(orig_pixels, benchmark_width_, dst_pixels_opt,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
}
opt_time = (get_time() - opt_time) / benchmark_iterations_;
// Report performance of C vs OPT
printf("%8d us C - %8d us OPT\n", static_cast<int>(c_time * 1e6),
static_cast<int>(opt_time * 1e6));
for (int i = 0; i < kPixels * 4; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(orig_pixels);
}
static int TestARGBRect(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off,
int bpp) {
if (width < 1) {
width = 1;
}
const int kStride = width * bpp;
const int kSize = kStride * height;
const uint32_t v32 = fastrand() & (bpp == 4 ? 0xffffffff : 0xff);
align_buffer_page_end(dst_argb_c, kSize + off);
align_buffer_page_end(dst_argb_opt, kSize + off);
MemRandomize(dst_argb_c + off, kSize);
memcpy(dst_argb_opt + off, dst_argb_c + off, kSize);
MaskCpuFlags(disable_cpu_flags);
if (bpp == 4) {
ARGBRect(dst_argb_c + off, kStride, 0, 0, width, invert * height, v32);
} else {
SetPlane(dst_argb_c + off, kStride, width, invert * height, v32);
}
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
if (bpp == 4) {
ARGBRect(dst_argb_opt + off, kStride, 0, 0, width, invert * height, v32);
} else {
SetPlane(dst_argb_opt + off, kStride, width, invert * height, v32);
}
}
int max_diff = 0;
for (int i = 0; i < kStride * height; ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i + off]) -
static_cast<int>(dst_argb_opt[i + off]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBRect_Any) {
int max_diff = TestARGBRect(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0, 4);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBRect_Unaligned) {
int max_diff =
TestARGBRect(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1, 4);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBRect_Invert) {
int max_diff =
TestARGBRect(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0, 4);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBRect_Opt) {
int max_diff =
TestARGBRect(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0, 4);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, SetPlane_Any) {
int max_diff = TestARGBRect(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0, 1);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, SetPlane_Unaligned) {
int max_diff =
TestARGBRect(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 1, 1);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, SetPlane_Invert) {
int max_diff =
TestARGBRect(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, -1, 0, 1);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, SetPlane_Opt) {
int max_diff =
TestARGBRect(benchmark_width_, benchmark_height_, benchmark_iterations_,
disable_cpu_flags_, benchmark_cpu_info_, +1, 0, 1);
ASSERT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, MergeUVPlane_Opt) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels_u, kPixels);
align_buffer_page_end(src_pixels_v, kPixels);
align_buffer_page_end(dst_pixels_opt, kPixels * 2);
align_buffer_page_end(dst_pixels_c, kPixels * 2);
MemRandomize(src_pixels_u, kPixels);
MemRandomize(src_pixels_v, kPixels);
MemRandomize(dst_pixels_opt, kPixels * 2);
MemRandomize(dst_pixels_c, kPixels * 2);
MaskCpuFlags(disable_cpu_flags_);
MergeUVPlane(src_pixels_u, benchmark_width_, src_pixels_v, benchmark_width_,
dst_pixels_c, benchmark_width_ * 2, benchmark_width_,
benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
MergeUVPlane(src_pixels_u, benchmark_width_, src_pixels_v, benchmark_width_,
dst_pixels_opt, benchmark_width_ * 2, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < kPixels * 2; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels_u);
free_aligned_buffer_page_end(src_pixels_v);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(dst_pixels_c);
}
// 16 bit channel split and merge
TEST_F(LibYUVPlanarTest, MergeUVPlane_16_Opt) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels_u, kPixels * 2);
align_buffer_page_end(src_pixels_v, kPixels * 2);
align_buffer_page_end(dst_pixels_opt, kPixels * 2 * 2);
align_buffer_page_end(dst_pixels_c, kPixels * 2 * 2);
MemRandomize(src_pixels_u, kPixels * 2);
MemRandomize(src_pixels_v, kPixels * 2);
MemRandomize(dst_pixels_opt, kPixels * 2 * 2);
MemRandomize(dst_pixels_c, kPixels * 2 * 2);
MaskCpuFlags(disable_cpu_flags_);
MergeUVPlane_16((const uint16_t*)src_pixels_u, benchmark_width_,
(const uint16_t*)src_pixels_v, benchmark_width_,
(uint16_t*)dst_pixels_c, benchmark_width_ * 2,
benchmark_width_, benchmark_height_, 12);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
MergeUVPlane_16((const uint16_t*)src_pixels_u, benchmark_width_,
(const uint16_t*)src_pixels_v, benchmark_width_,
(uint16_t*)dst_pixels_opt, benchmark_width_ * 2,
benchmark_width_, benchmark_height_, 12);
}
for (int i = 0; i < kPixels * 2 * 2; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels_u);
free_aligned_buffer_page_end(src_pixels_v);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(dst_pixels_c);
}
TEST_F(LibYUVPlanarTest, SplitUVPlane_Opt) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 2);
align_buffer_page_end(dst_pixels_u_c, kPixels);
align_buffer_page_end(dst_pixels_v_c, kPixels);
align_buffer_page_end(dst_pixels_u_opt, kPixels);
align_buffer_page_end(dst_pixels_v_opt, kPixels);
MemRandomize(src_pixels, kPixels * 2);
MemRandomize(dst_pixels_u_c, kPixels);
MemRandomize(dst_pixels_v_c, kPixels);
MemRandomize(dst_pixels_u_opt, kPixels);
MemRandomize(dst_pixels_v_opt, kPixels);
MaskCpuFlags(disable_cpu_flags_);
SplitUVPlane(src_pixels, benchmark_width_ * 2, dst_pixels_u_c,
benchmark_width_, dst_pixels_v_c, benchmark_width_,
benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
SplitUVPlane(src_pixels, benchmark_width_ * 2, dst_pixels_u_opt,
benchmark_width_, dst_pixels_v_opt, benchmark_width_,
benchmark_width_, benchmark_height_);
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_u_c[i], dst_pixels_u_opt[i]);
ASSERT_EQ(dst_pixels_v_c[i], dst_pixels_v_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(dst_pixels_u_c);
free_aligned_buffer_page_end(dst_pixels_v_c);
free_aligned_buffer_page_end(dst_pixels_u_opt);
free_aligned_buffer_page_end(dst_pixels_v_opt);
}
// 16 bit channel split
TEST_F(LibYUVPlanarTest, SplitUVPlane_16_Opt) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 2 * 2);
align_buffer_page_end(dst_pixels_u_c, kPixels * 2);
align_buffer_page_end(dst_pixels_v_c, kPixels * 2);
align_buffer_page_end(dst_pixels_u_opt, kPixels * 2);
align_buffer_page_end(dst_pixels_v_opt, kPixels * 2);
MemRandomize(src_pixels, kPixels * 2 * 2);
MemRandomize(dst_pixels_u_c, kPixels * 2);
MemRandomize(dst_pixels_v_c, kPixels * 2);
MemRandomize(dst_pixels_u_opt, kPixels * 2);
MemRandomize(dst_pixels_v_opt, kPixels * 2);
MaskCpuFlags(disable_cpu_flags_);
SplitUVPlane_16((const uint16_t*)src_pixels, benchmark_width_ * 2,
(uint16_t*)dst_pixels_u_c, benchmark_width_,
(uint16_t*)dst_pixels_v_c, benchmark_width_, benchmark_width_,
benchmark_height_, 10);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
SplitUVPlane_16((const uint16_t*)src_pixels, benchmark_width_ * 2,
(uint16_t*)dst_pixels_u_opt, benchmark_width_,
(uint16_t*)dst_pixels_v_opt, benchmark_width_,
benchmark_width_, benchmark_height_, 10);
}
for (int i = 0; i < kPixels * 2; ++i) {
ASSERT_EQ(dst_pixels_u_c[i], dst_pixels_u_opt[i]);
ASSERT_EQ(dst_pixels_v_c[i], dst_pixels_v_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(dst_pixels_u_c);
free_aligned_buffer_page_end(dst_pixels_v_c);
free_aligned_buffer_page_end(dst_pixels_u_opt);
free_aligned_buffer_page_end(dst_pixels_v_opt);
}
TEST_F(LibYUVPlanarTest, SwapUVPlane_Opt) {
// Round count up to multiple of 16
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 2);
align_buffer_page_end(dst_pixels_opt, kPixels * 2);
align_buffer_page_end(dst_pixels_c, kPixels * 2);
MemRandomize(src_pixels, kPixels * 2);
MemRandomize(dst_pixels_opt, kPixels * 2);
MemRandomize(dst_pixels_c, kPixels * 2);
MaskCpuFlags(disable_cpu_flags_);
SwapUVPlane(src_pixels, benchmark_width_ * 2, dst_pixels_c,
benchmark_width_ * 2, benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
SwapUVPlane(src_pixels, benchmark_width_ * 2, dst_pixels_opt,
benchmark_width_ * 2, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < kPixels * 2; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(dst_pixels_c);
}
TEST_F(LibYUVPlanarTest, MergeRGBPlane_Opt) {
// Round count up to multiple of 16
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 3);
align_buffer_page_end(tmp_pixels_c_r, kPixels);
align_buffer_page_end(tmp_pixels_opt_r, kPixels);
align_buffer_page_end(tmp_pixels_c_g, kPixels);
align_buffer_page_end(tmp_pixels_opt_g, kPixels);
align_buffer_page_end(tmp_pixels_c_b, kPixels);
align_buffer_page_end(tmp_pixels_opt_b, kPixels);
align_buffer_page_end(dst_pixels_c, kPixels * 3);
align_buffer_page_end(dst_pixels_opt, kPixels * 3);
MemRandomize(src_pixels, kPixels * 3);
MemRandomize(tmp_pixels_c_r, kPixels);
MemRandomize(tmp_pixels_opt_r, kPixels);
MemRandomize(tmp_pixels_c_g, kPixels);
MemRandomize(tmp_pixels_opt_g, kPixels);
MemRandomize(tmp_pixels_c_b, kPixels);
MemRandomize(tmp_pixels_opt_b, kPixels);
MemRandomize(dst_pixels_c, kPixels * 3);
MemRandomize(dst_pixels_opt, kPixels * 3);
MaskCpuFlags(disable_cpu_flags_);
SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_c_r,
benchmark_width_, tmp_pixels_c_g, benchmark_width_,
tmp_pixels_c_b, benchmark_width_, benchmark_width_,
benchmark_height_);
MergeRGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
benchmark_width_, tmp_pixels_c_b, benchmark_width_,
dst_pixels_c, benchmark_width_ * 3, benchmark_width_,
benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_opt_r,
benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
tmp_pixels_opt_b, benchmark_width_, benchmark_width_,
benchmark_height_);
for (int i = 0; i < benchmark_iterations_; ++i) {
MergeRGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
benchmark_width_, tmp_pixels_opt_b, benchmark_width_,
dst_pixels_opt, benchmark_width_ * 3, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < kPixels * 3; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(tmp_pixels_c_r);
free_aligned_buffer_page_end(tmp_pixels_opt_r);
free_aligned_buffer_page_end(tmp_pixels_c_g);
free_aligned_buffer_page_end(tmp_pixels_opt_g);
free_aligned_buffer_page_end(tmp_pixels_c_b);
free_aligned_buffer_page_end(tmp_pixels_opt_b);
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
}
TEST_F(LibYUVPlanarTest, SplitRGBPlane_Opt) {
// Round count up to multiple of 16
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 3);
align_buffer_page_end(tmp_pixels_c_r, kPixels);
align_buffer_page_end(tmp_pixels_opt_r, kPixels);
align_buffer_page_end(tmp_pixels_c_g, kPixels);
align_buffer_page_end(tmp_pixels_opt_g, kPixels);
align_buffer_page_end(tmp_pixels_c_b, kPixels);
align_buffer_page_end(tmp_pixels_opt_b, kPixels);
align_buffer_page_end(dst_pixels_c, kPixels * 3);
align_buffer_page_end(dst_pixels_opt, kPixels * 3);
MemRandomize(src_pixels, kPixels * 3);
MemRandomize(tmp_pixels_c_r, kPixels);
MemRandomize(tmp_pixels_opt_r, kPixels);
MemRandomize(tmp_pixels_c_g, kPixels);
MemRandomize(tmp_pixels_opt_g, kPixels);
MemRandomize(tmp_pixels_c_b, kPixels);
MemRandomize(tmp_pixels_opt_b, kPixels);
MemRandomize(dst_pixels_c, kPixels * 3);
MemRandomize(dst_pixels_opt, kPixels * 3);
MaskCpuFlags(disable_cpu_flags_);
SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_c_r,
benchmark_width_, tmp_pixels_c_g, benchmark_width_,
tmp_pixels_c_b, benchmark_width_, benchmark_width_,
benchmark_height_);
MergeRGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
benchmark_width_, tmp_pixels_c_b, benchmark_width_,
dst_pixels_c, benchmark_width_ * 3, benchmark_width_,
benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_opt_r,
benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
tmp_pixels_opt_b, benchmark_width_, benchmark_width_,
benchmark_height_);
}
MergeRGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
benchmark_width_, tmp_pixels_opt_b, benchmark_width_,
dst_pixels_opt, benchmark_width_ * 3, benchmark_width_,
benchmark_height_);
for (int i = 0; i < kPixels * 3; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(tmp_pixels_c_r);
free_aligned_buffer_page_end(tmp_pixels_opt_r);
free_aligned_buffer_page_end(tmp_pixels_c_g);
free_aligned_buffer_page_end(tmp_pixels_opt_g);
free_aligned_buffer_page_end(tmp_pixels_c_b);
free_aligned_buffer_page_end(tmp_pixels_opt_b);
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
}
// Call SplitRGBPlane() with a width that is not a multiple of 32. Verify there
// is no stack buffer overflow in SplitRGBRow_Any_AVX2().
TEST_F(LibYUVPlanarTest, SplitRGBPlaneOverflow) {
int width = 1024 + 31; // 1055
const int height = 2;
align_buffer_page_end(src_rgb, width * 3 * height);
align_buffer_page_end(dst_r, width * height);
align_buffer_page_end(dst_g, width * height);
align_buffer_page_end(dst_b, width * height);
memset(src_rgb, 0x5A, width * 3 * height);
SplitRGBPlane(src_rgb, width * 3, dst_r, width, dst_g, width, dst_b, width,
width, height);
free_aligned_buffer_page_end(src_rgb);
free_aligned_buffer_page_end(dst_r);
free_aligned_buffer_page_end(dst_g);
free_aligned_buffer_page_end(dst_b);
}
TEST_F(LibYUVPlanarTest, MergeARGBPlane_Opt) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 4);
align_buffer_page_end(tmp_pixels_c_r, kPixels);
align_buffer_page_end(tmp_pixels_opt_r, kPixels);
align_buffer_page_end(tmp_pixels_c_g, kPixels);
align_buffer_page_end(tmp_pixels_opt_g, kPixels);
align_buffer_page_end(tmp_pixels_c_b, kPixels);
align_buffer_page_end(tmp_pixels_opt_b, kPixels);
align_buffer_page_end(tmp_pixels_c_a, kPixels);
align_buffer_page_end(tmp_pixels_opt_a, kPixels);
align_buffer_page_end(dst_pixels_c, kPixels * 4);
align_buffer_page_end(dst_pixels_opt, kPixels * 4);
MemRandomize(src_pixels, kPixels * 4);
MemRandomize(tmp_pixels_c_r, kPixels);
MemRandomize(tmp_pixels_opt_r, kPixels);
MemRandomize(tmp_pixels_c_g, kPixels);
MemRandomize(tmp_pixels_opt_g, kPixels);
MemRandomize(tmp_pixels_c_b, kPixels);
MemRandomize(tmp_pixels_opt_b, kPixels);
MemRandomize(tmp_pixels_c_a, kPixels);
MemRandomize(tmp_pixels_opt_a, kPixels);
MemRandomize(dst_pixels_opt, kPixels * 4);
MemRandomize(dst_pixels_c, kPixels * 4);
MaskCpuFlags(disable_cpu_flags_);
SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_c_r,
benchmark_width_, tmp_pixels_c_g, benchmark_width_,
tmp_pixels_c_b, benchmark_width_, tmp_pixels_c_a,
benchmark_width_, benchmark_width_, benchmark_height_);
MergeARGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
benchmark_width_, tmp_pixels_c_b, benchmark_width_,
tmp_pixels_c_a, benchmark_width_, dst_pixels_c,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_opt_r,
benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
tmp_pixels_opt_b, benchmark_width_, tmp_pixels_opt_a,
benchmark_width_, benchmark_width_, benchmark_height_);
for (int i = 0; i < benchmark_iterations_; ++i) {
MergeARGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
benchmark_width_, tmp_pixels_opt_b, benchmark_width_,
tmp_pixels_opt_a, benchmark_width_, dst_pixels_opt,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < kPixels * 4; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(tmp_pixels_c_r);
free_aligned_buffer_page_end(tmp_pixels_opt_r);
free_aligned_buffer_page_end(tmp_pixels_c_g);
free_aligned_buffer_page_end(tmp_pixels_opt_g);
free_aligned_buffer_page_end(tmp_pixels_c_b);
free_aligned_buffer_page_end(tmp_pixels_opt_b);
free_aligned_buffer_page_end(tmp_pixels_c_a);
free_aligned_buffer_page_end(tmp_pixels_opt_a);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(dst_pixels_c);
}
TEST_F(LibYUVPlanarTest, SplitARGBPlane_Opt) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 4);
align_buffer_page_end(tmp_pixels_c_r, kPixels);
align_buffer_page_end(tmp_pixels_opt_r, kPixels);
align_buffer_page_end(tmp_pixels_c_g, kPixels);
align_buffer_page_end(tmp_pixels_opt_g, kPixels);
align_buffer_page_end(tmp_pixels_c_b, kPixels);
align_buffer_page_end(tmp_pixels_opt_b, kPixels);
align_buffer_page_end(tmp_pixels_c_a, kPixels);
align_buffer_page_end(tmp_pixels_opt_a, kPixels);
align_buffer_page_end(dst_pixels_opt, kPixels * 4);
align_buffer_page_end(dst_pixels_c, kPixels * 4);
MemRandomize(src_pixels, kPixels * 4);
MemRandomize(tmp_pixels_c_r, kPixels);
MemRandomize(tmp_pixels_opt_r, kPixels);
MemRandomize(tmp_pixels_c_g, kPixels);
MemRandomize(tmp_pixels_opt_g, kPixels);
MemRandomize(tmp_pixels_c_b, kPixels);
MemRandomize(tmp_pixels_opt_b, kPixels);
MemRandomize(tmp_pixels_c_a, kPixels);
MemRandomize(tmp_pixels_opt_a, kPixels);
MemRandomize(dst_pixels_opt, kPixels * 4);
MemRandomize(dst_pixels_c, kPixels * 4);
MaskCpuFlags(disable_cpu_flags_);
SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_c_r,
benchmark_width_, tmp_pixels_c_g, benchmark_width_,
tmp_pixels_c_b, benchmark_width_, tmp_pixels_c_a,
benchmark_width_, benchmark_width_, benchmark_height_);
MergeARGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
benchmark_width_, tmp_pixels_c_b, benchmark_width_,
tmp_pixels_c_a, benchmark_width_, dst_pixels_c,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_opt_r,
benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
tmp_pixels_opt_b, benchmark_width_, tmp_pixels_opt_a,
benchmark_width_, benchmark_width_, benchmark_height_);
}
MergeARGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
benchmark_width_, tmp_pixels_opt_b, benchmark_width_,
tmp_pixels_opt_a, benchmark_width_, dst_pixels_opt,
benchmark_width_ * 4, benchmark_width_, benchmark_height_);
for (int i = 0; i < kPixels * 4; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(tmp_pixels_c_r);
free_aligned_buffer_page_end(tmp_pixels_opt_r);
free_aligned_buffer_page_end(tmp_pixels_c_g);
free_aligned_buffer_page_end(tmp_pixels_opt_g);
free_aligned_buffer_page_end(tmp_pixels_c_b);
free_aligned_buffer_page_end(tmp_pixels_opt_b);
free_aligned_buffer_page_end(tmp_pixels_c_a);
free_aligned_buffer_page_end(tmp_pixels_opt_a);
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
}
// Call SplitARGBPlane() with a width that is not a multiple of 16. Verify there
// is no stack buffer overflow in SplitXRGBRow_Any_AVX2().
TEST_F(LibYUVPlanarTest, SplitARGBPlaneOverflow) {
int width = 1024 + 15; // 1039
int height = 2;
align_buffer_page_end(src_argb, width * 4 * height);
align_buffer_page_end(dst_r, width * height);
align_buffer_page_end(dst_g, width * height);
align_buffer_page_end(dst_b, width * height);
memset(src_argb, 0x5A, width * 4 * height);
// dst_a == NULL selects SplitXRGBRow
SplitARGBPlane(src_argb, width * 4, dst_r, width, dst_g, width, dst_b, width,
NULL, 0, width, height);
free_aligned_buffer_page_end(src_argb);
free_aligned_buffer_page_end(dst_r);
free_aligned_buffer_page_end(dst_g);
free_aligned_buffer_page_end(dst_b);
}
TEST_F(LibYUVPlanarTest, MergeXRGBPlane_Opt) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 4);
align_buffer_page_end(tmp_pixels_c_r, kPixels);
align_buffer_page_end(tmp_pixels_opt_r, kPixels);
align_buffer_page_end(tmp_pixels_c_g, kPixels);
align_buffer_page_end(tmp_pixels_opt_g, kPixels);
align_buffer_page_end(tmp_pixels_c_b, kPixels);
align_buffer_page_end(tmp_pixels_opt_b, kPixels);
align_buffer_page_end(dst_pixels_c, kPixels * 4);
align_buffer_page_end(dst_pixels_opt, kPixels * 4);
MemRandomize(src_pixels, kPixels * 4);
MemRandomize(tmp_pixels_c_r, kPixels);
MemRandomize(tmp_pixels_opt_r, kPixels);
MemRandomize(tmp_pixels_c_g, kPixels);
MemRandomize(tmp_pixels_opt_g, kPixels);
MemRandomize(tmp_pixels_c_b, kPixels);
MemRandomize(tmp_pixels_opt_b, kPixels);
MemRandomize(dst_pixels_c, kPixels * 4);
MemRandomize(dst_pixels_opt, kPixels * 4);
MaskCpuFlags(disable_cpu_flags_);
SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_c_r,
benchmark_width_, tmp_pixels_c_g, benchmark_width_,
tmp_pixels_c_b, benchmark_width_, NULL, 0, benchmark_width_,
benchmark_height_);
MergeARGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
benchmark_width_, tmp_pixels_c_b, benchmark_width_, NULL, 0,
dst_pixels_c, benchmark_width_ * 4, benchmark_width_,
benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_opt_r,
benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
tmp_pixels_opt_b, benchmark_width_, NULL, 0, benchmark_width_,
benchmark_height_);
for (int i = 0; i < benchmark_iterations_; ++i) {
MergeARGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
benchmark_width_, tmp_pixels_opt_b, benchmark_width_, NULL,
0, dst_pixels_opt, benchmark_width_ * 4, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < kPixels * 4; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(tmp_pixels_c_r);
free_aligned_buffer_page_end(tmp_pixels_opt_r);
free_aligned_buffer_page_end(tmp_pixels_c_g);
free_aligned_buffer_page_end(tmp_pixels_opt_g);
free_aligned_buffer_page_end(tmp_pixels_c_b);
free_aligned_buffer_page_end(tmp_pixels_opt_b);
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
}
TEST_F(LibYUVPlanarTest, SplitXRGBPlane_Opt) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels, kPixels * 4);
align_buffer_page_end(tmp_pixels_c_r, kPixels);
align_buffer_page_end(tmp_pixels_opt_r, kPixels);
align_buffer_page_end(tmp_pixels_c_g, kPixels);
align_buffer_page_end(tmp_pixels_opt_g, kPixels);
align_buffer_page_end(tmp_pixels_c_b, kPixels);
align_buffer_page_end(tmp_pixels_opt_b, kPixels);
align_buffer_page_end(dst_pixels_c, kPixels * 4);
align_buffer_page_end(dst_pixels_opt, kPixels * 4);
MemRandomize(src_pixels, kPixels * 4);
MemRandomize(tmp_pixels_c_r, kPixels);
MemRandomize(tmp_pixels_opt_r, kPixels);
MemRandomize(tmp_pixels_c_g, kPixels);
MemRandomize(tmp_pixels_opt_g, kPixels);
MemRandomize(tmp_pixels_c_b, kPixels);
MemRandomize(tmp_pixels_opt_b, kPixels);
MemRandomize(dst_pixels_c, kPixels * 4);
MemRandomize(dst_pixels_opt, kPixels * 4);
MaskCpuFlags(disable_cpu_flags_);
SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_c_r,
benchmark_width_, tmp_pixels_c_g, benchmark_width_,
tmp_pixels_c_b, benchmark_width_, NULL, 0, benchmark_width_,
benchmark_height_);
MergeARGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
benchmark_width_, tmp_pixels_c_b, benchmark_width_, NULL, 0,
dst_pixels_c, benchmark_width_ * 4, benchmark_width_,
benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_opt_r,
benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
tmp_pixels_opt_b, benchmark_width_, NULL, 0,
benchmark_width_, benchmark_height_);
}
MergeARGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
benchmark_width_, tmp_pixels_opt_b, benchmark_width_, NULL, 0,
dst_pixels_opt, benchmark_width_ * 4, benchmark_width_,
benchmark_height_);
for (int i = 0; i < kPixels * 4; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(src_pixels);
free_aligned_buffer_page_end(tmp_pixels_c_r);
free_aligned_buffer_page_end(tmp_pixels_opt_r);
free_aligned_buffer_page_end(tmp_pixels_c_g);
free_aligned_buffer_page_end(tmp_pixels_opt_g);
free_aligned_buffer_page_end(tmp_pixels_c_b);
free_aligned_buffer_page_end(tmp_pixels_opt_b);
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
}
// Merge 4 channels
#define TESTQPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, W1280, N, NEG, OFF) \
TEST_F(LibYUVPlanarTest, FUNC##Plane_##DEPTH##N) { \
const int kWidth = W1280; \
const int kPixels = kWidth * benchmark_height_; \
align_buffer_page_end(src_memory_r, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(src_memory_g, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(src_memory_b, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(src_memory_a, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(dst_memory_c, kPixels * 4 * sizeof(DTYPE)); \
align_buffer_page_end(dst_memory_opt, kPixels * 4 * sizeof(DTYPE)); \
MemRandomize(src_memory_r, kPixels * sizeof(STYPE) + OFF); \
MemRandomize(src_memory_g, kPixels * sizeof(STYPE) + OFF); \
MemRandomize(src_memory_b, kPixels * sizeof(STYPE) + OFF); \
MemRandomize(src_memory_a, kPixels * sizeof(STYPE) + OFF); \
memset(dst_memory_c, 0, kPixels * 4 * sizeof(DTYPE)); \
memset(dst_memory_opt, 0, kPixels * 4 * sizeof(DTYPE)); \
STYPE* src_pixels_r = reinterpret_cast<STYPE*>(src_memory_r + OFF); \
STYPE* src_pixels_g = reinterpret_cast<STYPE*>(src_memory_g + OFF); \
STYPE* src_pixels_b = reinterpret_cast<STYPE*>(src_memory_b + OFF); \
STYPE* src_pixels_a = reinterpret_cast<STYPE*>(src_memory_a + OFF); \
DTYPE* dst_pixels_c = reinterpret_cast<DTYPE*>(dst_memory_c); \
DTYPE* dst_pixels_opt = reinterpret_cast<DTYPE*>(dst_memory_opt); \
MaskCpuFlags(disable_cpu_flags_); \
FUNC##Plane(src_pixels_r, kWidth, src_pixels_g, kWidth, src_pixels_b, \
kWidth, src_pixels_a, kWidth, dst_pixels_c, kWidth * 4, \
kWidth, NEG benchmark_height_, DEPTH); \
MaskCpuFlags(benchmark_cpu_info_); \
for (int i = 0; i < benchmark_iterations_; ++i) { \
FUNC##Plane(src_pixels_r, kWidth, src_pixels_g, kWidth, src_pixels_b, \
kWidth, src_pixels_a, kWidth, dst_pixels_opt, kWidth * 4, \
kWidth, NEG benchmark_height_, DEPTH); \
} \
for (int i = 0; i < kPixels * 4; ++i) { \
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]); \
} \
free_aligned_buffer_page_end(src_memory_r); \
free_aligned_buffer_page_end(src_memory_g); \
free_aligned_buffer_page_end(src_memory_b); \
free_aligned_buffer_page_end(src_memory_a); \
free_aligned_buffer_page_end(dst_memory_c); \
free_aligned_buffer_page_end(dst_memory_opt); \
}
// Merge 3 channel RGB into 4 channel XRGB with opaque alpha
#define TESTQPLANAROTOPI(FUNC, STYPE, DTYPE, DEPTH, W1280, N, NEG, OFF) \
TEST_F(LibYUVPlanarTest, FUNC##Plane_Opaque_##DEPTH##N) { \
const int kWidth = W1280; \
const int kPixels = kWidth * benchmark_height_; \
align_buffer_page_end(src_memory_r, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(src_memory_g, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(src_memory_b, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(dst_memory_c, kPixels * 4 * sizeof(DTYPE)); \
align_buffer_page_end(dst_memory_opt, kPixels * 4 * sizeof(DTYPE)); \
MemRandomize(src_memory_r, kPixels * sizeof(STYPE) + OFF); \
MemRandomize(src_memory_g, kPixels * sizeof(STYPE) + OFF); \
MemRandomize(src_memory_b, kPixels * sizeof(STYPE) + OFF); \
memset(dst_memory_c, 0, kPixels * 4 * sizeof(DTYPE)); \
memset(dst_memory_opt, 0, kPixels * 4 * sizeof(DTYPE)); \
STYPE* src_pixels_r = reinterpret_cast<STYPE*>(src_memory_r + OFF); \
STYPE* src_pixels_g = reinterpret_cast<STYPE*>(src_memory_g + OFF); \
STYPE* src_pixels_b = reinterpret_cast<STYPE*>(src_memory_b + OFF); \
DTYPE* dst_pixels_c = reinterpret_cast<DTYPE*>(dst_memory_c); \
DTYPE* dst_pixels_opt = reinterpret_cast<DTYPE*>(dst_memory_opt); \
MaskCpuFlags(disable_cpu_flags_); \
FUNC##Plane(src_pixels_r, kWidth, src_pixels_g, kWidth, src_pixels_b, \
kWidth, NULL, 0, dst_pixels_c, kWidth * 4, kWidth, \
NEG benchmark_height_, DEPTH); \
MaskCpuFlags(benchmark_cpu_info_); \
for (int i = 0; i < benchmark_iterations_; ++i) { \
FUNC##Plane(src_pixels_r, kWidth, src_pixels_g, kWidth, src_pixels_b, \
kWidth, NULL, 0, dst_pixels_opt, kWidth * 4, kWidth, \
NEG benchmark_height_, DEPTH); \
} \
for (int i = 0; i < kPixels * 4; ++i) { \
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]); \
} \
free_aligned_buffer_page_end(src_memory_r); \
free_aligned_buffer_page_end(src_memory_g); \
free_aligned_buffer_page_end(src_memory_b); \
free_aligned_buffer_page_end(dst_memory_c); \
free_aligned_buffer_page_end(dst_memory_opt); \
}
#define TESTQPLANARTOP(FUNC, STYPE, DTYPE, DEPTH) \
TESTQPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_ + 1, _Any, +, 0) \
TESTQPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Unaligned, +, \
2) \
TESTQPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Invert, -, 0) \
TESTQPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Opt, +, 0) \
TESTQPLANAROTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_ + 1, _Any, +, \
0) \
TESTQPLANAROTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Unaligned, +, \
2) \
TESTQPLANAROTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Invert, -, 0) \
TESTQPLANAROTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Opt, +, 0)
TESTQPLANARTOP(MergeAR64, uint16_t, uint16_t, 10)
TESTQPLANARTOP(MergeAR64, uint16_t, uint16_t, 12)
TESTQPLANARTOP(MergeAR64, uint16_t, uint16_t, 16)
TESTQPLANARTOP(MergeARGB16To8, uint16_t, uint8_t, 10)
TESTQPLANARTOP(MergeARGB16To8, uint16_t, uint8_t, 12)
TESTQPLANARTOP(MergeARGB16To8, uint16_t, uint8_t, 16)
#define TESTTPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, W1280, N, NEG, OFF) \
TEST_F(LibYUVPlanarTest, FUNC##Plane_##DEPTH##N) { \
const int kWidth = W1280; \
const int kPixels = kWidth * benchmark_height_; \
align_buffer_page_end(src_memory_r, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(src_memory_g, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(src_memory_b, kPixels * sizeof(STYPE) + OFF); \
align_buffer_page_end(dst_memory_c, kPixels * 4 * sizeof(DTYPE)); \
align_buffer_page_end(dst_memory_opt, kPixels * 4 * sizeof(DTYPE)); \
MemRandomize(src_memory_r, kPixels * sizeof(STYPE) + OFF); \
MemRandomize(src_memory_g, kPixels * sizeof(STYPE) + OFF); \
MemRandomize(src_memory_b, kPixels * sizeof(STYPE) + OFF); \
STYPE* src_pixels_r = reinterpret_cast<STYPE*>(src_memory_r + OFF); \
STYPE* src_pixels_g = reinterpret_cast<STYPE*>(src_memory_g + OFF); \
STYPE* src_pixels_b = reinterpret_cast<STYPE*>(src_memory_b + OFF); \
DTYPE* dst_pixels_c = reinterpret_cast<DTYPE*>(dst_memory_c); \
DTYPE* dst_pixels_opt = reinterpret_cast<DTYPE*>(dst_memory_opt); \
memset(dst_pixels_c, 1, kPixels * 4 * sizeof(DTYPE)); \
memset(dst_pixels_opt, 2, kPixels * 4 * sizeof(DTYPE)); \
MaskCpuFlags(disable_cpu_flags_); \
FUNC##Plane(src_pixels_r, kWidth, src_pixels_g, kWidth, src_pixels_b, \
kWidth, dst_pixels_c, kWidth * 4, kWidth, \
NEG benchmark_height_, DEPTH); \
MaskCpuFlags(benchmark_cpu_info_); \
for (int i = 0; i < benchmark_iterations_; ++i) { \
FUNC##Plane(src_pixels_r, kWidth, src_pixels_g, kWidth, src_pixels_b, \
kWidth, dst_pixels_opt, kWidth * 4, kWidth, \
NEG benchmark_height_, DEPTH); \
} \
for (int i = 0; i < kPixels * 4; ++i) { \
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]); \
} \
free_aligned_buffer_page_end(src_memory_r); \
free_aligned_buffer_page_end(src_memory_g); \
free_aligned_buffer_page_end(src_memory_b); \
free_aligned_buffer_page_end(dst_memory_c); \
free_aligned_buffer_page_end(dst_memory_opt); \
}
#define TESTTPLANARTOP(FUNC, STYPE, DTYPE, DEPTH) \
TESTTPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_ + 1, _Any, +, 0) \
TESTTPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Unaligned, +, \
2) \
TESTTPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Invert, -, 0) \
TESTTPLANARTOPI(FUNC, STYPE, DTYPE, DEPTH, benchmark_width_, _Opt, +, 0)
TESTTPLANARTOP(MergeXR30, uint16_t, uint8_t, 10)
TESTTPLANARTOP(MergeXR30, uint16_t, uint8_t, 12)
TESTTPLANARTOP(MergeXR30, uint16_t, uint8_t, 16)
// TODO(fbarchard): improve test for platforms and cpu detect
#ifdef HAS_MERGEUVROW_16_AVX2
TEST_F(LibYUVPlanarTest, MergeUVRow_16_Opt) {
// Round count up to multiple of 8
const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7;
align_buffer_page_end(src_pixels_u, kPixels * 2);
align_buffer_page_end(src_pixels_v, kPixels * 2);
align_buffer_page_end(dst_pixels_uv_opt, kPixels * 2 * 2);
align_buffer_page_end(dst_pixels_uv_c, kPixels * 2 * 2);
MemRandomize(src_pixels_u, kPixels * 2);
MemRandomize(src_pixels_v, kPixels * 2);
memset(dst_pixels_uv_opt, 0, kPixels * 2 * 2);
memset(dst_pixels_uv_c, 1, kPixels * 2 * 2);
MergeUVRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_u),
reinterpret_cast<const uint16_t*>(src_pixels_v),
reinterpret_cast<uint16_t*>(dst_pixels_uv_c), 16, kPixels);
int has_avx2 = TestCpuFlag(kCpuHasAVX2);
for (int i = 0; i < benchmark_iterations_; ++i) {
if (has_avx2) {
MergeUVRow_16_AVX2(reinterpret_cast<const uint16_t*>(src_pixels_u),
reinterpret_cast<const uint16_t*>(src_pixels_v),
reinterpret_cast<uint16_t*>(dst_pixels_uv_opt), 16,
kPixels);
} else {
MergeUVRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_u),
reinterpret_cast<const uint16_t*>(src_pixels_v),
reinterpret_cast<uint16_t*>(dst_pixels_uv_opt), 16,
kPixels);
}
}
for (int i = 0; i < kPixels * 2 * 2; ++i) {
ASSERT_EQ(dst_pixels_uv_opt[i], dst_pixels_uv_c[i]);
}
free_aligned_buffer_page_end(src_pixels_u);
free_aligned_buffer_page_end(src_pixels_v);
free_aligned_buffer_page_end(dst_pixels_uv_opt);
free_aligned_buffer_page_end(dst_pixels_uv_c);
}
#endif
#if defined(HAS_MULTIPLYROW_16_AVX512BW) || \
defined(HAS_MULTIPLYROW_16_AVX2) || defined(HAS_MULTIPLYROW_16_NEON) || \
defined(HAS_MULTIPLYROW_16_SME) || defined(HAS_MULTIPLYROW_16_RVV) || \
defined(HAS_MULTIPLYROW_16_HVX)
TEST_F(LibYUVPlanarTest, MultiplyRow_16_Opt) {
// Round count up to multiple of 64
const int kPixels = (benchmark_width_ * benchmark_height_ + 63) & ~63;
align_buffer_page_end(src_pixels_y, kPixels * 2);
align_buffer_page_end(dst_pixels_y_opt, kPixels * 2);
align_buffer_page_end(dst_pixels_y_c, kPixels * 2);
MemRandomize(src_pixels_y, kPixels * 2);
memset(dst_pixels_y_opt, 0, kPixels * 2);
memset(dst_pixels_y_c, 1, kPixels * 2);
MultiplyRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_c), 64, kPixels);
#if defined(HAS_MULTIPLYROW_16_AVX512BW)
int has_avx512 = TestCpuFlag(kCpuHasAVX512BW);
#endif
#if defined(HAS_MULTIPLYROW_16_AVX2)
int has_avx2 = TestCpuFlag(kCpuHasAVX2);
#endif
#if defined(HAS_MULTIPLYROW_16_NEON)
int has_neon = TestCpuFlag(kCpuHasNEON);
#endif
#if defined(HAS_MULTIPLYROW_16_SME)
int has_sme = TestCpuFlag(kCpuHasSME);
#endif
#if defined(HAS_MULTIPLYROW_16_RVV)
int has_rvv = TestCpuFlag(kCpuHasRVV);
#endif
#if defined(HAS_MULTIPLYROW_16_HVX)
int has_hvx = TestCpuFlag(kCpuHasHVX);
#endif
for (int i = 0; i < benchmark_iterations_; ++i) {
#if defined(HAS_MULTIPLYROW_16_AVX512BW)
if (has_avx512) {
MultiplyRow_16_AVX512BW(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
kPixels);
} else
#endif
#if defined(HAS_MULTIPLYROW_16_AVX2)
if (has_avx2) {
MultiplyRow_16_AVX2(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
kPixels);
} else
#endif
#if defined(HAS_MULTIPLYROW_16_SME)
if (has_sme) {
MultiplyRow_16_SME(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
kPixels);
} else
#endif
#if defined(HAS_MULTIPLYROW_16_NEON)
if (has_neon) {
MultiplyRow_16_NEON(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
kPixels);
} else
#endif
#if defined(HAS_MULTIPLYROW_16_RVV)
if (has_rvv) {
MultiplyRow_16_RVV(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
kPixels);
} else
#endif
#if defined(HAS_MULTIPLYROW_16_HVX)
if (has_hvx) {
MultiplyRow_16_HVX(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
kPixels);
} else
#endif
{
MultiplyRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
kPixels);
}
}
for (int i = 0; i < kPixels * 2; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
#if defined(HAS_MULTIPLYROW_16_AVX512BW) || \
defined(HAS_MULTIPLYROW_16_AVX2) || defined(HAS_MULTIPLYROW_16_NEON)
TEST_F(LibYUVPlanarTest, MultiplyRow_16_Any) {
const int kMaxPixels = 256;
align_buffer_page_end(src_pixels_y, kMaxPixels * 2);
align_buffer_page_end(dst_pixels_y_opt, kMaxPixels * 2);
align_buffer_page_end(dst_pixels_y_c, kMaxPixels * 2);
for (int i = 0; i < kMaxPixels; ++i) {
reinterpret_cast<uint16_t*>(src_pixels_y)[i] = fastrand() & 1023;
}
#if defined(HAS_MULTIPLYROW_16_AVX512BW)
int has_avx512 = TestCpuFlag(kCpuHasAVX512BW);
#endif
#if defined(HAS_MULTIPLYROW_16_AVX2)
int has_avx2 = TestCpuFlag(kCpuHasAVX2);
#endif
#if defined(HAS_MULTIPLYROW_16_NEON)
int has_neon = TestCpuFlag(kCpuHasNEON);
#endif
for (int width = 1; width <= 129; ++width) {
memset(dst_pixels_y_opt, 0, kMaxPixels * 2);
memset(dst_pixels_y_c, 1, kMaxPixels * 2);
MultiplyRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_c), 64, width);
#if defined(HAS_MULTIPLYROW_16_AVX512BW)
if (has_avx512) {
MultiplyRow_16_Any_AVX512BW(
reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64, width);
} else
#endif
#if defined(HAS_MULTIPLYROW_16_AVX2)
if (has_avx2) {
MultiplyRow_16_Any_AVX2(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
width);
} else
#endif
#if defined(HAS_MULTIPLYROW_16_NEON)
if (has_neon) {
MultiplyRow_16_Any_NEON(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
width);
} else
#endif
{
MultiplyRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_y),
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64,
width);
}
for (int i = 0; i < width * 2; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
#endif // HAS_MULTIPLYROW_16_AVX512BW || HAS_MULTIPLYROW_16_AVX2 ||
// HAS_MULTIPLYROW_16_NEON
#endif // HAS_MULTIPLYROW_16_...
TEST_F(LibYUVPlanarTest, Convert16To8Plane) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels_y, kPixels * 2);
align_buffer_page_end(dst_pixels_y_opt, kPixels);
align_buffer_page_end(dst_pixels_y_c, kPixels);
MemRandomize(src_pixels_y, kPixels * 2);
memset(dst_pixels_y_opt, 0, kPixels);
memset(dst_pixels_y_c, 1, kPixels);
MaskCpuFlags(disable_cpu_flags_);
Convert16To8Plane(reinterpret_cast<const uint16_t*>(src_pixels_y),
benchmark_width_, dst_pixels_y_c, benchmark_width_, 16384,
benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
Convert16To8Plane(reinterpret_cast<const uint16_t*>(src_pixels_y),
benchmark_width_, dst_pixels_y_opt, benchmark_width_,
16384, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
TEST_F(LibYUVPlanarTest, Convert8To8Plane) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels_y, kPixels);
align_buffer_page_end(dst_pixels_y_opt, kPixels);
align_buffer_page_end(dst_pixels_y_c, kPixels);
MemRandomize(src_pixels_y, kPixels);
memset(dst_pixels_y_opt, 0, kPixels);
memset(dst_pixels_y_c, 1, kPixels);
MaskCpuFlags(disable_cpu_flags_);
Convert8To8Plane(src_pixels_y, benchmark_width_, dst_pixels_y_c,
benchmark_width_, 220, 16, benchmark_width_,
benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
Convert8To8Plane(src_pixels_y, benchmark_width_, dst_pixels_y_opt,
benchmark_width_, 220, 16, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
TEST_F(LibYUVPlanarTest, YUY2ToY) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels_y, kPixels * 2);
align_buffer_page_end(dst_pixels_y_opt, kPixels);
align_buffer_page_end(dst_pixels_y_c, kPixels);
MemRandomize(src_pixels_y, kPixels * 2);
memset(dst_pixels_y_opt, 0, kPixels);
memset(dst_pixels_y_c, 1, kPixels);
MaskCpuFlags(disable_cpu_flags_);
YUY2ToY(src_pixels_y, benchmark_width_ * 2, dst_pixels_y_c, benchmark_width_,
benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
YUY2ToY(src_pixels_y, benchmark_width_ * 2, dst_pixels_y_opt,
benchmark_width_, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
TEST_F(LibYUVPlanarTest, UYVYToY) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels_y, kPixels * 2);
align_buffer_page_end(dst_pixels_y_opt, kPixels);
align_buffer_page_end(dst_pixels_y_c, kPixels);
MemRandomize(src_pixels_y, kPixels * 2);
memset(dst_pixels_y_opt, 0, kPixels);
memset(dst_pixels_y_c, 1, kPixels);
MaskCpuFlags(disable_cpu_flags_);
UYVYToY(src_pixels_y, benchmark_width_ * 2, dst_pixels_y_c, benchmark_width_,
benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
UYVYToY(src_pixels_y, benchmark_width_ * 2, dst_pixels_y_opt,
benchmark_width_, benchmark_width_, benchmark_height_);
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
#ifdef ENABLE_ROW_TESTS
// TODO(fbarchard): Improve test for more platforms.
#ifdef HAS_CONVERT16TO8ROW_AVX2
TEST_F(LibYUVPlanarTest, Convert16To8Row_Opt) {
// AVX2 does multiple of 32, so round count up
const int kPixels = (benchmark_width_ * benchmark_height_ + 31) & ~31;
align_buffer_page_end(src_pixels_y, kPixels * 2);
align_buffer_page_end(dst_pixels_y_opt, kPixels);
align_buffer_page_end(dst_pixels_y_c, kPixels);
MemRandomize(src_pixels_y, kPixels * 2);
// clamp source range to 10 bits.
for (int i = 0; i < kPixels; ++i) {
reinterpret_cast<uint16_t*>(src_pixels_y)[i] &= 1023;
}
memset(dst_pixels_y_opt, 0, kPixels);
memset(dst_pixels_y_c, 1, kPixels);
Convert16To8Row_C(reinterpret_cast<const uint16_t*>(src_pixels_y),
dst_pixels_y_c, 16384, kPixels);
int has_avx2 = TestCpuFlag(kCpuHasAVX2);
int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
for (int i = 0; i < benchmark_iterations_; ++i) {
if (has_avx2) {
Convert16To8Row_AVX2(reinterpret_cast<const uint16_t*>(src_pixels_y),
dst_pixels_y_opt, 16384, kPixels);
} else if (has_ssse3) {
Convert16To8Row_SSSE3(reinterpret_cast<const uint16_t*>(src_pixels_y),
dst_pixels_y_opt, 16384, kPixels);
} else {
Convert16To8Row_C(reinterpret_cast<const uint16_t*>(src_pixels_y),
dst_pixels_y_opt, 16384, kPixels);
}
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
#endif // HAS_CONVERT16TO8ROW_AVX2
#if defined(HAS_HALFWIDTHROW_16TO8_AVX2) || \
defined(HAS_HALFWIDTHROW_16TO8_SSSE3) || \
defined(HAS_HALFWIDTHROW_16TO8_AVX512BW) || \
defined(HAS_HALFWIDTHROW_16TO8_NEON)
TEST_F(LibYUVPlanarTest, HalfWidthRow_16To8_Opt) {
const int kPixels = (benchmark_width_ * benchmark_height_ + 63) & ~63;
align_buffer_page_end_16(src_pixels_uv, kPixels * 4);
align_buffer_page_end(dst_pixels_uv_opt, kPixels);
align_buffer_page_end(dst_pixels_uv_c, kPixels);
for (int i = 0; i < kPixels * 4; ++i) {
src_pixels_uv[i] = fastrand() & 1023;
}
memset(dst_pixels_uv_opt, 0, kPixels);
memset(dst_pixels_uv_c, 1, kPixels);
HalfWidthRow_16To8_C(src_pixels_uv, kPixels * 2, dst_pixels_uv_c, 16384,
kPixels);
#if defined(HAS_HALFWIDTHROW_16TO8_AVX512BW)
int has_avx512 = TestCpuFlag(kCpuHasAVX512BW);
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_AVX2)
int has_avx2 = TestCpuFlag(kCpuHasAVX2);
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_SSSE3)
int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_NEON)
int has_neon = TestCpuFlag(kCpuHasNEON);
#endif
for (int i = 0; i < benchmark_iterations_; ++i) {
#if defined(HAS_HALFWIDTHROW_16TO8_AVX512BW)
if (has_avx512) {
HalfWidthRow_16To8_AVX512BW(src_pixels_uv, kPixels * 2, dst_pixels_uv_opt,
16384, kPixels);
} else
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_AVX2)
if (has_avx2) {
HalfWidthRow_16To8_AVX2(src_pixels_uv, kPixels * 2, dst_pixels_uv_opt,
16384, kPixels);
} else
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_SSSE3)
if (has_ssse3) {
HalfWidthRow_16To8_SSSE3(src_pixels_uv, kPixels * 2, dst_pixels_uv_opt,
16384, kPixels);
} else
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_NEON)
if (has_neon) {
HalfWidthRow_16To8_NEON(src_pixels_uv, kPixels * 2, dst_pixels_uv_opt,
16384, kPixels);
} else
#endif
{
HalfWidthRow_16To8_C(src_pixels_uv, kPixels * 2, dst_pixels_uv_opt, 16384,
kPixels);
}
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_uv_opt[i], dst_pixels_uv_c[i]);
}
free_aligned_buffer_page_end_16(src_pixels_uv);
free_aligned_buffer_page_end(dst_pixels_uv_opt);
free_aligned_buffer_page_end(dst_pixels_uv_c);
}
TEST_F(LibYUVPlanarTest, HalfWidthRow_16To8_Any) {
const int kMaxPixels = 256;
align_buffer_page_end_16(src_pixels_uv, kMaxPixels * 4);
align_buffer_page_end(dst_pixels_uv_opt, kMaxPixels);
align_buffer_page_end(dst_pixels_uv_c, kMaxPixels);
for (int i = 0; i < kMaxPixels * 4; ++i) {
src_pixels_uv[i] = fastrand() & 1023;
}
#if defined(HAS_HALFWIDTHROW_16TO8_AVX512BW)
int has_avx512 = TestCpuFlag(kCpuHasAVX512BW);
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_AVX2)
int has_avx2 = TestCpuFlag(kCpuHasAVX2);
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_SSSE3)
int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_NEON)
int has_neon = TestCpuFlag(kCpuHasNEON);
#endif
for (int width = 1; width <= 129; ++width) {
memset(dst_pixels_uv_opt, 0, kMaxPixels);
memset(dst_pixels_uv_c, 1, kMaxPixels);
HalfWidthRow_16To8_C(src_pixels_uv, kMaxPixels * 2, dst_pixels_uv_c, 16384,
width);
#if defined(HAS_HALFWIDTHROW_16TO8_AVX512BW)
if (has_avx512) {
HalfWidthRow_16To8_Any_AVX512BW(src_pixels_uv, kMaxPixels * 2,
dst_pixels_uv_opt, 16384, width);
} else
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_AVX2)
if (has_avx2) {
HalfWidthRow_16To8_Any_AVX2(src_pixels_uv, kMaxPixels * 2,
dst_pixels_uv_opt, 16384, width);
} else
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_SSSE3)
if (has_ssse3) {
HalfWidthRow_16To8_Any_SSSE3(src_pixels_uv, kMaxPixels * 2,
dst_pixels_uv_opt, 16384, width);
} else
#endif
#if defined(HAS_HALFWIDTHROW_16TO8_NEON)
if (has_neon) {
HalfWidthRow_16To8_Any_NEON(src_pixels_uv, kMaxPixels * 2,
dst_pixels_uv_opt, 16384, width);
} else
#endif
{
HalfWidthRow_16To8_C(src_pixels_uv, kMaxPixels * 2, dst_pixels_uv_opt,
16384, width);
}
for (int i = 0; i < width; ++i) {
ASSERT_EQ(dst_pixels_uv_opt[i], dst_pixels_uv_c[i]);
}
}
free_aligned_buffer_page_end_16(src_pixels_uv);
free_aligned_buffer_page_end(dst_pixels_uv_opt);
free_aligned_buffer_page_end(dst_pixels_uv_c);
}
#endif
#ifdef HAS_UYVYTOYROW_NEON
TEST_F(LibYUVPlanarTest, UYVYToYRow_Opt) {
// NEON does multiple of 16, so round count up
const int kPixels = (benchmark_width_ * benchmark_height_ + 15) & ~15;
align_buffer_page_end(src_pixels_y, kPixels * 2);
align_buffer_page_end(dst_pixels_y_opt, kPixels);
align_buffer_page_end(dst_pixels_y_c, kPixels);
MemRandomize(src_pixels_y, kPixels * 2);
memset(dst_pixels_y_opt, 0, kPixels);
memset(dst_pixels_y_c, 1, kPixels);
UYVYToYRow_C(src_pixels_y, dst_pixels_y_c, kPixels);
for (int i = 0; i < benchmark_iterations_; ++i) {
UYVYToYRow_NEON(src_pixels_y, dst_pixels_y_opt, kPixels);
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
#endif // HAS_UYVYTOYROW_NEON
#endif // ENABLE_ROW_TESTS
TEST_F(LibYUVPlanarTest, Convert8To16Plane) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels_y, kPixels);
align_buffer_page_end(dst_pixels_y_opt, kPixels * 2);
align_buffer_page_end(dst_pixels_y_c, kPixels * 2);
MemRandomize(src_pixels_y, kPixels);
memset(dst_pixels_y_opt, 0, kPixels * 2);
memset(dst_pixels_y_c, 1, kPixels * 2);
MaskCpuFlags(disable_cpu_flags_);
Convert8To16Plane(src_pixels_y, benchmark_width_,
reinterpret_cast<uint16_t*>(dst_pixels_y_c),
benchmark_width_, 10, benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
Convert8To16Plane(src_pixels_y, benchmark_width_,
reinterpret_cast<uint16_t*>(dst_pixels_y_opt),
benchmark_width_, 1024, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < kPixels * 2; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
#ifdef ENABLE_ROW_TESTS
// TODO(fbarchard): Improve test for more platforms.
#if defined(HAS_CONVERT8TO16ROW_AVX512BW) || defined(HAS_CONVERT8TO16ROW_AVX2)
TEST_F(LibYUVPlanarTest, Convert8To16Row_Opt) {
const int kPixels = (benchmark_width_ * benchmark_height_ + 63) & ~63;
align_buffer_page_end(src_pixels_y, kPixels);
align_buffer_page_end(dst_pixels_y_opt, kPixels * 2);
align_buffer_page_end(dst_pixels_y_c, kPixels * 2);
MemRandomize(src_pixels_y, kPixels);
memset(dst_pixels_y_opt, 0, kPixels * 2);
memset(dst_pixels_y_c, 1, kPixels * 2);
Convert8To16Row_C(src_pixels_y, reinterpret_cast<uint16_t*>(dst_pixels_y_c),
10, kPixels);
#if defined(HAS_CONVERT8TO16ROW_AVX512BW)
int has_avx512 = TestCpuFlag(kCpuHasAVX512BW);
#endif
int has_avx2 = TestCpuFlag(kCpuHasAVX2);
int has_sse2 = TestCpuFlag(kCpuHasSSE2);
for (int i = 0; i < benchmark_iterations_; ++i) {
#if defined(HAS_CONVERT8TO16ROW_AVX512BW)
if (has_avx512) {
Convert8To16Row_AVX512BW(src_pixels_y,
reinterpret_cast<uint16_t*>(dst_pixels_y_opt),
10, kPixels);
} else
#endif
if (has_avx2) {
Convert8To16Row_AVX2(src_pixels_y,
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 10,
kPixels);
} else if (has_sse2) {
Convert8To16Row_SSE2(src_pixels_y,
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 10,
kPixels);
} else {
Convert8To16Row_C(src_pixels_y,
reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 10,
kPixels);
}
}
for (int i = 0; i < kPixels * 2; ++i) {
ASSERT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
#endif // HAS_CONVERT8TO16ROW_AVX512BW || HAS_CONVERT8TO16ROW_AVX2
float TestScaleMaxSamples(int benchmark_width,
int benchmark_height,
int benchmark_iterations,
float scale,
bool opt) {
int i, j;
float max_c, max_opt = 0.f;
// NEON does multiple of 8, so round count up
const int kPixels = (benchmark_width * benchmark_height + 7) & ~7;
align_buffer_page_end(orig_y, kPixels * 4 * 3 + 48);
uint8_t* dst_c = orig_y + kPixels * 4 + 16;
uint8_t* dst_opt = orig_y + kPixels * 4 * 2 + 32;
// Randomize works but may contain some denormals affecting performance.
// MemRandomize(orig_y, kPixels * 4);
// large values are problematic. audio is really -1 to 1.
for (i = 0; i < kPixels; ++i) {
(reinterpret_cast<float*>(orig_y))[i] = sinf(static_cast<float>(i) * 0.1f);
}
memset(dst_c, 0, kPixels * 4);
memset(dst_opt, 1, kPixels * 4);
max_c = ScaleMaxSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_c), scale, kPixels);
for (j = 0; j < benchmark_iterations; j++) {
if (opt) {
#ifdef HAS_SCALESUMSAMPLES_NEON
max_opt = ScaleMaxSamples_NEON(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale,
kPixels);
#else
max_opt =
ScaleMaxSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale, kPixels);
#endif
} else {
max_opt =
ScaleMaxSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale, kPixels);
}
}
float max_diff = FAbs(max_opt - max_c);
for (i = 0; i < kPixels; ++i) {
float abs_diff = FAbs((reinterpret_cast<float*>(dst_c)[i]) -
(reinterpret_cast<float*>(dst_opt)[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(orig_y);
return max_diff;
}
TEST_F(LibYUVPlanarTest, TestScaleMaxSamples_C) {
float diff = TestScaleMaxSamples(benchmark_width_, benchmark_height_,
benchmark_iterations_, 1.2f, false);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestScaleMaxSamples_Opt) {
float diff = TestScaleMaxSamples(benchmark_width_, benchmark_height_,
benchmark_iterations_, 1.2f, true);
ASSERT_EQ(0, diff);
}
float TestScaleSumSamples(int benchmark_width,
int benchmark_height,
int benchmark_iterations,
float scale,
bool opt) {
int i, j;
float sum_c, sum_opt = 0.f;
// NEON does multiple of 8, so round count up
const int kPixels = (benchmark_width * benchmark_height + 7) & ~7;
align_buffer_page_end(orig_y, kPixels * 4 * 3);
uint8_t* dst_c = orig_y + kPixels * 4;
uint8_t* dst_opt = orig_y + kPixels * 4 * 2;
// Randomize works but may contain some denormals affecting performance.
// MemRandomize(orig_y, kPixels * 4);
// large values are problematic. audio is really -1 to 1.
for (i = 0; i < kPixels; ++i) {
(reinterpret_cast<float*>(orig_y))[i] = sinf(static_cast<float>(i) * 0.1f);
}
memset(dst_c, 0, kPixels * 4);
memset(dst_opt, 1, kPixels * 4);
sum_c = ScaleSumSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_c), scale, kPixels);
for (j = 0; j < benchmark_iterations; j++) {
if (opt) {
#ifdef HAS_SCALESUMSAMPLES_NEON
sum_opt = ScaleSumSamples_NEON(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale,
kPixels);
#else
sum_opt =
ScaleSumSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale, kPixels);
#endif
} else {
sum_opt =
ScaleSumSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale, kPixels);
}
}
float mse_opt = sum_opt / kPixels * 4;
float mse_c = sum_c / kPixels * 4;
float mse_error = FAbs(mse_opt - mse_c) / mse_c;
// If the sum of a float is more than 4 million, small adds are round down on
// float and produce different results with vectorized sum vs scalar sum.
// Ignore the difference if the sum is large.
float max_diff = 0.f;
if (mse_error > 0.0001 && sum_c < 4000000) { // allow .01% difference of mse
max_diff = mse_error;
}
for (i = 0; i < kPixels; ++i) {
float abs_diff = FAbs((reinterpret_cast<float*>(dst_c)[i]) -
(reinterpret_cast<float*>(dst_opt)[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(orig_y);
return max_diff;
}
TEST_F(LibYUVPlanarTest, TestScaleSumSamples_C) {
float diff = TestScaleSumSamples(benchmark_width_, benchmark_height_,
benchmark_iterations_, 1.2f, false);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestScaleSumSamples_Opt) {
float diff = TestScaleSumSamples(benchmark_width_, benchmark_height_,
benchmark_iterations_, 1.2f, true);
ASSERT_EQ(0, diff);
}
float TestScaleSamples(int benchmark_width,
int benchmark_height,
int benchmark_iterations,
float scale,
bool opt) {
int i, j;
// NEON does multiple of 8, so round count up
const int kPixels = (benchmark_width * benchmark_height + 7) & ~7;
align_buffer_page_end(orig_y, kPixels * 4 * 3);
uint8_t* dst_c = orig_y + kPixels * 4;
uint8_t* dst_opt = orig_y + kPixels * 4 * 2;
// Randomize works but may contain some denormals affecting performance.
// MemRandomize(orig_y, kPixels * 4);
// large values are problematic. audio is really -1 to 1.
for (i = 0; i < kPixels; ++i) {
(reinterpret_cast<float*>(orig_y))[i] = sinf(static_cast<float>(i) * 0.1f);
}
memset(dst_c, 0, kPixels * 4);
memset(dst_opt, 1, kPixels * 4);
ScaleSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_c), scale, kPixels);
for (j = 0; j < benchmark_iterations; j++) {
if (opt) {
#ifdef HAS_SCALESUMSAMPLES_NEON
ScaleSamples_NEON(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale, kPixels);
#else
ScaleSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale, kPixels);
#endif
} else {
ScaleSamples_C(reinterpret_cast<float*>(orig_y),
reinterpret_cast<float*>(dst_opt), scale, kPixels);
}
}
float max_diff = 0.f;
for (i = 0; i < kPixels; ++i) {
float abs_diff = FAbs((reinterpret_cast<float*>(dst_c)[i]) -
(reinterpret_cast<float*>(dst_opt)[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(orig_y);
return max_diff;
}
TEST_F(LibYUVPlanarTest, TestScaleSamples_C) {
float diff = TestScaleSamples(benchmark_width_, benchmark_height_,
benchmark_iterations_, 1.2f, false);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestScaleSamples_Opt) {
float diff = TestScaleSamples(benchmark_width_, benchmark_height_,
benchmark_iterations_, 1.2f, true);
ASSERT_EQ(0, diff);
}
float TestCopySamples(int benchmark_width,
int benchmark_height,
int benchmark_iterations,
bool opt) {
int i, j;
// NEON does multiple of 16 floats, so round count up
const int kPixels = (benchmark_width * benchmark_height + 15) & ~15;
align_buffer_page_end(orig_y, kPixels * 4 * 3);
uint8_t* dst_c = orig_y + kPixels * 4;
uint8_t* dst_opt = orig_y + kPixels * 4 * 2;
// Randomize works but may contain some denormals affecting performance.
// MemRandomize(orig_y, kPixels * 4);
// large values are problematic. audio is really -1 to 1.
for (i = 0; i < kPixels; ++i) {
(reinterpret_cast<float*>(orig_y))[i] = sinf(static_cast<float>(i) * 0.1f);
}
memset(dst_c, 0, kPixels * 4);
memset(dst_opt, 1, kPixels * 4);
memcpy(reinterpret_cast<void*>(dst_c), reinterpret_cast<void*>(orig_y),
kPixels * 4);
for (j = 0; j < benchmark_iterations; j++) {
if (opt) {
#ifdef HAS_COPYROW_NEON
CopyRow_NEON(orig_y, dst_opt, kPixels * 4);
#else
CopyRow_C(orig_y, dst_opt, kPixels * 4);
#endif
} else {
CopyRow_C(orig_y, dst_opt, kPixels * 4);
}
}
float max_diff = 0.f;
for (i = 0; i < kPixels; ++i) {
float abs_diff = FAbs((reinterpret_cast<float*>(dst_c)[i]) -
(reinterpret_cast<float*>(dst_opt)[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(orig_y);
return max_diff;
}
TEST_F(LibYUVPlanarTest, TestCopySamples_C) {
float diff = TestCopySamples(benchmark_width_, benchmark_height_,
benchmark_iterations_, false);
ASSERT_EQ(0, diff);
}
TEST_F(LibYUVPlanarTest, TestCopySamples_Opt) {
float diff = TestCopySamples(benchmark_width_, benchmark_height_,
benchmark_iterations_, true);
ASSERT_EQ(0, diff);
}
extern "C" void GaussRow_NEON(const uint32_t* src, uint16_t* dst, int width);
extern "C" void GaussRow_C(const uint32_t* src, uint16_t* dst, int width);
TEST_F(LibYUVPlanarTest, TestGaussRow_Opt) {
SIMD_ALIGNED(uint32_t orig_pixels[1280 + 8]);
SIMD_ALIGNED(uint16_t dst_pixels_c[1280]);
SIMD_ALIGNED(uint16_t dst_pixels_opt[1280]);
memset(orig_pixels, 0, sizeof(orig_pixels));
memset(dst_pixels_c, 1, sizeof(dst_pixels_c));
memset(dst_pixels_opt, 2, sizeof(dst_pixels_opt));
for (int i = 0; i < 1280 + 8; ++i) {
orig_pixels[i] = i * 256;
}
GaussRow_C(&orig_pixels[0], &dst_pixels_c[0], 1280);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
#if !defined(LIBYUV_DISABLE_NEON) && \
(defined(__aarch64__) || defined(__ARM_NEON__) || defined(LIBYUV_NEON))
int has_neon = TestCpuFlag(kCpuHasNEON);
if (has_neon) {
GaussRow_NEON(&orig_pixels[0], &dst_pixels_opt[0], 1280);
} else {
GaussRow_C(&orig_pixels[0], &dst_pixels_opt[0], 1280);
}
#else
GaussRow_C(&orig_pixels[0], &dst_pixels_opt[0], 1280);
#endif
}
for (int i = 0; i < 1280; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
ASSERT_EQ(dst_pixels_c[0],
static_cast<uint16_t>(0 * 1 + 1 * 4 + 2 * 6 + 3 * 4 + 4 * 1));
ASSERT_EQ(dst_pixels_c[639], static_cast<uint16_t>(10256));
}
extern "C" void GaussCol_NEON(const uint16_t* src0,
const uint16_t* src1,
const uint16_t* src2,
const uint16_t* src3,
const uint16_t* src4,
uint32_t* dst,
int width);
extern "C" void GaussCol_C(const uint16_t* src0,
const uint16_t* src1,
const uint16_t* src2,
const uint16_t* src3,
const uint16_t* src4,
uint32_t* dst,
int width);
TEST_F(LibYUVPlanarTest, TestGaussCol_Opt) {
SIMD_ALIGNED(uint16_t orig_pixels[1280 * 5]);
SIMD_ALIGNED(uint32_t dst_pixels_c[1280]);
SIMD_ALIGNED(uint32_t dst_pixels_opt[1280]);
memset(orig_pixels, 0, sizeof(orig_pixels));
memset(dst_pixels_c, 1, sizeof(dst_pixels_c));
memset(dst_pixels_opt, 2, sizeof(dst_pixels_opt));
for (int i = 0; i < 1280 * 5; ++i) {
orig_pixels[i] = static_cast<float>(i);
}
GaussCol_C(&orig_pixels[0], &orig_pixels[1280], &orig_pixels[1280 * 2],
&orig_pixels[1280 * 3], &orig_pixels[1280 * 4], &dst_pixels_c[0],
1280);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
#if !defined(LIBYUV_DISABLE_NEON) && \
(defined(__aarch64__) || defined(__ARM_NEON__) || defined(LIBYUV_NEON))
int has_neon = TestCpuFlag(kCpuHasNEON);
if (has_neon) {
GaussCol_NEON(&orig_pixels[0], &orig_pixels[1280], &orig_pixels[1280 * 2],
&orig_pixels[1280 * 3], &orig_pixels[1280 * 4],
&dst_pixels_opt[0], 1280);
} else {
GaussCol_C(&orig_pixels[0], &orig_pixels[1280], &orig_pixels[1280 * 2],
&orig_pixels[1280 * 3], &orig_pixels[1280 * 4],
&dst_pixels_opt[0], 1280);
}
#else
GaussCol_C(&orig_pixels[0], &orig_pixels[1280], &orig_pixels[1280 * 2],
&orig_pixels[1280 * 3], &orig_pixels[1280 * 4],
&dst_pixels_opt[0], 1280);
#endif
}
for (int i = 0; i < 1280; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
}
TEST_F(LibYUVPlanarTest, TestGaussRow_F32_Opt) {
SIMD_ALIGNED(float orig_pixels[1280 + 4]);
SIMD_ALIGNED(float dst_pixels_c[1280]);
SIMD_ALIGNED(float dst_pixels_opt[1280]);
memset(orig_pixels, 0, sizeof(orig_pixels));
memset(dst_pixels_c, 1, sizeof(dst_pixels_c));
memset(dst_pixels_opt, 2, sizeof(dst_pixels_opt));
for (int i = 0; i < 1280 + 4; ++i) {
orig_pixels[i] = static_cast<float>(i);
}
GaussRow_F32_C(&orig_pixels[0], &dst_pixels_c[0], 1280);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
#if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
int has_neon = TestCpuFlag(kCpuHasNEON);
if (has_neon) {
GaussRow_F32_NEON(&orig_pixels[0], &dst_pixels_opt[0], 1280);
} else {
GaussRow_F32_C(&orig_pixels[0], &dst_pixels_opt[0], 1280);
}
#else
GaussRow_F32_C(&orig_pixels[0], &dst_pixels_opt[0], 1280);
#endif
}
for (int i = 0; i < 1280; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
}
TEST_F(LibYUVPlanarTest, TestGaussCol_F32_Opt) {
SIMD_ALIGNED(float dst_pixels_c[1280]);
SIMD_ALIGNED(float dst_pixels_opt[1280]);
align_buffer_page_end(orig_pixels_buf, 1280 * 5 * 4); // 5 rows
float* orig_pixels = reinterpret_cast<float*>(orig_pixels_buf);
memset(orig_pixels, 0, 1280 * 5 * 4);
memset(dst_pixels_c, 1, sizeof(dst_pixels_c));
memset(dst_pixels_opt, 2, sizeof(dst_pixels_opt));
for (int i = 0; i < 1280 * 5; ++i) {
orig_pixels[i] = static_cast<float>(i);
}
GaussCol_F32_C(&orig_pixels[0], &orig_pixels[1280], &orig_pixels[1280 * 2],
&orig_pixels[1280 * 3], &orig_pixels[1280 * 4],
&dst_pixels_c[0], 1280);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
#if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
int has_neon = TestCpuFlag(kCpuHasNEON);
if (has_neon) {
GaussCol_F32_NEON(&orig_pixels[0], &orig_pixels[1280],
&orig_pixels[1280 * 2], &orig_pixels[1280 * 3],
&orig_pixels[1280 * 4], &dst_pixels_opt[0], 1280);
} else {
GaussCol_F32_C(&orig_pixels[0], &orig_pixels[1280],
&orig_pixels[1280 * 2], &orig_pixels[1280 * 3],
&orig_pixels[1280 * 4], &dst_pixels_opt[0], 1280);
}
#else
GaussCol_F32_C(&orig_pixels[0], &orig_pixels[1280], &orig_pixels[1280 * 2],
&orig_pixels[1280 * 3], &orig_pixels[1280 * 4],
&dst_pixels_opt[0], 1280);
#endif
}
for (int i = 0; i < 1280; ++i) {
ASSERT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
}
free_aligned_buffer_page_end(orig_pixels_buf);
}
TEST_F(LibYUVPlanarTest, SwapUVRow) {
const int kPixels = benchmark_width_ * benchmark_height_;
void (*SwapUVRow)(const uint8_t* src_uv, uint8_t* dst_vu, int width) =
SwapUVRow_C;
align_buffer_page_end(src_pixels_vu, kPixels * 2);
align_buffer_page_end(dst_pixels_uv, kPixels * 2);
MemRandomize(src_pixels_vu, kPixels * 2);
memset(dst_pixels_uv, 1, kPixels * 2);
#if defined(HAS_SWAPUVROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
SwapUVRow = SwapUVRow_Any_SSSE3;
if (IS_ALIGNED(kPixels, 16)) {
SwapUVRow = SwapUVRow_SSSE3;
}
}
#endif
#if defined(HAS_SWAPUVROW_AVX2)
if (TestCpuFlag(kCpuHasAVX2)) {
SwapUVRow = SwapUVRow_Any_AVX2;
if (IS_ALIGNED(kPixels, 32)) {
SwapUVRow = SwapUVRow_AVX2;
}
}
#endif
#if defined(HAS_SWAPUVROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
SwapUVRow = SwapUVRow_Any_NEON;
if (IS_ALIGNED(kPixels, 16)) {
SwapUVRow = SwapUVRow_NEON;
}
}
#endif
#if defined(HAS_SWAPUVROW_RVV)
if (TestCpuFlag(kCpuHasRVV)) {
SwapUVRow = SwapUVRow_RVV;
}
#endif
#if defined(HAS_SWAPUVROW_HVX)
if (TestCpuFlag(kCpuHasHVX)) {
SwapUVRow = SwapUVRow_HVX;
}
#endif
for (int j = 0; j < benchmark_iterations_; j++) {
SwapUVRow(src_pixels_vu, dst_pixels_uv, kPixels);
}
for (int i = 0; i < kPixels; ++i) {
ASSERT_EQ(dst_pixels_uv[i * 2 + 0], src_pixels_vu[i * 2 + 1]);
ASSERT_EQ(dst_pixels_uv[i * 2 + 1], src_pixels_vu[i * 2 + 0]);
}
free_aligned_buffer_page_end(src_pixels_vu);
free_aligned_buffer_page_end(dst_pixels_uv);
}
#endif // ENABLE_ROW_TESTS
TEST_F(LibYUVPlanarTest, TestGaussPlane_F32) {
const int kSize = benchmark_width_ * benchmark_height_ * 4;
align_buffer_page_end(orig_pixels, kSize);
align_buffer_page_end(dst_pixels_opt, kSize);
align_buffer_page_end(dst_pixels_c, kSize);
for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
((float*)(orig_pixels))[i] = (i & 1023) * 3.14f;
}
memset(dst_pixels_opt, 1, kSize);
memset(dst_pixels_c, 2, kSize);
MaskCpuFlags(disable_cpu_flags_);
GaussPlane_F32((const float*)(orig_pixels), benchmark_width_,
(float*)(dst_pixels_c), benchmark_width_, benchmark_width_,
benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
GaussPlane_F32((const float*)(orig_pixels), benchmark_width_,
(float*)(dst_pixels_opt), benchmark_width_, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
ASSERT_NEAR(((float*)(dst_pixels_c))[i], ((float*)(dst_pixels_opt))[i], 1.f)
<< i;
}
free_aligned_buffer_page_end(dst_pixels_c);
free_aligned_buffer_page_end(dst_pixels_opt);
free_aligned_buffer_page_end(orig_pixels);
}
TEST_F(LibYUVPlanarTest, HalfMergeUVPlane_Opt) {
int dst_width = (benchmark_width_ + 1) / 2;
int dst_height = (benchmark_height_ + 1) / 2;
align_buffer_page_end(src_pixels_u, benchmark_width_ * benchmark_height_);
align_buffer_page_end(src_pixels_v, benchmark_width_ * benchmark_height_);
align_buffer_page_end(dst_pixels_uv_opt, dst_width * 2 * dst_height);
align_buffer_page_end(dst_pixels_uv_c, dst_width * 2 * dst_height);
MemRandomize(src_pixels_u, benchmark_width_ * benchmark_height_);
MemRandomize(src_pixels_v, benchmark_width_ * benchmark_height_);
MemRandomize(dst_pixels_uv_opt, dst_width * 2 * dst_height);
MemRandomize(dst_pixels_uv_c, dst_width * 2 * dst_height);
MaskCpuFlags(disable_cpu_flags_);
HalfMergeUVPlane(src_pixels_u, benchmark_width_, src_pixels_v,
benchmark_width_, dst_pixels_uv_c, dst_width * 2,
benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
HalfMergeUVPlane(src_pixels_u, benchmark_width_, src_pixels_v,
benchmark_width_, dst_pixels_uv_opt, dst_width * 2,
benchmark_width_, benchmark_height_);
}
for (int i = 0; i < dst_width * 2 * dst_height; ++i) {
ASSERT_EQ(dst_pixels_uv_c[i], dst_pixels_uv_opt[i]);
}
free_aligned_buffer_page_end(src_pixels_u);
free_aligned_buffer_page_end(src_pixels_v);
free_aligned_buffer_page_end(dst_pixels_uv_opt);
free_aligned_buffer_page_end(dst_pixels_uv_c);
}
TEST_F(LibYUVPlanarTest, NV12Copy) {
const int halfwidth = (benchmark_width_ + 1) >> 1;
const int halfheight = (benchmark_height_ + 1) >> 1;
align_buffer_page_end(src_y, benchmark_width_ * benchmark_height_);
align_buffer_page_end(src_uv, halfwidth * 2 * halfheight);
align_buffer_page_end(dst_y, benchmark_width_ * benchmark_height_);
align_buffer_page_end(dst_uv, halfwidth * 2 * halfheight);
MemRandomize(src_y, benchmark_width_ * benchmark_height_);
MemRandomize(src_uv, halfwidth * 2 * halfheight);
MemRandomize(dst_y, benchmark_width_ * benchmark_height_);
MemRandomize(dst_uv, halfwidth * 2 * halfheight);
for (int i = 0; i < benchmark_iterations_; ++i) {
NV12Copy(src_y, benchmark_width_, src_uv, halfwidth * 2, dst_y,
benchmark_width_, dst_uv, halfwidth * 2, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
ASSERT_EQ(src_y[i], dst_y[i]);
}
for (int i = 0; i < halfwidth * 2 * halfheight; ++i) {
ASSERT_EQ(src_uv[i], dst_uv[i]);
}
free_aligned_buffer_page_end(src_y);
free_aligned_buffer_page_end(src_uv);
free_aligned_buffer_page_end(dst_y);
free_aligned_buffer_page_end(dst_uv);
}
TEST_F(LibYUVPlanarTest, NV21Copy) {
const int halfwidth = (benchmark_width_ + 1) >> 1;
const int halfheight = (benchmark_height_ + 1) >> 1;
align_buffer_page_end(src_y, benchmark_width_ * benchmark_height_);
align_buffer_page_end(src_vu, halfwidth * 2 * halfheight);
align_buffer_page_end(dst_y, benchmark_width_ * benchmark_height_);
align_buffer_page_end(dst_vu, halfwidth * 2 * halfheight);
MemRandomize(src_y, benchmark_width_ * benchmark_height_);
MemRandomize(src_vu, halfwidth * 2 * halfheight);
MemRandomize(dst_y, benchmark_width_ * benchmark_height_);
MemRandomize(dst_vu, halfwidth * 2 * halfheight);
for (int i = 0; i < benchmark_iterations_; ++i) {
NV21Copy(src_y, benchmark_width_, src_vu, halfwidth * 2, dst_y,
benchmark_width_, dst_vu, halfwidth * 2, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
ASSERT_EQ(src_y[i], dst_y[i]);
}
for (int i = 0; i < halfwidth * 2 * halfheight; ++i) {
ASSERT_EQ(src_vu[i], dst_vu[i]);
}
free_aligned_buffer_page_end(src_y);
free_aligned_buffer_page_end(src_vu);
free_aligned_buffer_page_end(dst_y);
free_aligned_buffer_page_end(dst_vu);
}
#if defined(ENABLE_ROW_TESTS) && !defined(LIBYUV_DISABLE_NEON) && \
defined(__aarch64__)
TEST_F(LibYUVPlanarTest, TestConvertFP16ToFP32) {
int i, j;
const int y_plane_size = benchmark_width_ * benchmark_height_;
align_buffer_page_end(orig_f, y_plane_size * 4);
align_buffer_page_end(orig_y, y_plane_size * 2);
align_buffer_page_end(dst_opt, y_plane_size * 4);
align_buffer_page_end(rec_opt, y_plane_size * 2);
for (i = 0; i < y_plane_size; ++i) {
((float*)orig_f)[i] = (float)(i % 10000) * 3.14f;
}
memset(orig_y, 1, y_plane_size * 2);
memset(dst_opt, 2, y_plane_size * 4);
memset(rec_opt, 3, y_plane_size * 2);
ConvertFP32ToFP16Row_NEON((const float*)orig_f, (uint16_t*)orig_y,
y_plane_size);
for (j = 0; j < benchmark_iterations_; j++) {
ConvertFP16ToFP32Row_NEON((const uint16_t*)orig_y, (float*)dst_opt,
y_plane_size);
}
ConvertFP32ToFP16Row_NEON((const float*)dst_opt, (uint16_t*)rec_opt,
y_plane_size);
for (i = 0; i < y_plane_size; ++i) {
ASSERT_EQ(((const uint16_t*)orig_y)[i], ((const uint16_t*)rec_opt)[i]);
}
free_aligned_buffer_page_end(orig_f);
free_aligned_buffer_page_end(orig_y);
free_aligned_buffer_page_end(dst_opt);
free_aligned_buffer_page_end(rec_opt);
}
TEST_F(LibYUVPlanarTest, TestConvertFP16ToFP32Column) {
int i, j;
const int y_plane_size = benchmark_width_ * benchmark_height_;
align_buffer_page_end(orig_f, y_plane_size * 4);
align_buffer_page_end(orig_y, y_plane_size * 2);
align_buffer_page_end(dst_opt, y_plane_size * 4);
align_buffer_page_end(rec_opt, y_plane_size * 2);
for (i = 0; i < y_plane_size; ++i) {
((float*)orig_f)[i] = (float)(i % 10000) * 3.14f;
}
memset(orig_y, 1, y_plane_size * 2);
memset(dst_opt, 2, y_plane_size * 4);
memset(rec_opt, 3, y_plane_size * 2);
ConvertFP32ToFP16Row_NEON((const float*)orig_f, (uint16_t*)orig_y,
y_plane_size);
for (j = 0; j < benchmark_iterations_; j++) {
ConvertFP16ToFP32Column_NEON((const uint16_t*)orig_y, 1, (float*)dst_opt,
y_plane_size);
}
ConvertFP32ToFP16Row_NEON((const float*)dst_opt, (uint16_t*)rec_opt,
y_plane_size);
for (i = 0; i < y_plane_size; ++i) {
ASSERT_EQ(((const uint16_t*)orig_y)[i], ((const uint16_t*)rec_opt)[i]);
}
free_aligned_buffer_page_end(orig_f);
free_aligned_buffer_page_end(orig_y);
free_aligned_buffer_page_end(dst_opt);
free_aligned_buffer_page_end(rec_opt);
}
#endif // defined(ENABLE_ROW_TESTS) && defined(__aarch64__)
static int TestARGBOr(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off,
uint32_t value) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb, kStride * abs(height) + off);
align_buffer_page_end(dst_argb_c, kStride * abs(height));
align_buffer_page_end(dst_argb_opt, kStride * abs(height));
MemRandomize(src_argb, kStride * abs(height) + off);
memset(dst_argb_c, 0, kStride * abs(height));
memset(dst_argb_opt, 1, kStride * abs(height));
MaskCpuFlags(disable_cpu_flags);
ARGBOr(src_argb + off, kStride, dst_argb_c, kStride, width, invert * height,
value);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBOr(src_argb + off, kStride, dst_argb_opt, kStride, width,
invert * height, value);
}
int max_diff = 0;
for (int i = 0; i < kStride * abs(height); ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBOr_Any) {
int max_diff = TestARGBOr(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0, 0xff000000u);
EXPECT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBOr_Unaligned) {
int max_diff = TestARGBOr(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 1, 0xff000000u);
EXPECT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBOr_Invert) {
int max_diff = TestARGBOr(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, -1, 0, 0xff000000u);
EXPECT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBOr_Opt) {
int max_diff = TestARGBOr(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0, 0xff000000u);
EXPECT_EQ(0, max_diff);
}
static int TestARGBAlphaBlend(int width,
int height,
int benchmark_iterations,
int disable_cpu_flags,
int benchmark_cpu_info,
int invert,
int off) {
if (width < 1) {
width = 1;
}
const int kBpp = 4;
const int kStride = width * kBpp;
align_buffer_page_end(src_argb0, kStride * abs(height) + off);
align_buffer_page_end(src_argb1, kStride * abs(height) + off);
align_buffer_page_end(dst_argb_c, kStride * abs(height));
align_buffer_page_end(dst_argb_opt, kStride * abs(height));
MemRandomize(src_argb0, kStride * abs(height) + off);
MemRandomize(src_argb1, kStride * abs(height) + off);
memset(dst_argb_c, 0, kStride * abs(height));
memset(dst_argb_opt, 1, kStride * abs(height));
MaskCpuFlags(disable_cpu_flags);
ARGBAlphaBlend(src_argb0 + off, kStride, src_argb1 + off, kStride, dst_argb_c,
kStride, width, invert * height);
MaskCpuFlags(benchmark_cpu_info);
for (int i = 0; i < benchmark_iterations; ++i) {
ARGBAlphaBlend(src_argb0 + off, kStride, src_argb1 + off, kStride,
dst_argb_opt, kStride, width, invert * height);
}
int max_diff = 0;
for (int i = 0; i < kStride * abs(height); ++i) {
int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -
static_cast<int>(dst_argb_opt[i]));
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
free_aligned_buffer_page_end(src_argb0);
free_aligned_buffer_page_end(src_argb1);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
return max_diff;
}
TEST_F(LibYUVPlanarTest, ARGBAlphaBlend_Any) {
int max_diff = TestARGBAlphaBlend(benchmark_width_ + 1, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
EXPECT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBAlphaBlend_Unaligned) {
int max_diff = TestARGBAlphaBlend(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 1);
EXPECT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBAlphaBlend_Invert) {
int max_diff = TestARGBAlphaBlend(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, -1, 0);
EXPECT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBAlphaBlend_Opt) {
int max_diff = TestARGBAlphaBlend(benchmark_width_, benchmark_height_,
benchmark_iterations_, disable_cpu_flags_,
benchmark_cpu_info_, +1, 0);
EXPECT_EQ(0, max_diff);
}
TEST_F(LibYUVPlanarTest, ARGBAlphaBlend_AllAlphas) {
const int kWidth = 256;
const int kHeight = 256;
const int kStride = kWidth * 4;
align_buffer_page_end(src_argb0, kStride * kHeight);
align_buffer_page_end(src_argb1, kStride * kHeight);
align_buffer_page_end(dst_argb_c, kStride * kHeight);
align_buffer_page_end(dst_argb_opt, kStride * kHeight);
for (int da = 0; da < 256; ++da) {
for (int sa = 0; sa < 256; ++sa) {
int idx = (da * 256 + sa) * 4;
src_argb0[idx + 0] = (sa * 7 + da * 3 + 13) & 255;
src_argb0[idx + 1] = (sa * 13 + da * 5 + 29) & 255;
src_argb0[idx + 2] = (sa * 29 + da * 11 + 47) & 255;
src_argb0[idx + 3] = sa;
src_argb1[idx + 0] = (da * 17 + sa * 19 + 53) & 255;
src_argb1[idx + 1] = (da * 23 + sa * 31 + 71) & 255;
src_argb1[idx + 2] = (da * 37 + sa * 41 + 89) & 255;
src_argb1[idx + 3] = da;
}
}
MaskCpuFlags(disable_cpu_flags_);
ARGBAlphaBlend(src_argb0, kStride, src_argb1, kStride, dst_argb_c, kStride,
kWidth, kHeight);
MaskCpuFlags(benchmark_cpu_info_);
ARGBAlphaBlend(src_argb0, kStride, src_argb1, kStride, dst_argb_opt, kStride,
kWidth, kHeight);
for (int i = 0; i < kStride * kHeight; ++i) {
ASSERT_EQ(dst_argb_c[i], dst_argb_opt[i]) << "Mismatch at byte " << i;
}
free_aligned_buffer_page_end(src_argb0);
free_aligned_buffer_page_end(src_argb1);
free_aligned_buffer_page_end(dst_argb_c);
free_aligned_buffer_page_end(dst_argb_opt);
}
} // namespace libyuv