From a0fa6329391922faca64955c1a7bf635ab87d833 Mon Sep 17 00:00:00 2001 From: Frank Barchard Date: Mon, 24 Aug 2026 19:07:15 -0700 Subject: [PATCH] Add AVX2 row functions for RGB565, ARGB1555, and ARGB4444 On Icelake: Was C I420ToARGB1555_Opt (1230 ms) I420ToARGB4444_Opt (1195 ms) I420ToRGB565_Opt (1141 ms) Now AVX2 I420ToARGB1555_Opt (372 ms) I420ToARGB4444_Opt (397 ms) I420ToRGB565_Opt (347 ms) I420ToRGB24Filter_Opt (567 ms) I420ToRGB565Dither_Opt (418 ms) I420ToARGBFilter_Opt (381 ms) I420ToRGBA_Opt (304 ms) I420ToBGRA_Opt (296 ms) I420ToARGB_Opt (257 ms) I420ToABGR_Opt (254 ms) I420ToAR30_Opt (215 ms) I420ToRGB24_Opt (205 ms) I420ToRAW_Opt (193 ms) Bug: None Change-Id: I36cf95d29ba85ae63c549fef7f55cb1fe0f95d8e Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8282746 Reviewed-by: richard winterton Commit-Queue: Frank Barchard --- README.chromium | 2 +- include/libyuv/row.h | 111 ++++++++++++++++++++++++++++++++ include/libyuv/version.h | 2 +- source/row_any.cc | 4 +- source/row_common.cc | 8 +-- source/row_gcc.cc | 118 ++++++++++++++++++++++++++++++++++ source/row_win.cc | 134 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 372 insertions(+), 7 deletions(-) diff --git a/README.chromium b/README.chromium index 64c0968d4..4bd9bdd00 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: https://chromium.googlesource.com/libyuv/libyuv/ -Version: 1963 +Version: 1964 Revision: DEPS License: BSD-3-Clause License File: LICENSE diff --git a/include/libyuv/row.h b/include/libyuv/row.h index c8ed007e3..e57077bd5 100644 --- a/include/libyuv/row.h +++ b/include/libyuv/row.h @@ -47,6 +47,9 @@ extern "C" { #define HAS_I422TOARGBROW_SSSE3 #define HAS_I422TORGB24ROW_SSSE3 #define HAS_I422TORGBBAROW_SSSE3 +#define HAS_I422TORGB565ROW_SSSE3 +#define HAS_I422TOARGB1555ROW_SSSE3 +#define HAS_I422TOARGB4444ROW_SSSE3 #define HAS_I422TOUYVYROW_SSE2 #define HAS_I422TOYUY2ROW_SSE2 #define HAS_I444TOARGBROW_SSSE3 @@ -55,6 +58,7 @@ extern "C" { #define HAS_MIRRORROW_SSSE3 #define HAS_NV12TOARGBROW_SSSE3 #define HAS_NV12TORGB24ROW_SSSE3 +#define HAS_NV12TORGB565ROW_SSSE3 #define HAS_NV21TOARGBROW_SSSE3 #define HAS_NV21TORGB24ROW_SSSE3 #define HAS_RAWTOARGBROW_SSSE3 @@ -158,6 +162,9 @@ extern "C" { #define HAS_I422TOARGBROW_AVX2 #define HAS_I422TORGB24ROW_AVX2 #define HAS_I422TORGBAROW_AVX2 +#define HAS_I422TORGB565ROW_AVX2 +#define HAS_I422TOARGB1555ROW_AVX2 +#define HAS_I422TOARGB4444ROW_AVX2 #define HAS_I444TOARGBROW_AVX2 #define HAS_I444TORGB24ROW_AVX2 #define HAS_J400TOARGBROW_AVX2 @@ -165,6 +172,7 @@ extern "C" { #define HAS_MIRRORSPLITUVROW_AVX2 #define HAS_NV12TOARGBROW_AVX2 #define HAS_NV12TORGB24ROW_AVX2 +#define HAS_NV12TORGB565ROW_AVX2 #define HAS_NV21TOARGBROW_AVX2 #define HAS_NV21TORGB24ROW_AVX2 #define HAS_SPLITUVROW_AVX2 @@ -272,6 +280,9 @@ extern "C" { #define HAS_ARGBTOAR64ROW_AVX2 #define HAS_ARGBTORAWROW_AVX2 #define HAS_ARGBTORGB24ROW_AVX2 +#define HAS_ARGBTORGB565ROW_AVX2 +#define HAS_ARGBTOARGB1555ROW_AVX2 +#define HAS_ARGBTOARGB4444ROW_AVX2 #define HAS_ARGBTOUVMATRIXROW_AVX2 #define HAS_RGBTOUVMATRIXROW_AVX2 #define HAS_RGB565TOUVMATRIXROW_AVX2 @@ -348,6 +359,14 @@ extern "C" { #define HAS_ARGB1555TOARGBROW_AVX2 #define HAS_ARGB4444TOARGBROW_AVX2 #define HAS_ARGBSHUFFLEROW_AVX2 +#define HAS_ARGBTORGB565ROW_AVX2 +#define HAS_ARGBTORGB565DITHERROW_AVX2 +#define HAS_ARGBTOARGB1555ROW_AVX2 +#define HAS_ARGBTOARGB4444ROW_AVX2 +#define HAS_I422TORGB565ROW_AVX2 +#define HAS_I422TOARGB1555ROW_AVX2 +#define HAS_I422TOARGB4444ROW_AVX2 +#define HAS_NV12TORGB565ROW_AVX2 #if defined(__x86_64__) || defined(_M_X64) #define HAS_I422TOAR30ROW_AVX2 #define HAS_RAWTOARGBROW_AVX512BW @@ -4486,6 +4505,42 @@ void I422ToRGBARow_AVX2(const uint8_t* y_buf, uint8_t* dst_rgba, const struct YuvConstants* yuvconstants, int width); +void I422ToRGB565Row_AVX2(const uint8_t* src_y, + const uint8_t* src_u, + const uint8_t* src_v, + uint8_t* dst_rgb565, + const struct YuvConstants* yuvconstants, + int width); +void I422ToARGB1555Row_AVX2(const uint8_t* src_y, + const uint8_t* src_u, + const uint8_t* src_v, + uint8_t* dst_argb1555, + const struct YuvConstants* yuvconstants, + int width); +void I422ToARGB4444Row_AVX2(const uint8_t* src_y, + const uint8_t* src_u, + const uint8_t* src_v, + uint8_t* dst_argb4444, + const struct YuvConstants* yuvconstants, + int width); +void I422ToRGB565Row_SSSE3(const uint8_t* src_y, + const uint8_t* src_u, + const uint8_t* src_v, + uint8_t* dst_rgb565, + const struct YuvConstants* yuvconstants, + int width); +void I422ToARGB1555Row_SSSE3(const uint8_t* src_y, + const uint8_t* src_u, + const uint8_t* src_v, + uint8_t* dst_argb1555, + const struct YuvConstants* yuvconstants, + int width); +void I422ToARGB4444Row_SSSE3(const uint8_t* src_y, + const uint8_t* src_u, + const uint8_t* src_v, + uint8_t* dst_argb4444, + const struct YuvConstants* yuvconstants, + int width); void I444ToARGBRow_SSSE3(const uint8_t* y_buf, const uint8_t* u_buf, const uint8_t* v_buf, @@ -4694,6 +4749,16 @@ void NV21ToRGB24Row_AVX2(const uint8_t* src_y, uint8_t* dst_rgb24, const struct YuvConstants* yuvconstants, int width); +void NV12ToRGB565Row_SSSE3(const uint8_t* src_y, + const uint8_t* src_uv, + uint8_t* dst_rgb565, + const struct YuvConstants* yuvconstants, + int width); +void NV12ToRGB565Row_AVX2(const uint8_t* src_y, + const uint8_t* src_uv, + uint8_t* dst_rgb565, + const struct YuvConstants* yuvconstants, + int width); void NV21ToYUV24Row_SSSE3(const uint8_t* src_y, const uint8_t* src_vu, uint8_t* dst_yuv24, @@ -5126,6 +5191,52 @@ void I422ToRGB24Row_Any_AVX2(const uint8_t* y_buf, uint8_t* dst_ptr, const struct YuvConstants* yuvconstants, int width); +void I422ToRGB565Row_Any_SSSE3(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 I422ToARGB1555Row_Any_SSSE3(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 I422ToARGB4444Row_Any_SSSE3(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 NV12ToRGB565Row_Any_SSSE3(const uint8_t* y_buf, + const uint8_t* uv_buf, + uint8_t* dst_ptr, + const struct YuvConstants* yuvconstants, + int width); +void I422ToRGB565Row_Any_AVX2(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 I422ToARGB1555Row_Any_AVX2(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 I422ToARGB4444Row_Any_AVX2(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 NV12ToRGB565Row_Any_AVX2(const uint8_t* y_buf, + const uint8_t* uv_buf, + uint8_t* dst_ptr, + const struct YuvConstants* yuvconstants, + int width); void I422ToRGB24Row_Any_AVX512VBMI(const uint8_t* y_buf, const uint8_t* u_buf, const uint8_t* v_buf, diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 12eb1503d..8ee46e791 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,6 +11,6 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 1963 +#define LIBYUV_VERSION 1964 #endif // INCLUDE_LIBYUV_VERSION_H_ diff --git a/source/row_any.cc b/source/row_any.cc index 1b41f3dad..4f820491a 100644 --- a/source/row_any.cc +++ b/source/row_any.cc @@ -1017,8 +1017,10 @@ ANY11(ARGBToRAWRow_Any_AVX2, ARGBToRAWRow_AVX2, 0, 4, 3, 31) #if defined(HAS_ARGBTORGB565ROW_AVX2) ANY11(ARGBToRGB565Row_Any_AVX2, ARGBToRGB565Row_AVX2, 0, 4, 2, 7) #endif -#if defined(HAS_ARGBTOARGB4444ROW_AVX2) +#if defined(HAS_ARGBTOARGB1555ROW_AVX2) ANY11(ARGBToARGB1555Row_Any_AVX2, ARGBToARGB1555Row_AVX2, 0, 4, 2, 7) +#endif +#if defined(HAS_ARGBTOARGB4444ROW_AVX2) ANY11(ARGBToARGB4444Row_Any_AVX2, ARGBToARGB4444Row_AVX2, 0, 4, 2, 7) #endif #if defined(HAS_ABGRTOAR30ROW_SSSE3) diff --git a/source/row_common.cc b/source/row_common.cc index d0dcc3b43..839e5c851 100644 --- a/source/row_common.cc +++ b/source/row_common.cc @@ -4071,7 +4071,7 @@ void I422ToRGB565Row_SSSE3(const uint8_t* src_y, while (width > 0) { int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, yuvconstants, twidth); - ARGBToRGB565Row_SSE2(row, dst_rgb565, twidth); + ARGBToRGB565Row_C(row, dst_rgb565, twidth); src_y += twidth; src_u += twidth / 2; src_v += twidth / 2; @@ -4093,7 +4093,7 @@ void I422ToARGB1555Row_SSSE3(const uint8_t* src_y, while (width > 0) { int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, yuvconstants, twidth); - ARGBToARGB1555Row_SSE2(row, dst_argb1555, twidth); + ARGBToARGB1555Row_C(row, dst_argb1555, twidth); src_y += twidth; src_u += twidth / 2; src_v += twidth / 2; @@ -4115,7 +4115,7 @@ void I422ToARGB4444Row_SSSE3(const uint8_t* src_y, while (width > 0) { int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, yuvconstants, twidth); - ARGBToARGB4444Row_SSE2(row, dst_argb4444, twidth); + ARGBToARGB4444Row_C(row, dst_argb4444, twidth); src_y += twidth; src_u += twidth / 2; src_v += twidth / 2; @@ -4136,7 +4136,7 @@ void NV12ToRGB565Row_SSSE3(const uint8_t* src_y, while (width > 0) { int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; NV12ToARGBRow_SSSE3(src_y, src_uv, row, yuvconstants, twidth); - ARGBToRGB565Row_SSE2(row, dst_rgb565, twidth); + ARGBToRGB565Row_C(row, dst_rgb565, twidth); src_y += twidth; src_uv += twidth; dst_rgb565 += twidth * 2; diff --git a/source/row_gcc.cc b/source/row_gcc.cc index 9cc30799a..c69843f47 100644 --- a/source/row_gcc.cc +++ b/source/row_gcc.cc @@ -921,6 +921,124 @@ void ARGBToRGB565DitherRow_AVX2(const uint8_t* src, } #endif // HAS_ARGBTORGB565DITHERROW_AVX2 +#ifdef HAS_ARGBTORGB565ROW_AVX2 +void ARGBToRGB565Row_AVX2(const uint8_t* src, uint8_t* dst, int width) { + asm volatile( + "vpcmpeqb %%ymm3,%%ymm3,%%ymm3 \n" + "vpsrld $0x1b,%%ymm3,%%ymm3 \n" + "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" + "vpsrld $0x1a,%%ymm4,%%ymm4 \n" + "vpslld $0x5,%%ymm4,%%ymm4 \n" + "vpslld $0xb,%%ymm3,%%ymm5 \n" + + LABELALIGN + "1: \n" + "vmovdqu (%0),%%ymm0 \n" + "vpsrld $0x5,%%ymm0,%%ymm2 \n" + "vpsrld $0x3,%%ymm0,%%ymm1 \n" + "vpsrld $0x8,%%ymm0,%%ymm0 \n" + "vpand %%ymm4,%%ymm2,%%ymm2 \n" + "vpand %%ymm3,%%ymm1,%%ymm1 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpor %%ymm2,%%ymm1,%%ymm1 \n" + "vpor %%ymm1,%%ymm0,%%ymm0 \n" + "vpackusdw %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "lea 0x20(%0),%0 \n" + "vmovdqu %%xmm0,(%1) \n" + "lea 0x10(%1),%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); +} +#endif // HAS_ARGBTORGB565ROW_AVX2 + +#ifdef HAS_ARGBTOARGB1555ROW_AVX2 +void ARGBToARGB1555Row_AVX2(const uint8_t* src, uint8_t* dst, int width) { + asm volatile( + "vpcmpeqb %%ymm3,%%ymm3,%%ymm3 \n" + "vpslld $0x1f,%%ymm3,%%ymm6 \n" + "vpsrld $0x10,%%ymm6,%%ymm6 \n" + "vpsrld $0x1b,%%ymm3,%%ymm3 \n" + "vpslld $0x5,%%ymm3,%%ymm4 \n" + "vpslld $0xa,%%ymm3,%%ymm5 \n" + + LABELALIGN + "1: \n" + "vmovdqu (%0),%%ymm0 \n" + "vpsrld $0x6,%%ymm0,%%ymm2 \n" + "vpsrld $0x3,%%ymm0,%%ymm1 \n" + "vpsrld $0x10,%%ymm0,%%ymm7 \n" + "vpsrld $0x9,%%ymm0,%%ymm0 \n" + "vpand %%ymm4,%%ymm2,%%ymm2 \n" + "vpand %%ymm3,%%ymm1,%%ymm1 \n" + "vpand %%ymm6,%%ymm7,%%ymm7 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpor %%ymm2,%%ymm1,%%ymm1 \n" + "vpor %%ymm7,%%ymm0,%%ymm0 \n" + "vpor %%ymm1,%%ymm0,%%ymm0 \n" + "vpackusdw %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "lea 0x20(%0),%0 \n" + "vmovdqu %%xmm0,(%1) \n" + "lea 0x10(%1),%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", + "xmm7"); +} +#endif // HAS_ARGBTOARGB1555ROW_AVX2 + +#ifdef HAS_ARGBTOARGB4444ROW_AVX2 +void ARGBToARGB4444Row_AVX2(const uint8_t* src, uint8_t* dst, int width) { + asm volatile( + "vpcmpeqb %%ymm3,%%ymm3,%%ymm3 \n" + "vpsrld $0x1c,%%ymm3,%%ymm3 \n" + "vpslld $0x4,%%ymm3,%%ymm4 \n" + "vpslld $0x8,%%ymm3,%%ymm5 \n" + "vpslld $0xc,%%ymm3,%%ymm6 \n" + + LABELALIGN + "1: \n" + "vmovdqu (%0),%%ymm0 \n" + "vpsrld $0x8,%%ymm0,%%ymm2 \n" + "vpsrld $0x4,%%ymm0,%%ymm1 \n" + "vpsrld $0x10,%%ymm0,%%ymm7 \n" + "vpsrld $0xc,%%ymm0,%%ymm0 \n" + "vpand %%ymm4,%%ymm2,%%ymm2 \n" + "vpand %%ymm3,%%ymm1,%%ymm1 \n" + "vpand %%ymm6,%%ymm7,%%ymm7 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpor %%ymm2,%%ymm1,%%ymm1 \n" + "vpor %%ymm7,%%ymm0,%%ymm0 \n" + "vpor %%ymm1,%%ymm0,%%ymm0 \n" + "vpackusdw %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "lea 0x20(%0),%0 \n" + "vmovdqu %%xmm0,(%1) \n" + "lea 0x10(%1),%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", + "xmm7"); +} +#endif // HAS_ARGBTOARGB4444ROW_AVX2 + #endif // HAS_RGB24TOARGBROW_SSSE3 /* diff --git a/source/row_win.cc b/source/row_win.cc index 86eac555d..818d04d66 100644 --- a/source/row_win.cc +++ b/source/row_win.cc @@ -938,6 +938,140 @@ void ARGB4444ToARGBRow_AVX2(const uint8_t* src_argb4444, } #endif +#ifdef HAS_ARGBTORGB565DITHERROW_AVX2 +LIBYUV_TARGET_AVX2 +void ARGBToRGB565DitherRow_AVX2(const uint8_t* src_argb, + uint8_t* dst_rgb, + uint32_t dither4, + int width) { + __m128i dither_shuf = + _mm_setr_epi8(0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3); + __m128i d128 = _mm_shuffle_epi8(_mm_cvtsi32_si128((int)dither4), dither_shuf); + __m256i ymm_dither = _mm256_broadcastsi128_si256(d128); + __m256i mask_b = _mm256_set1_epi32(0x0000001f); + __m256i mask_g = _mm256_set1_epi32(0x000007e0); + __m256i mask_r = _mm256_set1_epi32(0x0000f800); + + while (width > 0) { + __m256i ymm0 = _mm256_loadu_si256((const __m256i*)src_argb); + ymm0 = _mm256_adds_epu8(ymm0, ymm_dither); + __m256i ymm2 = _mm256_srli_epi32(ymm0, 5); + __m256i ymm1 = _mm256_srli_epi32(ymm0, 3); + ymm0 = _mm256_srli_epi32(ymm0, 8); + ymm2 = _mm256_and_si256(ymm2, mask_g); + ymm1 = _mm256_and_si256(ymm1, mask_b); + ymm0 = _mm256_and_si256(ymm0, mask_r); + ymm1 = _mm256_or_si256(ymm2, ymm1); + ymm0 = _mm256_or_si256(ymm1, ymm0); + ymm0 = _mm256_packus_epi32(ymm0, ymm0); + ymm0 = _mm256_permute4x64_epi64(ymm0, 0xd8); + _mm_storeu_si128((__m128i*)dst_rgb, _mm256_castsi256_si128(ymm0)); + src_argb += 32; + dst_rgb += 16; + width -= 8; + } + _mm256_zeroupper(); +} +#endif + +#ifdef HAS_ARGBTORGB565ROW_AVX2 +LIBYUV_TARGET_AVX2 +void ARGBToRGB565Row_AVX2(const uint8_t* src_argb, + uint8_t* dst_rgb, + int width) { + __m256i mask_b = _mm256_set1_epi32(0x0000001f); + __m256i mask_g = _mm256_set1_epi32(0x000007e0); + __m256i mask_r = _mm256_set1_epi32(0x0000f800); + + while (width > 0) { + __m256i ymm0 = _mm256_loadu_si256((const __m256i*)src_argb); + __m256i ymm2 = _mm256_srli_epi32(ymm0, 5); + __m256i ymm1 = _mm256_srli_epi32(ymm0, 3); + ymm0 = _mm256_srli_epi32(ymm0, 8); + ymm2 = _mm256_and_si256(ymm2, mask_g); + ymm1 = _mm256_and_si256(ymm1, mask_b); + ymm0 = _mm256_and_si256(ymm0, mask_r); + ymm1 = _mm256_or_si256(ymm2, ymm1); + ymm0 = _mm256_or_si256(ymm1, ymm0); + ymm0 = _mm256_packus_epi32(ymm0, ymm0); + ymm0 = _mm256_permute4x64_epi64(ymm0, 0xd8); + _mm_storeu_si128((__m128i*)dst_rgb, _mm256_castsi256_si128(ymm0)); + src_argb += 32; + dst_rgb += 16; + width -= 8; + } + _mm256_zeroupper(); +} +#endif + +#ifdef HAS_ARGBTOARGB1555ROW_AVX2 +LIBYUV_TARGET_AVX2 +void ARGBToARGB1555Row_AVX2(const uint8_t* src_argb, + uint8_t* dst_argb1555, + int width) { + __m256i mask_b = _mm256_set1_epi32(0x0000001f); + __m256i mask_g = _mm256_set1_epi32(0x000003e0); + __m256i mask_r = _mm256_set1_epi32(0x00007c00); + __m256i mask_a = _mm256_set1_epi32(0x00008000); + + while (width > 0) { + __m256i ymm0 = _mm256_loadu_si256((const __m256i*)src_argb); + __m256i ymm2 = _mm256_srli_epi32(ymm0, 6); + __m256i ymm1 = _mm256_srli_epi32(ymm0, 3); + __m256i ymm7 = _mm256_srli_epi32(ymm0, 16); + ymm0 = _mm256_srli_epi32(ymm0, 9); + ymm2 = _mm256_and_si256(ymm2, mask_g); + ymm1 = _mm256_and_si256(ymm1, mask_b); + ymm7 = _mm256_and_si256(ymm7, mask_a); + ymm0 = _mm256_and_si256(ymm0, mask_r); + ymm1 = _mm256_or_si256(ymm2, ymm1); + ymm0 = _mm256_or_si256(ymm7, ymm0); + ymm0 = _mm256_or_si256(ymm1, ymm0); + ymm0 = _mm256_packus_epi32(ymm0, ymm0); + ymm0 = _mm256_permute4x64_epi64(ymm0, 0xd8); + _mm_storeu_si128((__m128i*)dst_argb1555, _mm256_castsi256_si128(ymm0)); + src_argb += 32; + dst_argb1555 += 16; + width -= 8; + } + _mm256_zeroupper(); +} +#endif + +#ifdef HAS_ARGBTOARGB4444ROW_AVX2 +LIBYUV_TARGET_AVX2 +void ARGBToARGB4444Row_AVX2(const uint8_t* src_argb, + uint8_t* dst_argb4444, + int width) { + __m256i mask_b = _mm256_set1_epi32(0x0000000f); + __m256i mask_g = _mm256_set1_epi32(0x000000f0); + __m256i mask_r = _mm256_set1_epi32(0x00000f00); + __m256i mask_a = _mm256_set1_epi32(0x0000f000); + + while (width > 0) { + __m256i ymm0 = _mm256_loadu_si256((const __m256i*)src_argb); + __m256i ymm2 = _mm256_srli_epi32(ymm0, 8); + __m256i ymm1 = _mm256_srli_epi32(ymm0, 4); + __m256i ymm7 = _mm256_srli_epi32(ymm0, 16); + ymm0 = _mm256_srli_epi32(ymm0, 12); + ymm2 = _mm256_and_si256(ymm2, mask_g); + ymm1 = _mm256_and_si256(ymm1, mask_b); + ymm7 = _mm256_and_si256(ymm7, mask_a); + ymm0 = _mm256_and_si256(ymm0, mask_r); + ymm1 = _mm256_or_si256(ymm2, ymm1); + ymm0 = _mm256_or_si256(ymm7, ymm0); + ymm0 = _mm256_or_si256(ymm1, ymm0); + ymm0 = _mm256_packus_epi32(ymm0, ymm0); + ymm0 = _mm256_permute4x64_epi64(ymm0, 0xd8); + _mm_storeu_si128((__m128i*)dst_argb4444, _mm256_castsi256_si128(ymm0)); + src_argb += 32; + dst_argb4444 += 16; + width -= 8; + } + _mm256_zeroupper(); +} +#endif + #ifdef HAS_RGB24TOARGBROW_AVX2 LIBYUV_TARGET_AVX2 void RGB24ToARGBRow_AVX2(const uint8_t* src_rgb24,