I422ToRGB24 avx512bw tail and row coalesce

I422ToRGB24Matrix (299x299, repeat=10000)
====================================================================
CPU                        Before       After            Improvement
--------------------------------------------------------------------
Intel Skylake-X            275 ms       213 ms       -22.5% (1.29x)
Intel Ice Lake             225 ms       177 ms       -21.3% (1.27x)
Intel Sapphire Rapids      181 ms       144 ms       -20.4% (1.26x)
Intel Emerald Rapids       167 ms       136 ms       -18.6% (1.23x)
Intel Granite Rapids       170 ms       140 ms       -17.6% (1.21x)
AMD Zen 4 (Genoa)          192 ms       136 ms       -29.2% (1.41x)
AMD Zen 5 (Turin)          102 ms        68 ms       -33.3% (1.50x)
AMD Zen 6 (Venice)         102 ms        60 ms       -41.2% (1.70x)
====================================================================

I422ToRGB24Matrix (298x299, repeat=10000)
====================================================================
CPU                        Before       After            Improvement
--------------------------------------------------------------------
Intel Skylake-X            271 ms       184 ms       -32.1% (1.47x)
Intel Ice Lake             235 ms       152 ms       -35.3% (1.55x)
Intel Sapphire Rapids      199 ms       128 ms       -35.7% (1.55x)
Intel Emerald Rapids       170 ms       121 ms       -28.8% (1.40x)
Intel Granite Rapids       177 ms       125 ms       -29.4% (1.42x)
AMD Zen 4 (Genoa)          185 ms       119 ms       -35.7% (1.55x)
AMD Zen 5 (Turin)          102 ms        59 ms       -42.2% (1.73x)
AMD Zen 6 (Venice)         100 ms        51 ms       -49.0% (1.96x)
====================================================================

Bug: None
Change-Id: Id75e3d1df6d26bc28a252672816a7c438cb664a4
Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8452502
Reviewed-by: richard winterton <rrwinterton@gmail.com>
Commit-Queue: Frank Barchard <fbarchard@google.com>
This commit is contained in:
Frank Barchard 2026-09-23 20:22:05 -07:00 committed by libyuv-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 41a6e684a6
commit 2124173f34
6 changed files with 286 additions and 171 deletions

View File

@ -375,6 +375,7 @@ extern "C" {
#define HAS_RGB24TOARGBROW_AVX512BW
#define HAS_RAWTORGB24ROW_AVX512BW
#define HAS_ARGBSHUFFLEROW_AVX512BW
#define HAS_I422TORGB24ROW_AVX512VBMI
#define HAS_RAWTORGB24ROW_AVX512VBMI
#define HAS_I422TORGB24ROW_AVX512BW
#define HAS_I422TOAR30ROW_AVX512BW
@ -417,7 +418,6 @@ extern "C" {
#define HAS_RAWTORGB24ROW_AVX512BW
#define HAS_RAWTORGB24ROW_AVX512VBMI
#define HAS_ARGBTORGB24ROW_AVX512VBMI
#define HAS_I422TORGB24ROW_AVX512VBMI
#define HAS_CONVERT16TO8ROW_AVX512BW
#define HAS_CONVERT8TO16ROW_AVX512BW
#define HAS_HALFROW_16TO8_AVX512BW
@ -436,6 +436,7 @@ extern "C" {
#define HAS_BLENDPLANEROW_AVX512BW
#define HAS_RGBTOUV444MATRIXROW_AVX512BW
#define HAS_ARGBTOYMATRIXROW_AVX512BW
#define HAS_I422TORGB24ROW_AVX512VBMI
#define HAS_RAWTORGB24ROW_AVX512VBMI
#define HAS_I422TORGB24ROW_AVX512BW
#define HAS_ARGBTOUVMATRIXROW_AVX512BW
@ -5274,12 +5275,6 @@ void NV12ToRGB565Row_Any_AVX2(const uint8_t* y_buf,
uint8_t* dst_ptr,
const struct YuvConstants* yuvconstants,
int width);
void I422ToRGB24Row_Any_AVX512BW(const uint8_t* y_buf,
const uint8_t* u_buf,
const uint8_t* v_buf,
uint8_t* dst_ptr,
const struct YuvConstants* yuvconstants,
int width);
void I400ToARGBRow_C(const uint8_t* src_y,
uint8_t* rgb_buf,

View File

@ -1717,6 +1717,14 @@ int I210ToARGBMatrix(const uint16_t* src_y,
dst_argb = dst_argb + (ptrdiff_t)(height - 1) * dst_stride_argb;
dst_stride_argb = -dst_stride_argb;
}
// Coalesce rows.
if (src_stride_y == width && src_stride_u * 2 == width &&
src_stride_v * 2 == width && dst_stride_argb == width * 4 &&
(ptrdiff_t)width * height <= INT_MAX) {
width *= height;
height = 1;
src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
}
#if defined(HAS_I210TOARGBROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
I210ToARGBRow = I210ToARGBRow_Any_SSSE3;
@ -1897,6 +1905,13 @@ int I410ToARGBMatrix(const uint16_t* src_y,
dst_argb = dst_argb + (ptrdiff_t)(height - 1) * dst_stride_argb;
dst_stride_argb = -dst_stride_argb;
}
// Coalesce rows.
if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
dst_stride_argb == width * 4 && (ptrdiff_t)width * height <= INT_MAX) {
width *= height;
height = 1;
src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
}
#if defined(HAS_I410TOARGBROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
I410ToARGBRow = I410ToARGBRow_Any_SSSE3;
@ -2541,6 +2556,15 @@ int I422AlphaToARGBMatrix(const uint8_t* src_y,
dst_argb = dst_argb + (ptrdiff_t)(height - 1) * dst_stride_argb;
dst_stride_argb = -dst_stride_argb;
}
// Coalesce rows.
if (src_stride_y == width && src_stride_u * 2 == width &&
src_stride_v * 2 == width && src_stride_a == width &&
dst_stride_argb == width * 4 && (ptrdiff_t)width * height <= INT_MAX) {
width *= height;
height = 1;
src_stride_y = src_stride_u = src_stride_v = src_stride_a =
dst_stride_argb = 0;
}
#if defined(HAS_I422ALPHATOARGBROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3;
@ -2692,6 +2716,15 @@ int I444AlphaToARGBMatrix(const uint8_t* src_y,
dst_argb = dst_argb + (ptrdiff_t)(height - 1) * dst_stride_argb;
dst_stride_argb = -dst_stride_argb;
}
// Coalesce rows.
if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
src_stride_a == width && dst_stride_argb == width * 4 &&
(ptrdiff_t)width * height <= INT_MAX) {
width *= height;
height = 1;
src_stride_y = src_stride_u = src_stride_v = src_stride_a =
dst_stride_argb = 0;
}
#if defined(HAS_I444ALPHATOARGBROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
I444AlphaToARGBRow = I444AlphaToARGBRow_Any_SSSE3;
@ -5320,6 +5353,14 @@ int I422ToRGBAMatrix(const uint8_t* src_y,
dst_rgba = dst_rgba + (ptrdiff_t)(height - 1) * dst_stride_rgba;
dst_stride_rgba = -dst_stride_rgba;
}
// Coalesce rows.
if (src_stride_y == width && src_stride_u * 2 == width &&
src_stride_v * 2 == width && dst_stride_rgba == width * 4 &&
(ptrdiff_t)width * height <= INT_MAX) {
width *= height;
height = 1;
src_stride_y = src_stride_u = src_stride_v = dst_stride_rgba = 0;
}
#if defined(HAS_I422TORGBAROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
@ -5695,10 +5736,7 @@ int I420ToRGB24Matrix(const uint8_t* src_y,
#endif
#if defined(HAS_I422TORGB24ROW_AVX512BW)
if (TestCpuFlag(kCpuHasAVX512BW)) {
I422ToRGB24Row = I422ToRGB24Row_Any_AVX512BW;
if (IS_ALIGNED(width, 32)) {
I422ToRGB24Row = I422ToRGB24Row_AVX512BW;
}
I422ToRGB24Row = I422ToRGB24Row_AVX512BW;
}
#endif
#if defined(HAS_I422TORGB24ROW_AVX512VBMI)
@ -5895,6 +5933,14 @@ int I422ToRGB24Matrix(const uint8_t* src_y,
dst_rgb24 = dst_rgb24 + (ptrdiff_t)(height - 1) * dst_stride_rgb24;
dst_stride_rgb24 = -dst_stride_rgb24;
}
// Coalesce rows.
if (src_stride_y == width && src_stride_u * 2 == width &&
src_stride_v * 2 == width && dst_stride_rgb24 == width * 3 &&
(ptrdiff_t)width * height <= INT_MAX) {
width *= height;
height = 1;
src_stride_y = src_stride_u = src_stride_v = dst_stride_rgb24 = 0;
}
#if defined(HAS_I422TORGB24ROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
@ -5913,10 +5959,7 @@ int I422ToRGB24Matrix(const uint8_t* src_y,
#endif
#if defined(HAS_I422TORGB24ROW_AVX512BW)
if (TestCpuFlag(kCpuHasAVX512BW)) {
I422ToRGB24Row = I422ToRGB24Row_Any_AVX512BW;
if (IS_ALIGNED(width, 32)) {
I422ToRGB24Row = I422ToRGB24Row_AVX512BW;
}
I422ToRGB24Row = I422ToRGB24Row_AVX512BW;
}
#endif
#if defined(HAS_I422TORGB24ROW_AVX512VBMI)
@ -6364,6 +6407,14 @@ int I422ToRGB565Matrix(const uint8_t* src_y,
dst_rgb565 = dst_rgb565 + (ptrdiff_t)(height - 1) * dst_stride_rgb565;
dst_stride_rgb565 = -dst_stride_rgb565;
}
// Coalesce rows.
if (src_stride_y == width && src_stride_u * 2 == width &&
src_stride_v * 2 == width && dst_stride_rgb565 == width * 2 &&
(ptrdiff_t)width * height <= INT_MAX) {
width *= height;
height = 1;
src_stride_y = src_stride_u = src_stride_v = dst_stride_rgb565 = 0;
}
#if defined(HAS_I422TORGB565ROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;

View File

@ -420,9 +420,6 @@ ANY31C(I444ToRGB24Row_Any_SSSE3, I444ToRGB24Row_SSSE3, 0, 0, 3, 15)
#ifdef HAS_I422TORGB24ROW_AVX2
ANY31C(I422ToRGB24Row_Any_AVX2, I422ToRGB24Row_AVX2, 1, 0, 3, 15)
#endif
#ifdef HAS_I422TORGB24ROW_AVX512BW
ANY31C(I422ToRGB24Row_Any_AVX512BW, I422ToRGB24Row_AVX512BW, 1, 0, 3, 31)
#endif
#ifdef HAS_I422TOARGBROW_AVX2
ANY31C(I422ToARGBRow_Any_AVX2, I422ToARGBRow_AVX2, 1, 0, 4, 15)
#endif

View File

@ -3506,6 +3506,27 @@ void OMITFP I422ToRGBARow_SSSE3(const uint8_t* y_buf,
"vpord %%zmm3,%%zmm4,%%zmm4 \n" \
"vmovdqa64 %%zmm1,%%zmm3 \n"
#define READYUV422_MASK_AVX512BW \
"mov $-1,%[temp] \n" \
"bzhi %q[width],%[temp],%[temp] \n" \
"kmovd %k[temp],%%k1 \n" \
"vpmovzxbw (%[y_buf]),%%zmm4%{%%k1%}%{z%} \n" \
"mov $-1,%[temp] \n" \
"lea 1(%q[width]),%k[y_buf] \n" \
"shr $1,%k[y_buf] \n" \
"bzhi %q[y_buf],%[temp],%[y_buf] \n" \
"kmovw %k[y_buf],%%k2 \n" \
"vmovdqu8 (%[u_buf]),%%xmm3%{%%k2%}%{z%} \n" \
"vmovdqu8 0x00(%[u_buf],%[v_buf],1),%%xmm1%{%%k2%}%{z%} \n" \
"vpunpcklbw %%xmm1,%%xmm3,%%xmm2 \n" \
"vpunpckhbw %%xmm1,%%xmm3,%%xmm3 \n" \
"vinserti64x2 $1,%%xmm3,%%ymm2,%%ymm3 \n" \
"vmovdqa64 %%zmm16,%%zmm1 \n" \
"vpermi2w %%zmm3,%%zmm3,%%zmm1 \n" \
"vpsllw $8,%%zmm4,%%zmm3 \n" \
"vpord %%zmm3,%%zmm4,%%zmm4 \n" \
"vmovdqa64 %%zmm1,%%zmm3 \n"
// Read 8 UV from 210, upsample to 16 UV
// TODO(fbarchard): Consider vpshufb to replace pack/unpack
// TODO(fbarchard): Consider vunpcklpd to combine the 2 registers into 1.
@ -3854,6 +3875,23 @@ void OMITFP I422ToRGBARow_SSSE3(const uint8_t* y_buf,
"vmovdqu8 %%ymm0,0x40(%[dst_rgb24]) \n" \
"lea 0x60(%[dst_rgb24]),%[dst_rgb24] \n"
// Store masked RGB24 values with VBMI.
#define STORERGB24_MASK_AVX512VBMI \
"lea (%q[width],%q[width],2),%k[width] \n" \
"bzhi %q[width],%[temp],%[y_buf] \n" \
"kmovq %[y_buf],%%k3 \n" \
"xor %k[y_buf],%k[y_buf] \n" \
"sub $0x40,%k[width] \n" \
"cmovg %[temp],%[y_buf] \n" \
"bzhi %q[width],%[y_buf],%[y_buf] \n" \
"kmovd %k[y_buf],%%k4 \n" \
"vpermt2b %%zmm1,%%zmm20,%%zmm0 \n" \
"vmovdqa64 %%zmm0,%%zmm3 \n" \
"vpermt2b %%zmm2,%%zmm21,%%zmm3 \n" \
"vpermt2b %%zmm2,%%zmm22,%%zmm0 \n" \
"vmovdqu8 %%zmm3,(%[dst_rgb24])%{%%k3%} \n" \
"vmovdqu8 %%ymm0,0x40(%[dst_rgb24])%{%%k4%} \n"
// Store 32 RGB24 values with AVX512BW.
#define STORERGB24_AVX512BW \
"vpunpcklbw %%zmm1,%%zmm0,%%zmm0 \n" \
@ -3872,6 +3910,31 @@ void OMITFP I422ToRGBARow_SSSE3(const uint8_t* y_buf,
"vmovdqu8 %%ymm4,0x40(%[dst_rgb24]) \n" \
"lea 0x60(%[dst_rgb24]),%[dst_rgb24] \n"
// Store masked RGB24 values with AVX512BW.
#define STORERGB24_MASK_AVX512BW \
"lea (%q[width],%q[width],2),%k[width] \n" \
"bzhi %q[width],%[temp],%[y_buf] \n" \
"kmovq %[y_buf],%%k3 \n" \
"xor %k[y_buf],%k[y_buf] \n" \
"sub $0x40,%k[width] \n" \
"cmovg %[temp],%[y_buf] \n" \
"bzhi %q[width],%[y_buf],%[y_buf] \n" \
"kmovd %k[y_buf],%%k4 \n" \
"vpunpcklbw %%zmm1,%%zmm0,%%zmm0 \n" \
"vpunpcklbw %%zmm2,%%zmm2,%%zmm2 \n" \
"vmovdqa64 %%zmm0,%%zmm1 \n" \
"vpunpcklwd %%zmm2,%%zmm0,%%zmm0 \n" \
"vpunpckhwd %%zmm2,%%zmm1,%%zmm1 \n" \
"vpshufb %%zmm5,%%zmm0,%%zmm0 \n" \
"vpshufb %%zmm6,%%zmm1,%%zmm1 \n" \
"vpalignr $0xc,%%zmm0,%%zmm1,%%zmm1 \n" \
"vmovdqa64 %%zmm20,%%zmm3 \n" \
"vpermi2q %%zmm1,%%zmm0,%%zmm3 \n" \
"vmovdqa64 %%zmm21,%%zmm4 \n" \
"vpermi2q %%zmm1,%%zmm0,%%zmm4 \n" \
"vmovdqu8 %%zmm3,(%[dst_rgb24])%{%%k3%} \n" \
"vmovdqu8 %%ymm4,0x40(%[dst_rgb24])%{%%k4%} \n"
// Store 32 AR30 values.
#define STOREAR30_AVX512BW \
"vpminsw %%zmm7,%%zmm0,%%zmm0 \n" \
@ -4142,42 +4205,9 @@ void OMITFP I422ToRGB24Row_AVX512VBMI(const uint8_t* y_buf,
"add $0x20,%[width] \n"
"je 99f \n"
// Calculate a mask for the final iteration to deal with the tail.
"mov $-1,%[temp] \n"
"bzhi %q[width],%[temp],%[temp] \n"
"kmovd %k[temp],%%k1 \n"
"vpmovzxbw (%[y_buf]),%%zmm4%{%%k1%}%{z%}\n"
"mov $-1,%[temp] \n"
"lea 1(%q[width]),%k[y_buf] \n"
"shr $1,%k[y_buf] \n"
"bzhi %q[y_buf],%[temp],%[y_buf] \n"
"kmovw %k[y_buf],%%k2 \n"
"vmovdqu8 (%[u_buf]),%%xmm3%{%%k2%}%{z%}\n"
"vmovdqu8 0x00(%[u_buf],%[v_buf],1),%%xmm1%{%%k2%}%{z%}\n"
"lea (%q[width],%q[width],2),%k[width]\n"
"bzhi %q[width],%[temp],%[y_buf] \n"
"kmovq %[y_buf],%%k3 \n"
"xor %k[y_buf],%k[y_buf] \n"
"sub $0x40,%k[width] \n"
"cmovg %[temp],%[y_buf] \n"
"bzhi %q[width],%[y_buf],%[y_buf] \n"
"kmovd %k[y_buf],%%k4 \n"
"vpunpcklbw %%xmm1,%%xmm3,%%xmm2 \n"
"vpunpckhbw %%xmm1,%%xmm3,%%xmm3 \n"
"vinserti64x2 $1,%%xmm3,%%ymm2,%%ymm3 \n"
"vmovdqa64 %%zmm16,%%zmm1 \n"
"vpermi2w %%zmm3,%%zmm3,%%zmm1 \n"
"vpsllw $8,%%zmm4,%%zmm3 \n"
"vpord %%zmm3,%%zmm4,%%zmm4 \n"
"vmovdqa64 %%zmm1,%%zmm3 \n"
READYUV422_MASK_AVX512BW
YUVTORGB_AVX512BW(yuvconstants)
"vpermt2b %%zmm1,%%zmm20,%%zmm0 \n"
"vmovdqa64 %%zmm0,%%zmm3 \n"
"vpermt2b %%zmm2,%%zmm21,%%zmm3 \n"
"vpermt2b %%zmm2,%%zmm22,%%zmm0 \n"
"vmovdqu8 %%zmm3,(%[dst_rgb24])%{%%k3%} \n"
"vmovdqu8 %%ymm0,0x40(%[dst_rgb24])%{%%k4%}\n"
STORERGB24_MASK_AVX512VBMI
"99: \n"
"vzeroupper \n"
@ -4215,6 +4245,7 @@ void OMITFP I422ToRGB24Row_AVX512BW(const uint8_t* y_buf,
uint8_t* dst_rgb24,
const struct YuvConstants* yuvconstants,
int width) {
uintptr_t temp;
asm volatile (
YUVTORGB_SETUP_AVX512BW(yuvconstants)
"vbroadcasti32x4 %[kShuffleMaskARGBToRGB24_1],%%zmm5 \n"
@ -4222,6 +4253,8 @@ void OMITFP I422ToRGB24Row_AVX512BW(const uint8_t* y_buf,
"vmovdqu64 %[kStitchRGB24_0],%%zmm20 \n"
"vmovdqu64 %[kStitchRGB24_1],%%zmm21 \n"
"sub %[u_buf],%[v_buf] \n"
"sub $0x20,%[width] \n"
"jl 2f \n"
LABELALIGN
"1: \n"
@ -4229,13 +4262,24 @@ void OMITFP I422ToRGB24Row_AVX512BW(const uint8_t* y_buf,
YUVTORGB_AVX512BW(yuvconstants)
STORERGB24_AVX512BW
"sub $0x20,%[width] \n"
"jg 1b \n"
"jge 1b \n"
"2: \n"
"add $0x20,%[width] \n"
"je 99f \n"
READYUV422_MASK_AVX512BW
YUVTORGB_AVX512BW(yuvconstants)
STORERGB24_MASK_AVX512BW
"99: \n"
"vzeroupper \n"
: [y_buf]"+r"(y_buf), // %[y_buf]
[u_buf]"+r"(u_buf), // %[u_buf]
[v_buf]"+r"(v_buf), // %[v_buf]
[dst_rgb24]"+r"(dst_rgb24), // %[dst_rgb24]
[width]"+rm"(width) // %[width]
[width]"+r"(width), // %[width]
[temp]"=&r"(temp) // %[temp]
: [yuvconstants]"r"(yuvconstants), // %[yuvconstants]
[quadsplitperm]"r"(kSplitQuadWords), // %[quadsplitperm]
[dquadsplitperm]"r"(kSplitDoubleQuadWords), // %[dquadsplitperm]
@ -4246,7 +4290,8 @@ void OMITFP I422ToRGB24Row_AVX512BW(const uint8_t* y_buf,
[kStitchRGB24_1]"m"(kStitchRGB24_1) // %[kStitchRGB24_1]
: "memory", "cc", YUVTORGB_REGS_AVX512BW
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
"xmm20", "xmm21"
"xmm20", "xmm21",
"k1", "k2", "k3", "k4"
);
}
#endif // defined(HAS_I422TORGB24ROW_AVX512BW)

View File

@ -1907,6 +1907,119 @@ void I422ToRGB24Row_AVX2(const uint8_t* src_y,
#endif // defined(HAS_I422TORGB24ROW_AVX2) ||
// defined(HAS_I422TORGB24ROW_AVX512BW)
#if defined(HAS_I422TORGB24ROW_AVX512VBMI) || \
defined(HAS_I422TORGB24ROW_AVX512BW)
#define READYUV422_AVX512BW \
__m128i xmm_u = _mm_loadu_si128((const __m128i*)src_u); \
__m128i xmm_v = _mm_loadu_si128((const __m128i*)(src_u + offset)); \
src_u += 16; \
__m512i zmm_u_val = _mm512_castsi128_si512(xmm_u); \
__m512i zmm_v_val = _mm512_castsi128_si512(xmm_v); \
zmm_u_val = _mm512_permutexvar_epi64(zmm_split, zmm_u_val); \
zmm_v_val = _mm512_permutexvar_epi64(zmm_split, zmm_v_val); \
__m512i zmm3 = _mm512_unpacklo_epi8(zmm_u_val, zmm_v_val); \
zmm3 = _mm512_permutex_epi64(zmm3, 0xd8); \
zmm3 = _mm512_unpacklo_epi16(zmm3, zmm3); \
__m256i ymm_y = _mm256_loadu_si256((const __m256i*)src_y); \
src_y += 32; \
__m512i zmm4 = _mm512_castsi256_si512(ymm_y); \
zmm4 = _mm512_permutexvar_epi64(zmm_split_y, zmm4); \
zmm4 = _mm512_permutex_epi64(zmm4, 0xd8); \
zmm4 = _mm512_unpacklo_epi8(zmm4, zmm4);
#define READYUV422_MASK_AVX512BW \
__mmask16 mask_uv = (__mmask16)((1u << ((width + 1) >> 1)) - 1u); \
__mmask32 mask_y = (__mmask32)((1u << width) - 1u); \
__m128i xmm_u = _mm_maskz_loadu_epi8(mask_uv, src_u); \
__m128i xmm_v = _mm_maskz_loadu_epi8(mask_uv, src_u + offset); \
__m512i zmm_u_val = _mm512_castsi128_si512(xmm_u); \
__m512i zmm_v_val = _mm512_castsi128_si512(xmm_v); \
zmm_u_val = _mm512_permutexvar_epi64(zmm_split, zmm_u_val); \
zmm_v_val = _mm512_permutexvar_epi64(zmm_split, zmm_v_val); \
__m512i zmm3 = _mm512_unpacklo_epi8(zmm_u_val, zmm_v_val); \
zmm3 = _mm512_permutex_epi64(zmm3, 0xd8); \
zmm3 = _mm512_unpacklo_epi16(zmm3, zmm3); \
__m256i ymm_y = _mm256_maskz_loadu_epi8(mask_y, src_y); \
__m512i zmm4 = _mm512_castsi256_si512(ymm_y); \
zmm4 = _mm512_permutexvar_epi64(zmm_split_y, zmm4); \
zmm4 = _mm512_permutex_epi64(zmm4, 0xd8); \
zmm4 = _mm512_unpacklo_epi8(zmm4, zmm4);
#define YUVTORGB_AVX512BW \
zmm3 = _mm512_sub_epi8(zmm3, zmm_128); \
zmm4 = _mm512_mulhi_epu16(zmm4, zmm_kYToRgb); \
__m512i zmm0 = _mm512_maddubs_epi16(zmm_kUVToB, zmm3); \
__m512i zmm1 = _mm512_maddubs_epi16(zmm_kUVToG, zmm3); \
__m512i zmm2 = _mm512_maddubs_epi16(zmm_kUVToR, zmm3); \
zmm4 = _mm512_add_epi16(zmm4, zmm_kYBiasToRgb); \
zmm0 = _mm512_adds_epi16(zmm0, zmm4); \
zmm1 = _mm512_subs_epi16(zmm4, zmm1); \
zmm2 = _mm512_adds_epi16(zmm2, zmm4); \
zmm0 = _mm512_srai_epi16(zmm0, 6); \
zmm1 = _mm512_srai_epi16(zmm1, 6); \
zmm2 = _mm512_srai_epi16(zmm2, 6); \
zmm0 = _mm512_packus_epi16(zmm0, zmm0); \
zmm1 = _mm512_packus_epi16(zmm1, zmm1); \
zmm2 = _mm512_packus_epi16(zmm2, zmm2);
#define STORERGB24_AVX512VBMI \
__m512i zmm_BG = _mm512_permutex2var_epi8(zmm0, zmm_mask_BG, zmm1); \
__m512i zmm_dst0 = _mm512_permutex2var_epi8(zmm_BG, zmm_mask_DST0, zmm2); \
__m512i zmm_dst1 = _mm512_permutex2var_epi8(zmm_BG, zmm_mask_DST1, zmm2); \
_mm512_storeu_si512((__m512i*)dst_rgb24, zmm_dst0); \
_mm256_storeu_si256((__m256i*)(dst_rgb24 + 64), \
_mm512_castsi512_si256(zmm_dst1)); \
dst_rgb24 += 96;
#define STORERGB24_MASK_AVX512VBMI \
int dst_bytes = width * 3; \
__mmask64 mask_dst0 = \
dst_bytes >= 64 ? ~0ull : (1ull << dst_bytes) - 1ull; \
__mmask32 mask_dst1 = \
dst_bytes > 64 ? (1u << (dst_bytes - 64)) - 1u : 0u; \
__m512i zmm_BG = _mm512_permutex2var_epi8(zmm0, zmm_mask_BG, zmm1); \
__m512i zmm_dst0 = _mm512_permutex2var_epi8(zmm_BG, zmm_mask_DST0, zmm2); \
__m512i zmm_dst1 = _mm512_permutex2var_epi8(zmm_BG, zmm_mask_DST1, zmm2); \
_mm512_mask_storeu_epi8(dst_rgb24, mask_dst0, zmm_dst0); \
_mm256_mask_storeu_epi8(dst_rgb24 + 64, mask_dst1, \
_mm512_castsi512_si256(zmm_dst1));
#define STORERGB24_AVX512BW \
__m512i zmm_bg = _mm512_unpacklo_epi8(zmm0, zmm1); \
__m512i zmm_rr = _mm512_unpacklo_epi8(zmm2, zmm2); \
__m512i zmm_lo = _mm512_unpacklo_epi16(zmm_bg, zmm_rr); \
__m512i zmm_hi = _mm512_unpackhi_epi16(zmm_bg, zmm_rr); \
zmm_lo = _mm512_shuffle_epi8(zmm_lo, zmm_shuf0); \
zmm_hi = _mm512_shuffle_epi8(zmm_hi, zmm_shuf1); \
zmm_hi = _mm512_alignr_epi8(zmm_hi, zmm_lo, 12); \
__m512i zmm_dst0 = _mm512_permutex2var_epi64(zmm_lo, zmm_stitch0, zmm_hi); \
__m512i zmm_dst1 = _mm512_permutex2var_epi64(zmm_lo, zmm_stitch1, zmm_hi); \
_mm512_storeu_si512((__m512i*)dst_rgb24, zmm_dst0); \
_mm256_storeu_si256((__m256i*)(dst_rgb24 + 64), \
_mm512_castsi512_si256(zmm_dst1)); \
dst_rgb24 += 96;
#define STORERGB24_MASK_AVX512BW \
int dst_bytes = width * 3; \
__mmask64 mask_dst0 = \
dst_bytes >= 64 ? ~0ull : (1ull << dst_bytes) - 1ull; \
__mmask32 mask_dst1 = \
dst_bytes > 64 ? (1u << (dst_bytes - 64)) - 1u : 0u; \
__m512i zmm_bg = _mm512_unpacklo_epi8(zmm0, zmm1); \
__m512i zmm_rr = _mm512_unpacklo_epi8(zmm2, zmm2); \
__m512i zmm_lo = _mm512_unpacklo_epi16(zmm_bg, zmm_rr); \
__m512i zmm_hi = _mm512_unpackhi_epi16(zmm_bg, zmm_rr); \
zmm_lo = _mm512_shuffle_epi8(zmm_lo, zmm_shuf0); \
zmm_hi = _mm512_shuffle_epi8(zmm_hi, zmm_shuf1); \
zmm_hi = _mm512_alignr_epi8(zmm_hi, zmm_lo, 12); \
__m512i zmm_dst0 = _mm512_permutex2var_epi64(zmm_lo, zmm_stitch0, zmm_hi); \
__m512i zmm_dst1 = _mm512_permutex2var_epi64(zmm_lo, zmm_stitch1, zmm_hi); \
_mm512_mask_storeu_epi8(dst_rgb24, mask_dst0, zmm_dst0); \
_mm256_mask_storeu_epi8(dst_rgb24 + 64, mask_dst1, \
_mm512_castsi512_si256(zmm_dst1));
#endif // defined(HAS_I422TORGB24ROW_AVX512VBMI) ||
// defined(HAS_I422TORGB24ROW_AVX512BW)
#ifdef HAS_I422TORGB24ROW_AVX512VBMI
LIBYUV_TARGET_AVX512VBMI
void I422ToRGB24Row_AVX512VBMI(const uint8_t* src_y,
@ -1958,61 +2071,16 @@ void I422ToRGB24Row_AVX512VBMI(const uint8_t* src_y,
ptrdiff_t offset = src_v - src_u;
while (width >= 32) {
// READYUV422_AVX512BW
__m128i xmm_u = _mm_loadu_si128((const __m128i*)src_u);
__m128i xmm_v = _mm_loadu_si128((const __m128i*)(src_u + offset));
src_u += 16;
__m512i zmm_u_val = _mm512_castsi128_si512(xmm_u);
__m512i zmm_v_val = _mm512_castsi128_si512(xmm_v);
zmm_u_val = _mm512_permutexvar_epi64(zmm_split, zmm_u_val);
zmm_v_val = _mm512_permutexvar_epi64(zmm_split, zmm_v_val);
__m512i zmm3 = _mm512_unpacklo_epi8(zmm_u_val, zmm_v_val);
zmm3 = _mm512_permutex_epi64(zmm3, 0xd8);
zmm3 = _mm512_unpacklo_epi16(zmm3, zmm3);
__m256i ymm_y = _mm256_loadu_si256((const __m256i*)src_y);
src_y += 32;
__m512i zmm4 = _mm512_castsi256_si512(ymm_y);
zmm4 = _mm512_permutexvar_epi64(zmm_split_y, zmm4);
zmm4 = _mm512_permutex_epi64(zmm4, 0xd8);
zmm4 = _mm512_unpacklo_epi8(zmm4, zmm4);
// YUVTORGB_AVX512BW
zmm3 = _mm512_sub_epi8(zmm3, zmm_128);
zmm4 = _mm512_mulhi_epu16(zmm4, zmm_kYToRgb);
__m512i zmm0 = _mm512_maddubs_epi16(zmm_kUVToB, zmm3);
__m512i zmm1 = _mm512_maddubs_epi16(zmm_kUVToG, zmm3);
__m512i zmm2 = _mm512_maddubs_epi16(zmm_kUVToR, zmm3);
zmm4 = _mm512_add_epi16(zmm4, zmm_kYBiasToRgb);
zmm0 = _mm512_adds_epi16(zmm0, zmm4);
zmm1 = _mm512_subs_epi16(zmm4, zmm1);
zmm2 = _mm512_adds_epi16(zmm2, zmm4);
zmm0 = _mm512_srai_epi16(zmm0, 6);
zmm1 = _mm512_srai_epi16(zmm1, 6);
zmm2 = _mm512_srai_epi16(zmm2, 6);
zmm0 = _mm512_packus_epi16(zmm0, zmm0);
zmm1 = _mm512_packus_epi16(zmm1, zmm1);
zmm2 = _mm512_packus_epi16(zmm2, zmm2);
// STORERGB24_AVX512VBMI
__m512i zmm_BG = _mm512_permutex2var_epi8(zmm0, zmm_mask_BG, zmm1);
__m512i zmm_dst0 = _mm512_permutex2var_epi8(zmm_BG, zmm_mask_DST0, zmm2);
__m512i zmm_dst1 = _mm512_permutex2var_epi8(zmm_BG, zmm_mask_DST1, zmm2);
_mm512_storeu_si512((__m512i*)dst_rgb24, zmm_dst0);
_mm256_storeu_si256((__m256i*)(dst_rgb24 + 64), _mm512_castsi512_si256(zmm_dst1));
dst_rgb24 += 96;
READYUV422_AVX512BW
YUVTORGB_AVX512BW
STORERGB24_AVX512VBMI
width -= 32;
}
if (width > 0) {
READYUV422_MASK_AVX512BW
YUVTORGB_AVX512BW
STORERGB24_MASK_AVX512VBMI
}
_mm256_zeroupper();
}
#endif // HAS_I422TORGB24ROW_AVX512VBMI
@ -2050,72 +2118,31 @@ void I422ToRGB24Row_AVX512BW(const uint8_t* src_y,
ptrdiff_t offset = src_v - src_u;
while (width >= 32) {
// READYUV422_AVX512BW
__m128i xmm_u = _mm_loadu_si128((const __m128i*)src_u);
__m128i xmm_v = _mm_loadu_si128((const __m128i*)(src_u + offset));
src_u += 16;
__m512i zmm_u_val = _mm512_castsi128_si512(xmm_u);
__m512i zmm_v_val = _mm512_castsi128_si512(xmm_v);
zmm_u_val = _mm512_permutexvar_epi64(zmm_split, zmm_u_val);
zmm_v_val = _mm512_permutexvar_epi64(zmm_split, zmm_v_val);
__m512i zmm3 = _mm512_unpacklo_epi8(zmm_u_val, zmm_v_val);
zmm3 = _mm512_permutex_epi64(zmm3, 0xd8);
zmm3 = _mm512_unpacklo_epi16(zmm3, zmm3);
__m256i ymm_y = _mm256_loadu_si256((const __m256i*)src_y);
src_y += 32;
__m512i zmm4 = _mm512_castsi256_si512(ymm_y);
zmm4 = _mm512_permutexvar_epi64(zmm_split_y, zmm4);
zmm4 = _mm512_permutex_epi64(zmm4, 0xd8);
zmm4 = _mm512_unpacklo_epi8(zmm4, zmm4);
// YUVTORGB_AVX512BW
zmm3 = _mm512_sub_epi8(zmm3, zmm_128);
zmm4 = _mm512_mulhi_epu16(zmm4, zmm_kYToRgb);
__m512i zmm0 = _mm512_maddubs_epi16(zmm_kUVToB, zmm3);
__m512i zmm1 = _mm512_maddubs_epi16(zmm_kUVToG, zmm3);
__m512i zmm2 = _mm512_maddubs_epi16(zmm_kUVToR, zmm3);
zmm4 = _mm512_add_epi16(zmm4, zmm_kYBiasToRgb);
zmm0 = _mm512_adds_epi16(zmm0, zmm4);
zmm1 = _mm512_subs_epi16(zmm4, zmm1);
zmm2 = _mm512_adds_epi16(zmm2, zmm4);
zmm0 = _mm512_srai_epi16(zmm0, 6);
zmm1 = _mm512_srai_epi16(zmm1, 6);
zmm2 = _mm512_srai_epi16(zmm2, 6);
zmm0 = _mm512_packus_epi16(zmm0, zmm0);
zmm1 = _mm512_packus_epi16(zmm1, zmm1);
zmm2 = _mm512_packus_epi16(zmm2, zmm2);
// STORERGB24_AVX512BW
__m512i zmm_bg = _mm512_unpacklo_epi8(zmm0, zmm1);
__m512i zmm_rr = _mm512_unpacklo_epi8(zmm2, zmm2);
__m512i zmm_lo = _mm512_unpacklo_epi16(zmm_bg, zmm_rr);
__m512i zmm_hi = _mm512_unpackhi_epi16(zmm_bg, zmm_rr);
zmm_lo = _mm512_shuffle_epi8(zmm_lo, zmm_shuf0);
zmm_hi = _mm512_shuffle_epi8(zmm_hi, zmm_shuf1);
zmm_hi = _mm512_alignr_epi8(zmm_hi, zmm_lo, 12);
__m512i zmm_dst0 = _mm512_permutex2var_epi64(zmm_lo, zmm_stitch0, zmm_hi);
__m512i zmm_dst1 = _mm512_permutex2var_epi64(zmm_lo, zmm_stitch1, zmm_hi);
_mm512_storeu_si512((__m512i*)dst_rgb24, zmm_dst0);
_mm256_storeu_si256((__m256i*)(dst_rgb24 + 64), _mm512_castsi512_si256(zmm_dst1));
dst_rgb24 += 96;
READYUV422_AVX512BW
YUVTORGB_AVX512BW
STORERGB24_AVX512BW
width -= 32;
}
if (width > 0) {
READYUV422_MASK_AVX512BW
YUVTORGB_AVX512BW
STORERGB24_MASK_AVX512BW
}
_mm256_zeroupper();
}
#endif // HAS_I422TORGB24ROW_AVX512BW
#if defined(HAS_I422TORGB24ROW_AVX512VBMI) || \
defined(HAS_I422TORGB24ROW_AVX512BW)
#undef READYUV422_AVX512BW
#undef READYUV422_MASK_AVX512BW
#undef YUVTORGB_AVX512BW
#undef STORERGB24_AVX512VBMI
#undef STORERGB24_MASK_AVX512VBMI
#undef STORERGB24_AVX512BW
#undef STORERGB24_MASK_AVX512BW
#endif
#ifdef HAS_I422TOAR30ROW_AVX512BW
LIBYUV_TARGET_AVX512BW
void I422ToAR30Row_AVX512BW(const uint8_t* src_y,

View File

@ -331,8 +331,8 @@ TESTPLANARTOB(V422, 2, 1, ARGB, 4, 4, 1)
TESTPLANARTOB(V422, 2, 1, ABGR, 4, 4, 1)
TESTPLANARTOB(I422, 2, 1, BGRA, 4, 4, 1)
TESTPLANARTOB(I422, 2, 1, RGBA, 4, 4, 1)
TESTPLANARTOB(I422, 1, 1, RGB24, 3, 3, 1)
TESTPLANARTOB(I422, 1, 1, RAW, 3, 3, 1)
TESTPLANARTOB(I422, 2, 1, RGB24, 3, 3, 1)
TESTPLANARTOB(I422, 2, 1, RAW, 3, 3, 1)
TESTPLANARTOB(I444, 1, 1, ARGB, 4, 4, 1)
TESTPLANARTOB(I444, 1, 1, ABGR, 4, 4, 1)
TESTPLANARTOB(I444, 1, 1, RGB24, 3, 3, 1)