mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2026-10-28 18:07:12 +08:00
[libyuv] Add SwapUVRow_AVX2 and NV12ToNV21
Add SwapUVRow_AVX2 implementation in row_win.cc for MSVC and enable HAS_SWAPUVROW_AVX2 under USE_ROW_WIN. Share kShuffleUVToVU shuffle table between SSSE3 and AVX2 in row_gcc.cc. Make NV12ToNV21 the primary implementation and alias NV21ToNV12 to it. Add NV12ToNV21 test in convert_test.cc and benchmark dispatch for SSSE3 and AVX2 in planar_test.cc. CPU Before After Speedup ---------------------------------------------------------------- Intel Granite Rapids 282 ms 125 ms 2.26x Intel Emerald Rapids 264 ms 108 ms 2.44x Intel Sapphire Rapids 276 ms 122 ms 2.26x Intel Ice Lake 310 ms 122 ms 2.54x Intel Skylake-X 573 ms 157 ms 3.65x Intel Haswell 620 ms 162 ms 3.83x AMD Zen 4 (Genoa) 266 ms 52 ms 5.12x AMD Zen 6 (Venice) 229 ms 43 ms 5.33x ARM Neoverse-N1 140 ms 71 ms 1.97x NVIDIA Grace (Neoverse-V2) 62 ms 69 ms 0.90x R=wtc@google.com Test: libyuv_unittest --gtest_filter=*SwapUV*:*NV12ToNV21*:*NV21ToNV12* Bug: 406251841 Change-Id: I9bed5522aedadea13cdf69c27e3cbe633e31dd5b TAG=agy CONV=bb50ac62-0c55-4969-8fff-c71ab3d9a79f Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8356968 Reviewed-by: richard winterton <rrwinterton@gmail.com> Commit-Queue: Frank Barchard <fbarchard@google.com>
This commit is contained in:
parent
fc0dc6c339
commit
e58eeea369
@ -1,6 +1,6 @@
|
||||
Name: libyuv
|
||||
URL: https://chromium.googlesource.com/libyuv/libyuv/
|
||||
Version: 1970
|
||||
Version: 1971
|
||||
Revision: DEPS
|
||||
License: BSD-3-Clause
|
||||
License File: LICENSE
|
||||
|
||||
@ -479,21 +479,21 @@ int UYVYToNV12(const uint8_t* src_uyvy,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Convert NV21 to NV12.
|
||||
// Convert NV12 to NV21.
|
||||
LIBYUV_API
|
||||
int NV21ToNV12(const uint8_t* src_y,
|
||||
int NV12ToNV21(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_vu,
|
||||
int src_stride_vu,
|
||||
const uint8_t* src_uv,
|
||||
int src_stride_uv,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_uv,
|
||||
int dst_stride_uv,
|
||||
uint8_t* dst_vu,
|
||||
int dst_stride_vu,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Alias
|
||||
#define NV12ToNV21 NV21ToNV12
|
||||
#define NV21ToNV12 NV12ToNV21
|
||||
|
||||
LIBYUV_API
|
||||
int YUY2ToY(const uint8_t* src_yuy2,
|
||||
|
||||
@ -405,6 +405,7 @@ extern "C" {
|
||||
#define HAS_INTERPOLATEROW_AVX2
|
||||
#define HAS_INTERPOLATEROW_16_AVX2
|
||||
#define HAS_MULTIPLYROW_16_AVX2
|
||||
#define HAS_SWAPUVROW_AVX2
|
||||
#endif
|
||||
|
||||
// The following are available for AVX512 clang x64 platforms:
|
||||
|
||||
@ -11,6 +11,6 @@
|
||||
#ifndef INCLUDE_LIBYUV_VERSION_H_
|
||||
#define INCLUDE_LIBYUV_VERSION_H_
|
||||
|
||||
#define LIBYUV_VERSION 1970
|
||||
#define LIBYUV_VERSION 1971
|
||||
|
||||
#endif // INCLUDE_LIBYUV_VERSION_H_
|
||||
|
||||
@ -1108,22 +1108,22 @@ void SwapUVPlane(const uint8_t* src_uv,
|
||||
}
|
||||
}
|
||||
|
||||
// Convert NV21 to NV12.
|
||||
// Convert NV12 to NV21.
|
||||
LIBYUV_API
|
||||
int NV21ToNV12(const uint8_t* src_y,
|
||||
int NV12ToNV21(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_vu,
|
||||
int src_stride_vu,
|
||||
const uint8_t* src_uv,
|
||||
int src_stride_uv,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_uv,
|
||||
int dst_stride_uv,
|
||||
uint8_t* dst_vu,
|
||||
int dst_stride_vu,
|
||||
int width,
|
||||
int height) {
|
||||
int halfwidth = (width + 1) >> 1;
|
||||
int halfheight = (height + 1) >> 1;
|
||||
|
||||
if (!src_vu || !dst_uv || width <= 0 || height == 0 || height == INT_MIN) {
|
||||
if (!src_uv || !dst_vu || width <= 0 || height == 0 || height == INT_MIN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1135,11 +1135,11 @@ int NV21ToNV12(const uint8_t* src_y,
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
halfheight = (height + 1) >> 1;
|
||||
src_vu = src_vu + (ptrdiff_t)(halfheight - 1) * src_stride_vu;
|
||||
src_stride_vu = -src_stride_vu;
|
||||
src_uv = src_uv + (ptrdiff_t)(halfheight - 1) * src_stride_uv;
|
||||
src_stride_uv = -src_stride_uv;
|
||||
}
|
||||
|
||||
SwapUVPlane(src_vu, src_stride_vu, dst_uv, dst_stride_uv, halfwidth,
|
||||
SwapUVPlane(src_uv, src_stride_uv, dst_vu, dst_stride_vu, halfwidth,
|
||||
halfheight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -10498,12 +10498,14 @@ void NV21ToYUV24Row_AVX512(const uint8_t* src_y,
|
||||
|
||||
#endif // HAS_NV21ToYUV24ROW_AVX512
|
||||
|
||||
#ifdef HAS_SWAPUVROW_SSSE3
|
||||
#if defined(HAS_SWAPUVROW_SSSE3) || defined(HAS_SWAPUVROW_AVX2)
|
||||
|
||||
// Shuffle table for reversing the bytes.
|
||||
static const uvec8 kShuffleUVToVU = {1u, 0u, 3u, 2u, 5u, 4u, 7u, 6u,
|
||||
9u, 8u, 11u, 10u, 13u, 12u, 15u, 14u};
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SWAPUVROW_SSSE3
|
||||
// Convert UV plane of NV12 to VU of NV21.
|
||||
void SwapUVRow_SSSE3(const uint8_t* src_uv, uint8_t* dst_vu, int width) {
|
||||
asm volatile("movdqu %3,%%xmm5 \n"
|
||||
|
||||
@ -874,6 +874,26 @@ void MirrorUVRow_AVX2(const uint8_t* src_uv, uint8_t* dst_uv, int width) {
|
||||
}
|
||||
#endif // HAS_MIRRORUVROW_AVX2
|
||||
|
||||
#ifdef HAS_SWAPUVROW_AVX2
|
||||
LIBYUV_TARGET_AVX2
|
||||
void SwapUVRow_AVX2(const uint8_t* src_uv, uint8_t* dst_vu, int width) {
|
||||
__m256i ymm_shuf = _mm256_broadcastsi128_si256(
|
||||
_mm_setr_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14));
|
||||
while (width > 0) {
|
||||
__m256i ymm0 = _mm256_loadu_si256((const __m256i*)src_uv);
|
||||
__m256i ymm1 = _mm256_loadu_si256((const __m256i*)(src_uv + 32));
|
||||
ymm0 = _mm256_shuffle_epi8(ymm0, ymm_shuf);
|
||||
ymm1 = _mm256_shuffle_epi8(ymm1, ymm_shuf);
|
||||
_mm256_storeu_si256((__m256i*)dst_vu, ymm0);
|
||||
_mm256_storeu_si256((__m256i*)(dst_vu + 32), ymm1);
|
||||
src_uv += 64;
|
||||
dst_vu += 64;
|
||||
width -= 32;
|
||||
}
|
||||
_mm256_zeroupper();
|
||||
}
|
||||
#endif // HAS_SWAPUVROW_AVX2
|
||||
|
||||
#ifdef HAS_MIRRORSPLITUVROW_AVX2
|
||||
LIBYUV_TARGET_AVX2
|
||||
void MirrorSplitUVRow_AVX2(const uint8_t* src_uv,
|
||||
|
||||
@ -588,6 +588,7 @@ TESTPLANARTOBP(I212, uint16_t, 2, 2, 1, P212, uint16_t, 2, 2, 1, 12)
|
||||
TILE_HEIGHT)
|
||||
#endif
|
||||
|
||||
TESTBPTOBP(NV12, uint8_t, 1, 2, 2, NV21, uint8_t, 1, 2, 2, 8, 1, 1)
|
||||
TESTBPTOBP(NV21, uint8_t, 1, 2, 2, NV12, uint8_t, 1, 2, 2, 8, 1, 1)
|
||||
TESTBPTOBP(NV12, uint8_t, 1, 2, 2, NV12Mirror, uint8_t, 1, 2, 2, 8, 1, 1)
|
||||
TESTBPTOBP(NV12, uint8_t, 1, 2, 2, NV24, uint8_t, 1, 1, 1, 8, 1, 1)
|
||||
|
||||
@ -4794,6 +4794,22 @@ TEST_F(LibYUVPlanarTest, SwapUVRow) {
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user