Commit 008c21ffac for aom
commit 008c21ffac928131c34117d5474d5ac94e95f381
Author: Lin Zheng <linzhen@google.com>
Date: Wed Oct 28 14:48:45 2026 +0000
Add AVX-512 intrinsics for AV1 and DSP encoder kernels
Pure encoder speedup by ~4% for all speed levels.
Change-Id: I16961c36e00eb09cbaa3ff0a2d1c5401e3a2f40c
diff --git a/aom_dsp/aom_dsp.cmake b/aom_dsp/aom_dsp.cmake
index e249af360b..fdb38ee562 100644
--- a/aom_dsp/aom_dsp.cmake
+++ b/aom_dsp/aom_dsp.cmake
@@ -268,6 +268,12 @@ if(CONFIG_AV1_ENCODER)
"${AOM_ROOT}/aom_dsp/x86/blk_sse_sum_avx2.c"
"${AOM_ROOT}/aom_dsp/x86/sum_squares_avx2.c")
+ list(APPEND AOM_DSP_ENCODER_INTRIN_AVX512
+ "${AOM_ROOT}/aom_dsp/x86/avg_intrin_avx512.c"
+ "${AOM_ROOT}/aom_dsp/x86/sad_avx512.c"
+ "${AOM_ROOT}/aom_dsp/x86/subtract_avx512.c"
+ "${AOM_ROOT}/aom_dsp/x86/variance_avx512.c")
+
if(CONFIG_HIGHWAY)
list(APPEND AOM_DSP_ENCODER_INTRIN_AVX2
"${AOM_ROOT}/aom_dsp/x86/sad_hwy_avx2.cc")
@@ -508,10 +514,10 @@ function(setup_aom_dsp_targets)
endif()
endif()
- if(HAVE_AVX512 AND CONFIG_AV1_ENCODER AND CONFIG_HIGHWAY)
- add_intrinsics_object_library("-march=skylake-avx512" "avx512"
- "aom_dsp_encoder"
- "AOM_DSP_ENCODER_INTRIN_AVX512")
+ if(HAVE_AVX512 AND CONFIG_AV1_ENCODER)
+ add_intrinsics_object_library(
+ "-mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl" "avx512"
+ "aom_dsp_encoder" "AOM_DSP_ENCODER_INTRIN_AVX512")
endif()
if(HAVE_AVX512 AND CONFIG_HIGHWAY)
diff --git a/aom_dsp/aom_dsp_rtcd_defs.pl b/aom_dsp/aom_dsp_rtcd_defs.pl
index 440aac1f79..a7d07b6d11 100755
--- a/aom_dsp/aom_dsp_rtcd_defs.pl
+++ b/aom_dsp/aom_dsp_rtcd_defs.pl
@@ -747,13 +747,13 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes"){
#
if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
add_proto qw/void aom_quantize_b/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
- specialize qw/aom_quantize_b sse2 neon avx avx2/, "$ssse3_x86_64";
+ specialize qw/aom_quantize_b sse2 neon avx avx2 avx512/, "$ssse3_x86_64";
add_proto qw/void aom_quantize_b_32x32/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
- specialize qw/aom_quantize_b_32x32 neon avx avx2/, "$ssse3_x86_64";
+ specialize qw/aom_quantize_b_32x32 neon avx avx2 avx512/, "$ssse3_x86_64";
add_proto qw/void aom_quantize_b_64x64/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
- specialize qw/aom_quantize_b_64x64 neon ssse3 avx2/;
+ specialize qw/aom_quantize_b_64x64 neon ssse3 avx2 avx512/;
if (aom_config("CONFIG_REALTIME_ONLY") ne "yes") {
add_proto qw/void aom_quantize_b_adaptive/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
@@ -817,13 +817,13 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
# Block subtraction
#
add_proto qw/void aom_subtract_block/, "int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride";
- specialize qw/aom_subtract_block neon avx2/, "$sse2_asm";
+ specialize qw/aom_subtract_block neon avx2 avx512/, "$sse2_asm";
add_proto qw/int64_t/, "aom_sse", "const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height";
specialize qw/aom_sse sse4_1 avx2 neon neon_dotprod/;
add_proto qw/void/, "aom_get_blk_sse_sum", "const int16_t *data, int stride, int bw, int bh, int *x_sum, int64_t *x2_sum";
- specialize qw/aom_get_blk_sse_sum sse2 avx2 neon sve/;
+ specialize qw/aom_get_blk_sse_sum sse2 avx2 avx512 neon sve/;
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
add_proto qw/void aom_highbd_subtract_block/, "int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride";
@@ -866,26 +866,18 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
add_proto qw/uint64_t aom_sum_sse_2d_i16/, "const int16_t *src, int src_stride, int width, int height, int *sum";
specialize qw/aom_sum_sse_2d_i16 avx2 neon sse2 sve/;
- specialize qw/aom_sad128x128 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad128x64 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x128 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x64 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x32 avx2 neon neon_dotprod/, "$sse2_asm";
-
- if(aom_config("CONFIG_HIGHWAY") eq "yes") {
- specialize qw/aom_sad128x128 avx512/;
- specialize qw/aom_sad128x64 avx512/;
- specialize qw/aom_sad64x128 avx512/;
- specialize qw/aom_sad64x64 avx512/;
- specialize qw/aom_sad64x32 avx512/;
- }
-
- specialize qw/aom_sad32x64 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad32x32 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad32x16 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x32 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x16 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x8 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad128x128 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad128x64 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x128 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x64 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x32 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+
+ specialize qw/aom_sad32x64 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x32 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x16 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x32 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x16 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x8 avx512 neon neon_dotprod/, "$sse2_asm";
specialize qw/aom_sad8x16 neon/, "$sse2_asm";
specialize qw/aom_sad8x8 neon/, "$sse2_asm";
specialize qw/aom_sad8x4 neon/, "$sse2_asm";
@@ -893,66 +885,50 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
specialize qw/aom_sad4x4 neon/, "$sse2_asm";
specialize qw/aom_sad4x16 neon/, "$sse2_asm";
- specialize qw/aom_sad16x4 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x4 avx512 neon neon_dotprod/, "$sse2_asm";
specialize qw/aom_sad8x32 neon/, "$sse2_asm";
- specialize qw/aom_sad32x8 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x64 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x16 neon neon_dotprod/, "$sse2_asm";
-
- specialize qw/aom_sad_skip_128x128 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_128x64 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_64x128 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_64x64 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_64x32 avx2 neon neon_dotprod/, "$sse2_asm";
-
- if(aom_config("CONFIG_HIGHWAY") eq "yes") {
- specialize qw/aom_sad_skip_128x128 avx512/;
- specialize qw/aom_sad_skip_128x64 avx512/;
- specialize qw/aom_sad_skip_64x128 avx512/;
- specialize qw/aom_sad_skip_64x64 avx512/;
- specialize qw/aom_sad_skip_64x32 avx512/;
- }
-
- specialize qw/aom_sad_skip_32x64 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_32x32 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_32x16 avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_16x32 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_16x16 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x8 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x64 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x16 avx512 neon neon_dotprod/, "$sse2_asm";
+
+ specialize qw/aom_sad_skip_128x128 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_128x64 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_64x128 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_64x64 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_64x32 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+
+ specialize qw/aom_sad_skip_32x64 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_32x32 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_32x16 avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_16x32 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_16x16 avx512 neon neon_dotprod/, "$sse2_asm";
specialize qw/aom_sad_skip_16x8 sse2 neon neon_dotprod/;
specialize qw/aom_sad_skip_8x16 neon/, "$sse2_asm";
specialize qw/aom_sad_skip_4x16 neon/, "$sse2_asm";
specialize qw/aom_sad_skip_8x32 neon/, "$sse2_asm";
- specialize qw/aom_sad_skip_16x64 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_64x16 neon neon_dotprod/, "$sse2_asm";
-
- specialize qw/aom_sad128x128_avg avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad128x64_avg avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x128_avg avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x64_avg avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x32_avg avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad32x64_avg avx2 neon neon_dotprod/, "$sse2_asm";
-
- if(aom_config("CONFIG_HIGHWAY") eq "yes") {
- specialize qw/aom_sad128x128_avg avx512/;
- specialize qw/aom_sad128x64_avg avx512/;
- specialize qw/aom_sad64x128_avg avx512/;
- specialize qw/aom_sad64x64_avg avx512/;
- specialize qw/aom_sad64x32_avg avx512/;
- }
-
- specialize qw/aom_sad32x32_avg avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad32x16_avg avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x32_avg neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x16_avg neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x8_avg neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_16x64 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_64x16 avx512 neon neon_dotprod/, "$sse2_asm";
+
+ specialize qw/aom_sad128x128_avg avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad128x64_avg avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x128_avg avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x64_avg avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x32_avg avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x64_avg avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+
+ specialize qw/aom_sad32x32_avg avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x16_avg avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x32_avg avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x16_avg avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x8_avg avx512 neon neon_dotprod/, "$sse2_asm";
specialize qw/aom_sad8x16_avg neon/, "$sse2_asm";
specialize qw/aom_sad8x8_avg neon/, "$sse2_asm";
specialize qw/aom_sad8x32_avg neon/, "$sse2_asm";
- specialize qw/aom_sad32x8_avg neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x64_avg neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x16_avg neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x8_avg avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x64_avg avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x16_avg avx512 neon neon_dotprod/, "$sse2_asm";
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
foreach (@encoder_block_sizes) {
@@ -1035,7 +1011,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
foreach (@encoder_block_sizes) {
($w, $h) = @$_;
add_proto qw/unsigned int/, "aom_masked_sad${w}x${h}", "const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, const uint8_t *second_pred, const uint8_t *msk, int msk_stride, int invert_mask";
- specialize "aom_masked_sad${w}x${h}", qw/ssse3 avx2 neon/;
+ specialize "aom_masked_sad${w}x${h}", qw/ssse3 avx2 avx512 neon/;
}
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
@@ -1054,7 +1030,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
($w, $h) = @$_;
add_proto qw/unsigned int/, "aom_obmc_sad${w}x${h}", "const uint8_t *pre, int pre_stride, const int32_t *wsrc, const int32_t *mask";
if (! (($w == 128 && $h == 32) || ($w == 32 && $h == 128))) {
- specialize "aom_obmc_sad${w}x${h}", qw/sse4_1 avx2 neon/;
+ specialize "aom_obmc_sad${w}x${h}", qw/sse4_1 avx2 avx512 neon/;
}
}
@@ -1081,26 +1057,18 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
}
}
- specialize qw/aom_sad128x128x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad128x64x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x128x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x64x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad64x32x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad32x64x4d avx2 neon neon_dotprod/, "$sse2_asm";
-
- if(aom_config("CONFIG_HIGHWAY") eq "yes") {
- specialize qw/aom_sad128x128x4d avx512/;
- specialize qw/aom_sad128x64x4d avx512/;
- specialize qw/aom_sad64x128x4d avx512/;
- specialize qw/aom_sad64x64x4d avx512/;
- specialize qw/aom_sad64x32x4d avx512/;
- }
+ specialize qw/aom_sad128x128x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad128x64x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x128x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x64x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x32x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x64x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad32x32x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad32x16x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x32x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x16x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x8x4d avx2 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x32x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x16x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x32x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x16x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x8x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
specialize qw/aom_sad8x16x4d neon/, "$sse2_asm";
specialize qw/aom_sad8x8x4d neon/, "$sse2_asm";
@@ -1108,69 +1076,53 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
specialize qw/aom_sad4x8x4d neon/, "$sse2_asm";
specialize qw/aom_sad4x4x4d neon/, "$sse2_asm";
- specialize qw/aom_sad64x16x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad32x8x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x64x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad16x4x4d avx2 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad64x16x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad32x8x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x64x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad16x4x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
specialize qw/aom_sad8x32x4d neon/, "$sse2_asm";
specialize qw/aom_sad4x16x4d neon/, "$sse2_asm";
- specialize qw/aom_sad_skip_128x128x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_128x64x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_64x128x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_64x64x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_64x32x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_64x16x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_32x64x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_32x32x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_32x16x4d avx2 neon neon_dotprod/, "$sse2_asm";
-
- if(aom_config("CONFIG_HIGHWAY") eq "yes") {
- specialize qw/aom_sad_skip_128x128x4d avx512/;
- specialize qw/aom_sad_skip_128x64x4d avx512/;
- specialize qw/aom_sad_skip_64x128x4d avx512/;
- specialize qw/aom_sad_skip_64x64x4d avx512/;
- specialize qw/aom_sad_skip_64x32x4d avx512/;
- }
-
- specialize qw/aom_sad_skip_16x64x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_16x32x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_16x16x4d avx2 neon neon_dotprod/, "$sse2_asm";
- specialize qw/aom_sad_skip_16x8x4d avx2 sse2 neon neon_dotprod/;
+ specialize qw/aom_sad_skip_128x128x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_128x64x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_64x128x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_64x64x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_64x32x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_64x16x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_32x64x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_32x32x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_32x16x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+
+ specialize qw/aom_sad_skip_16x64x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_16x32x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_16x16x4d avx2 avx512 neon neon_dotprod/, "$sse2_asm";
+ specialize qw/aom_sad_skip_16x8x4d avx2 avx512 sse2 neon neon_dotprod/;
specialize qw/aom_sad_skip_8x32x4d neon/, "$sse2_asm";
specialize qw/aom_sad_skip_8x16x4d neon/, "$sse2_asm";
specialize qw/aom_sad_skip_4x16x4d neon/, "$sse2_asm";
- specialize qw/aom_sad128x128x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad128x64x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad64x128x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad64x64x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad64x32x3d avx2 neon neon_dotprod/;
-
- if(aom_config("CONFIG_HIGHWAY") eq "yes") {
- specialize qw/aom_sad128x128x3d avx512/;
- specialize qw/aom_sad128x64x3d avx512/;
- specialize qw/aom_sad64x128x3d avx512/;
- specialize qw/aom_sad64x64x3d avx512/;
- specialize qw/aom_sad64x32x3d avx512/;
- }
-
- specialize qw/aom_sad32x64x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad32x32x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad32x16x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad16x32x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad16x16x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad16x8x3d avx2 neon neon_dotprod/;
+ specialize qw/aom_sad128x128x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad128x64x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad64x128x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad64x64x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad64x32x3d avx2 avx512 neon neon_dotprod/;
+
+ specialize qw/aom_sad32x64x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad32x32x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad32x16x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad16x32x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad16x16x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad16x8x3d avx2 avx512 neon neon_dotprod/;
specialize qw/aom_sad8x16x3d neon/;
specialize qw/aom_sad8x8x3d neon/;
specialize qw/aom_sad8x4x3d neon/;
specialize qw/aom_sad4x8x3d neon/;
specialize qw/aom_sad4x4x3d neon/;
- specialize qw/aom_sad64x16x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad32x8x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad16x64x3d avx2 neon neon_dotprod/;
- specialize qw/aom_sad16x4x3d avx2 neon neon_dotprod/;
+ specialize qw/aom_sad64x16x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad32x8x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad16x64x3d avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_sad16x4x3d avx2 avx512 neon neon_dotprod/;
specialize qw/aom_sad8x32x3d neon/;
specialize qw/aom_sad4x16x3d neon/;
@@ -1279,13 +1231,13 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
}
add_proto qw/void aom_int_pro_row/, "int16_t *hbuf, const uint8_t *ref, const int ref_stride, const int width, const int height, int norm_factor";
- specialize qw/aom_int_pro_row avx2 sse2 neon/;
+ specialize qw/aom_int_pro_row avx2 avx512 sse2 neon/;
add_proto qw/void aom_int_pro_col/, "int16_t *vbuf, const uint8_t *ref, const int ref_stride, const int width, const int height, int norm_factor";
- specialize qw/aom_int_pro_col avx2 sse2 neon/;
+ specialize qw/aom_int_pro_col avx2 avx512 sse2 neon/;
add_proto qw/int aom_vector_var/, "const int16_t *ref, const int16_t *src, int bwl";
- specialize qw/aom_vector_var avx2 sse4_1 neon sve/;
+ specialize qw/aom_vector_var avx2 avx512 sse4_1 neon sve/;
#
# hamadard transform and satd for implmenting temporal dependency model
@@ -1297,35 +1249,35 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
specialize qw/aom_hadamard_8x8 sse2 neon/;
add_proto qw/void aom_hadamard_16x16/, "const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff";
- specialize qw/aom_hadamard_16x16 avx2 sse2 neon/;
+ specialize qw/aom_hadamard_16x16 avx2 avx512 sse2 neon/;
add_proto qw/void aom_hadamard_32x32/, "const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff";
- specialize qw/aom_hadamard_32x32 avx2 sse2 neon/;
+ specialize qw/aom_hadamard_32x32 avx2 avx512 sse2 neon/;
add_proto qw/void aom_hadamard_lp_8x8/, "const int16_t *src_diff, ptrdiff_t src_stride, int16_t *coeff";
specialize qw/aom_hadamard_lp_8x8 sse2 neon/;
add_proto qw/void aom_hadamard_lp_16x16/, "const int16_t *src_diff, ptrdiff_t src_stride, int16_t *coeff";
- specialize qw/aom_hadamard_lp_16x16 sse2 avx2 neon/;
+ specialize qw/aom_hadamard_lp_16x16 sse2 avx2 avx512 neon/;
add_proto qw/void aom_hadamard_lp_8x8_dual/, "const int16_t *src_diff, ptrdiff_t src_stride, int16_t *coeff";
- specialize qw/aom_hadamard_lp_8x8_dual sse2 avx2 neon/;
+ specialize qw/aom_hadamard_lp_8x8_dual sse2 avx2 avx512 neon/;
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
add_proto qw/void aom_highbd_hadamard_8x8/, "const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff";
specialize qw/aom_highbd_hadamard_8x8 avx2 neon/;
add_proto qw/void aom_highbd_hadamard_16x16/, "const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff";
- specialize qw/aom_highbd_hadamard_16x16 avx2 neon/;
+ specialize qw/aom_highbd_hadamard_16x16 avx2 avx512 neon/;
add_proto qw/void aom_highbd_hadamard_32x32/, "const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff";
- specialize qw/aom_highbd_hadamard_32x32 avx2 neon/;
+ specialize qw/aom_highbd_hadamard_32x32 avx2 avx512 neon/;
}
add_proto qw/int aom_satd/, "const tran_low_t *coeff, int length";
- specialize qw/aom_satd neon sse2 avx2/;
+ specialize qw/aom_satd neon sse2 avx2 avx512/;
add_proto qw/int aom_satd_lp/, "const int16_t *coeff, int length";
- specialize qw/aom_satd_lp sse2 avx2 neon/;
+ specialize qw/aom_satd_lp sse2 avx2 avx512 neon/;
#
@@ -1355,7 +1307,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
add_proto qw/unsigned int aom_mse8x16/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse";
add_proto qw/unsigned int aom_mse8x8/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse";
- specialize qw/aom_mse16x16 sse2 avx2 neon neon_dotprod/;
+ specialize qw/aom_mse16x16 sse2 avx2 avx512 neon neon_dotprod/;
specialize qw/aom_mse16x8 sse2 neon neon_dotprod/;
specialize qw/aom_mse8x16 sse2 neon neon_dotprod/;
specialize qw/aom_mse8x8 sse2 neon neon_dotprod/;
@@ -1399,11 +1351,11 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
specialize qw/aom_mse_wxh_16bit sse2 avx2 neon/;
add_proto qw/int64_t/, "aom_calc_variance_stat", "const uint8_t *src, int stride, int bw, int bh";
- specialize qw/aom_calc_variance_stat avx2/;
+ specialize qw/aom_calc_variance_stat avx2 avx512/;
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
add_proto qw/int64_t/, "aom_highbd_calc_variance_stat", "const uint16_t *src, int stride, int bw, int bh";
- specialize qw/aom_highbd_calc_variance_stat avx2/;
+ specialize qw/aom_highbd_calc_variance_stat avx2 avx512/;
}
add_proto qw/uint64_t/, "aom_mse_16xh_16bit", "uint8_t *dst, int dstride,uint16_t *src, int w, int h";
@@ -1415,31 +1367,31 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
add_proto qw/uint32_t/, "aom_sub_pixel_variance${w}x${h}", "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
add_proto qw/uint32_t/, "aom_sub_pixel_avg_variance${w}x${h}", "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse, const uint8_t *second_pred";
}
- specialize qw/aom_variance128x128 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance128x64 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance64x128 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance64x64 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance64x32 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance32x64 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance32x32 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance32x16 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance16x32 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance16x16 sse2 avx2 neon neon_dotprod/;
- specialize qw/aom_variance16x8 sse2 avx2 neon neon_dotprod/;
+ specialize qw/aom_variance128x128 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance128x64 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance64x128 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance64x64 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance64x32 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance32x64 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance32x32 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance32x16 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance16x32 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance16x16 sse2 avx2 avx512 neon neon_dotprod/;
+ specialize qw/aom_variance16x8 sse2 avx2 avx512 neon neon_dotprod/;
specialize qw/aom_variance8x16 sse2 neon neon_dotprod/;
specialize qw/aom_variance8x8 sse2 neon neon_dotprod/;
specialize qw/aom_variance8x4 sse2 neon neon_dotprod/;
specialize qw/aom_variance4x8 sse2 neon neon_dotprod/;
specialize qw/aom_variance4x4 sse2 neon/;
- specialize qw/aom_sub_pixel_variance128x128 avx2 neon neon_dotprod/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance128x64 avx2 neon neon_dotprod/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance64x128 avx2 neon neon_dotprod/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance64x64 avx2 neon neon_dotprod/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance64x32 avx2 neon neon_dotprod/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance32x64 avx2 neon neon_dotprod/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance32x32 avx2 neon neon_dotprod/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance32x16 avx2 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance128x128 avx2 avx512 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance128x64 avx2 avx512 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance64x128 avx2 avx512 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance64x64 avx2 avx512 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance64x32 avx2 avx512 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance32x64 avx2 avx512 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance32x32 avx2 avx512 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance32x16 avx2 avx512 neon neon_dotprod/, "$ssse3_asm";
specialize qw/aom_sub_pixel_variance16x32 avx2 neon neon_dotprod/, "$ssse3_asm";
specialize qw/aom_sub_pixel_variance16x16 avx2 neon neon_dotprod/, "$ssse3_asm";
specialize qw/aom_sub_pixel_variance16x8 avx2 neon neon_dotprod/, "$ssse3_asm";
@@ -1449,14 +1401,14 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
specialize qw/aom_sub_pixel_variance4x8 neon neon_dotprod/, "$ssse3_asm";
specialize qw/aom_sub_pixel_variance4x4 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance128x128 avx2 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance128x64 avx2 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance64x128 avx2 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance64x64 avx2 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance64x32 avx2 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance32x64 avx2 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance32x32 avx2 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance32x16 avx2 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance128x128 avx2 avx512 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance128x64 avx2 avx512 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance64x128 avx2 avx512 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance64x64 avx2 avx512 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance64x32 avx2 avx512 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance32x64 avx2 avx512 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance32x32 avx2 avx512 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance32x16 avx2 avx512 neon/, "$ssse3_asm";
specialize qw/aom_sub_pixel_avg_variance16x32 neon/, "$ssse3_asm";
specialize qw/aom_sub_pixel_avg_variance16x16 neon/, "$ssse3_asm";
specialize qw/aom_sub_pixel_avg_variance16x8 neon/, "$ssse3_asm";
@@ -1468,24 +1420,24 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
if (aom_config("CONFIG_REALTIME_ONLY") ne "yes") {
specialize qw/aom_variance4x16 neon neon_dotprod sse2/;
- specialize qw/aom_variance16x4 neon neon_dotprod sse2 avx2/;
+ specialize qw/aom_variance16x4 neon neon_dotprod sse2 avx2 avx512/;
specialize qw/aom_variance8x32 neon neon_dotprod sse2/;
- specialize qw/aom_variance32x8 neon neon_dotprod sse2 avx2/;
- specialize qw/aom_variance16x64 neon neon_dotprod sse2 avx2/;
- specialize qw/aom_variance64x16 neon neon_dotprod sse2 avx2/;
+ specialize qw/aom_variance32x8 neon neon_dotprod sse2 avx2 avx512/;
+ specialize qw/aom_variance16x64 neon neon_dotprod sse2 avx2 avx512/;
+ specialize qw/aom_variance64x16 neon neon_dotprod sse2 avx2 avx512/;
specialize qw/aom_sub_pixel_variance4x16 neon neon_dotprod/, "$ssse3_asm";
specialize qw/aom_sub_pixel_variance16x4 neon neon_dotprod avx2/, "$ssse3_asm";
specialize qw/aom_sub_pixel_variance8x32 neon neon_dotprod/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance32x8 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance32x8 neon neon_dotprod avx512/, "$ssse3_asm";
specialize qw/aom_sub_pixel_variance16x64 neon neon_dotprod avx2/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_variance64x16 neon neon_dotprod/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_variance64x16 neon neon_dotprod avx512/, "$ssse3_asm";
specialize qw/aom_sub_pixel_avg_variance4x16 neon/, "$ssse3_asm";
specialize qw/aom_sub_pixel_avg_variance16x4 neon/, "$ssse3_asm";
specialize qw/aom_sub_pixel_avg_variance8x32 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance32x8 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance32x8 neon avx512/, "$ssse3_asm";
specialize qw/aom_sub_pixel_avg_variance16x64 neon/, "$ssse3_asm";
- specialize qw/aom_sub_pixel_avg_variance64x16 neon/, "$ssse3_asm";
+ specialize qw/aom_sub_pixel_avg_variance64x16 neon avx512/, "$ssse3_asm";
}
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
@@ -1712,7 +1664,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
($w, $h) = @$_;
add_proto qw/unsigned int/, "aom_obmc_variance${w}x${h}", "const uint8_t *pre, int pre_stride, const int32_t *wsrc, const int32_t *mask, unsigned int *sse";
add_proto qw/unsigned int/, "aom_obmc_sub_pixel_variance${w}x${h}", "const uint8_t *pre, int pre_stride, int xoffset, int yoffset, const int32_t *wsrc, const int32_t *mask, unsigned int *sse";
- specialize "aom_obmc_variance${w}x${h}", qw/sse4_1 avx2 neon/;
+ specialize "aom_obmc_variance${w}x${h}", qw/sse4_1 avx2 avx512 neon/;
specialize "aom_obmc_sub_pixel_variance${w}x${h}", qw/sse4_1 neon/;
}
@@ -1733,7 +1685,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
# Comp Avg
#
add_proto qw/void aom_comp_avg_pred/, "uint8_t *comp_pred, const uint8_t *pred, int width, int height, const uint8_t *ref, int ref_stride";
- specialize qw/aom_comp_avg_pred avx2 neon/;
+ specialize qw/aom_comp_avg_pred avx2 avx512 neon/;
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
add_proto qw/void aom_highbd_comp_avg_pred/, "uint8_t *comp_pred8, const uint8_t *pred8, int width, int height, const uint8_t *ref8, int ref_stride";
@@ -1744,11 +1696,11 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
}
add_proto qw/void aom_comp_mask_pred/, "uint8_t *comp_pred, const uint8_t *pred, int width, int height, const uint8_t *ref, int ref_stride, const uint8_t *mask, int mask_stride, int invert_mask";
- specialize qw/aom_comp_mask_pred ssse3 avx2 neon/;
+ specialize qw/aom_comp_mask_pred ssse3 avx2 avx512 neon/;
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
add_proto qw/void aom_highbd_comp_mask_pred/, "uint8_t *comp_pred, const uint8_t *pred8, int width, int height, const uint8_t *ref8, int ref_stride, const uint8_t *mask, int mask_stride, int invert_mask";
- specialize qw/aom_highbd_comp_mask_pred sse2 avx2 neon/;
+ specialize qw/aom_highbd_comp_mask_pred sse2 avx2 avx512 neon/;
}
# Flow estimation library
diff --git a/aom_dsp/x86/avg_intrin_avx512.c b/aom_dsp/x86/avg_intrin_avx512.c
new file mode 100644
index 0000000000..4303f66e8c
--- /dev/null
+++ b/aom_dsp/x86/avg_intrin_avx512.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <assert.h>
+#include <immintrin.h>
+#include <stdlib.h>
+
+#include "config/aom_config.h"
+#include "config/aom_dsp_rtcd.h"
+#include "aom/aom_integer.h"
+#include "aom_dsp/x86/bitdepth_conversion_avx2.h"
+#include "aom_ports/mem.h"
+
+// Stores 32 int16_t values from a 512-bit register into 32 tran_low_t (int32_t)
+// slots with the exact same lane layout as two back-to-back AVX2
+// store_tran_low() calls.
+static inline void store_tran_low_avx512(__m512i a, tran_low_t *b) {
+ const __m512i a_hi = _mm512_srai_epi16(a, 15);
+ const __m512i a_1 = _mm512_unpacklo_epi16(a, a_hi);
+ const __m512i a_2 = _mm512_unpackhi_epi16(a, a_hi);
+ const __m512i out0 = _mm512_shuffle_i64x2(a_1, a_2, 0x44);
+ const __m512i out1 = _mm512_shuffle_i64x2(a_1, a_2, 0xEE);
+ _mm512_storeu_si512((__m512i *)b, out0);
+ _mm512_storeu_si512((__m512i *)(b + 16), out1);
+}
+
+static inline void sign_extend_16bit_to_32bit_avx512(__m512i in,
+ __m512i *out_lo,
+ __m512i *out_hi) {
+ const __m512i sign_bits = _mm512_srai_epi16(in, 15);
+ *out_lo = _mm512_unpacklo_epi16(in, sign_bits);
+ *out_hi = _mm512_unpackhi_epi16(in, sign_bits);
+}
+
+// Processes four 8x8 16-bit Hadamard blocks simultaneously across the four
+// 128-bit lanes of in[0..7].
+static inline void hadamard_col8x4_avx512(__m512i *in, int iter) {
+ __m512i a0 = in[0];
+ __m512i a1 = in[1];
+ __m512i a2 = in[2];
+ __m512i a3 = in[3];
+ __m512i a4 = in[4];
+ __m512i a5 = in[5];
+ __m512i a6 = in[6];
+ __m512i a7 = in[7];
+
+ __m512i b0 = _mm512_add_epi16(a0, a1);
+ __m512i b1 = _mm512_sub_epi16(a0, a1);
+ __m512i b2 = _mm512_add_epi16(a2, a3);
+ __m512i b3 = _mm512_sub_epi16(a2, a3);
+ __m512i b4 = _mm512_add_epi16(a4, a5);
+ __m512i b5 = _mm512_sub_epi16(a4, a5);
+ __m512i b6 = _mm512_add_epi16(a6, a7);
+ __m512i b7 = _mm512_sub_epi16(a6, a7);
+
+ a0 = _mm512_add_epi16(b0, b2);
+ a1 = _mm512_add_epi16(b1, b3);
+ a2 = _mm512_sub_epi16(b0, b2);
+ a3 = _mm512_sub_epi16(b1, b3);
+ a4 = _mm512_add_epi16(b4, b6);
+ a5 = _mm512_add_epi16(b5, b7);
+ a6 = _mm512_sub_epi16(b4, b6);
+ a7 = _mm512_sub_epi16(b5, b7);
+
+ if (iter == 0) {
+ b0 = _mm512_add_epi16(a0, a4);
+ b7 = _mm512_add_epi16(a1, a5);
+ b3 = _mm512_add_epi16(a2, a6);
+ b4 = _mm512_add_epi16(a3, a7);
+ b2 = _mm512_sub_epi16(a0, a4);
+ b6 = _mm512_sub_epi16(a1, a5);
+ b1 = _mm512_sub_epi16(a2, a6);
+ b5 = _mm512_sub_epi16(a3, a7);
+
+ a0 = _mm512_unpacklo_epi16(b0, b1);
+ a1 = _mm512_unpacklo_epi16(b2, b3);
+ a2 = _mm512_unpackhi_epi16(b0, b1);
+ a3 = _mm512_unpackhi_epi16(b2, b3);
+ a4 = _mm512_unpacklo_epi16(b4, b5);
+ a5 = _mm512_unpacklo_epi16(b6, b7);
+ a6 = _mm512_unpackhi_epi16(b4, b5);
+ a7 = _mm512_unpackhi_epi16(b6, b7);
+
+ b0 = _mm512_unpacklo_epi32(a0, a1);
+ b1 = _mm512_unpacklo_epi32(a4, a5);
+ b2 = _mm512_unpackhi_epi32(a0, a1);
+ b3 = _mm512_unpackhi_epi32(a4, a5);
+ b4 = _mm512_unpacklo_epi32(a2, a3);
+ b5 = _mm512_unpacklo_epi32(a6, a7);
+ b6 = _mm512_unpackhi_epi32(a2, a3);
+ b7 = _mm512_unpackhi_epi32(a6, a7);
+
+ in[0] = _mm512_unpacklo_epi64(b0, b1);
+ in[1] = _mm512_unpackhi_epi64(b0, b1);
+ in[2] = _mm512_unpacklo_epi64(b2, b3);
+ in[3] = _mm512_unpackhi_epi64(b2, b3);
+ in[4] = _mm512_unpacklo_epi64(b4, b5);
+ in[5] = _mm512_unpackhi_epi64(b4, b5);
+ in[6] = _mm512_unpacklo_epi64(b6, b7);
+ in[7] = _mm512_unpackhi_epi64(b6, b7);
+ } else {
+ in[0] = _mm512_add_epi16(a0, a4);
+ in[7] = _mm512_add_epi16(a1, a5);
+ in[3] = _mm512_add_epi16(a2, a6);
+ in[4] = _mm512_add_epi16(a3, a7);
+ in[2] = _mm512_sub_epi16(a0, a4);
+ in[6] = _mm512_sub_epi16(a1, a5);
+ in[1] = _mm512_sub_epi16(a2, a6);
+ in[5] = _mm512_sub_epi16(a3, a7);
+ }
+}
+
+void aom_hadamard_lp_8x8_dual_avx512(const int16_t *src_diff,
+ ptrdiff_t src_stride, int16_t *coeff) {
+ aom_hadamard_lp_8x8_dual_avx2(src_diff, src_stride, coeff);
+}
+
+static inline void load_row_pair_16x16(const int16_t *r_top,
+ const int16_t *r_bot, __m512i *out) {
+ const __m256i top = _mm256_loadu_si256((const __m256i *)r_top);
+ const __m256i bot = _mm256_loadu_si256((const __m256i *)r_bot);
+ *out = _mm512_inserti64x4(_mm512_castsi256_si512(top), bot, 1);
+}
+
+// Transposes 4x4 128-bit lanes across 4 ZMM registers so c0..c3 hold 32
+// contiguous int16_t coefficients from quadrants 0..3 respectively, then runs
+// the 2x2 inter-quadrant Hadamard butterfly in-register.
+static inline void hadamard_16x16_quadrant_butterfly_avx512(
+ __m512i s0, __m512i s1, __m512i s2, __m512i s3, __m512i *out0,
+ __m512i *out1, __m512i *out2, __m512i *out3) {
+ const __m512i t0 = _mm512_shuffle_i64x2(s0, s1, 0x44);
+ const __m512i t1 = _mm512_shuffle_i64x2(s2, s3, 0x44);
+ const __m512i t2 = _mm512_shuffle_i64x2(s0, s1, 0xEE);
+ const __m512i t3 = _mm512_shuffle_i64x2(s2, s3, 0xEE);
+
+ const __m512i coeff0 = _mm512_shuffle_i64x2(t0, t1, 0x88);
+ const __m512i coeff1 = _mm512_shuffle_i64x2(t0, t1, 0xDD);
+ const __m512i coeff2 = _mm512_shuffle_i64x2(t2, t3, 0x88);
+ const __m512i coeff3 = _mm512_shuffle_i64x2(t2, t3, 0xDD);
+
+ __m512i b0 = _mm512_srai_epi16(_mm512_add_epi16(coeff0, coeff1), 1);
+ __m512i b1 = _mm512_srai_epi16(_mm512_sub_epi16(coeff0, coeff1), 1);
+ __m512i b2 = _mm512_srai_epi16(_mm512_add_epi16(coeff2, coeff3), 1);
+ __m512i b3 = _mm512_srai_epi16(_mm512_sub_epi16(coeff2, coeff3), 1);
+
+ *out0 = _mm512_add_epi16(b0, b2);
+ *out1 = _mm512_add_epi16(b1, b3);
+ *out2 = _mm512_sub_epi16(b0, b2);
+ *out3 = _mm512_sub_epi16(b1, b3);
+}
+
+static inline void hadamard_16x16_avx512(const int16_t *src_diff,
+ ptrdiff_t src_stride,
+ tran_low_t *coeff, int is_final) {
+ __m512i src[8];
+ const int16_t *src_top = src_diff;
+ const int16_t *src_bot = src_diff + 8 * src_stride;
+
+ load_row_pair_16x16(src_top, src_bot, &src[0]);
+ load_row_pair_16x16(src_top += src_stride, src_bot += src_stride, &src[1]);
+ load_row_pair_16x16(src_top += src_stride, src_bot += src_stride, &src[2]);
+ load_row_pair_16x16(src_top += src_stride, src_bot += src_stride, &src[3]);
+ load_row_pair_16x16(src_top += src_stride, src_bot += src_stride, &src[4]);
+ load_row_pair_16x16(src_top += src_stride, src_bot += src_stride, &src[5]);
+ load_row_pair_16x16(src_top += src_stride, src_bot += src_stride, &src[6]);
+ load_row_pair_16x16(src_top + src_stride, src_bot + src_stride, &src[7]);
+
+ hadamard_col8x4_avx512(src, 0);
+ hadamard_col8x4_avx512(src, 1);
+
+ __m512i out0, out1, out2, out3;
+ hadamard_16x16_quadrant_butterfly_avx512(src[0], src[1], src[2], src[3],
+ &out0, &out1, &out2, &out3);
+ if (is_final) {
+ store_tran_low_avx512(out0, coeff);
+ store_tran_low_avx512(out1, coeff + 64);
+ store_tran_low_avx512(out2, coeff + 128);
+ store_tran_low_avx512(out3, coeff + 192);
+ } else {
+ int16_t *coeff16 = (int16_t *)coeff;
+ _mm512_storeu_si512((__m512i *)coeff16, out0);
+ _mm512_storeu_si512((__m512i *)(coeff16 + 64), out1);
+ _mm512_storeu_si512((__m512i *)(coeff16 + 128), out2);
+ _mm512_storeu_si512((__m512i *)(coeff16 + 192), out3);
+ }
+
+ hadamard_16x16_quadrant_butterfly_avx512(src[4], src[5], src[6], src[7],
+ &out0, &out1, &out2, &out3);
+ if (is_final) {
+ store_tran_low_avx512(out0, coeff + 32);
+ store_tran_low_avx512(out1, coeff + 96);
+ store_tran_low_avx512(out2, coeff + 160);
+ store_tran_low_avx512(out3, coeff + 224);
+ } else {
+ int16_t *coeff16 = (int16_t *)coeff + 32;
+ _mm512_storeu_si512((__m512i *)coeff16, out0);
+ _mm512_storeu_si512((__m512i *)(coeff16 + 64), out1);
+ _mm512_storeu_si512((__m512i *)(coeff16 + 128), out2);
+ _mm512_storeu_si512((__m512i *)(coeff16 + 192), out3);
+ }
+}
+
+void aom_hadamard_16x16_avx512(const int16_t *src_diff, ptrdiff_t src_stride,
+ tran_low_t *coeff) {
+ hadamard_16x16_avx512(src_diff, src_stride, coeff, 1);
+}
+
+void aom_hadamard_lp_16x16_avx512(const int16_t *src_diff, ptrdiff_t src_stride,
+ int16_t *coeff) {
+ hadamard_16x16_avx512(src_diff, src_stride, (tran_low_t *)coeff, 0);
+}
+
+void aom_hadamard_32x32_avx512(const int16_t *src_diff, ptrdiff_t src_stride,
+ tran_low_t *coeff) {
+ DECLARE_ALIGNED(64, int16_t, temp_coeff[32 * 32]);
+ int16_t *t_coeff = temp_coeff;
+ for (int idx = 0; idx < 4; ++idx) {
+ const int16_t *src_ptr =
+ src_diff + (idx >> 1) * 16 * src_stride + (idx & 0x01) * 16;
+ hadamard_16x16_avx512(src_ptr, src_stride,
+ (tran_low_t *)(t_coeff + idx * 256), 0);
+ }
+
+ for (int idx = 0; idx < 256; idx += 32) {
+ const __m512i coeff0 = _mm512_loadu_si512((const __m512i *)t_coeff);
+ const __m512i coeff1 = _mm512_loadu_si512((const __m512i *)(t_coeff + 256));
+ const __m512i coeff2 = _mm512_loadu_si512((const __m512i *)(t_coeff + 512));
+ const __m512i coeff3 = _mm512_loadu_si512((const __m512i *)(t_coeff + 768));
+
+ __m512i coeff0_lo, coeff0_hi, coeff1_lo, coeff1_hi;
+ __m512i coeff2_lo, coeff2_hi, coeff3_lo, coeff3_hi;
+ sign_extend_16bit_to_32bit_avx512(coeff0, &coeff0_lo, &coeff0_hi);
+ sign_extend_16bit_to_32bit_avx512(coeff1, &coeff1_lo, &coeff1_hi);
+ sign_extend_16bit_to_32bit_avx512(coeff2, &coeff2_lo, &coeff2_hi);
+ sign_extend_16bit_to_32bit_avx512(coeff3, &coeff3_lo, &coeff3_hi);
+
+ __m512i b0_lo =
+ _mm512_srai_epi32(_mm512_add_epi32(coeff0_lo, coeff1_lo), 2);
+ __m512i b0_hi =
+ _mm512_srai_epi32(_mm512_add_epi32(coeff0_hi, coeff1_hi), 2);
+ __m512i b1_lo =
+ _mm512_srai_epi32(_mm512_sub_epi32(coeff0_lo, coeff1_lo), 2);
+ __m512i b1_hi =
+ _mm512_srai_epi32(_mm512_sub_epi32(coeff0_hi, coeff1_hi), 2);
+ __m512i b2_lo =
+ _mm512_srai_epi32(_mm512_add_epi32(coeff2_lo, coeff3_lo), 2);
+ __m512i b2_hi =
+ _mm512_srai_epi32(_mm512_add_epi32(coeff2_hi, coeff3_hi), 2);
+ __m512i b3_lo =
+ _mm512_srai_epi32(_mm512_sub_epi32(coeff2_lo, coeff3_lo), 2);
+ __m512i b3_hi =
+ _mm512_srai_epi32(_mm512_sub_epi32(coeff2_hi, coeff3_hi), 2);
+
+ const __m512i b0 = _mm512_packs_epi32(b0_lo, b0_hi);
+ const __m512i b1 = _mm512_packs_epi32(b1_lo, b1_hi);
+ const __m512i b2 = _mm512_packs_epi32(b2_lo, b2_hi);
+ const __m512i b3 = _mm512_packs_epi32(b3_lo, b3_hi);
+
+ store_tran_low_avx512(_mm512_add_epi16(b0, b2), coeff);
+ store_tran_low_avx512(_mm512_add_epi16(b1, b3), coeff + 256);
+ store_tran_low_avx512(_mm512_sub_epi16(b0, b2), coeff + 512);
+ store_tran_low_avx512(_mm512_sub_epi16(b1, b3), coeff + 768);
+
+ coeff += 32;
+ t_coeff += 32;
+ }
+}
+
+#if CONFIG_AV1_HIGHBITDEPTH
+// Processes two 8x8 32-bit Hadamard blocks simultaneously (block 0 in the low
+// 256-bit half, block 1 in the high 256-bit half of in[0..7]).
+static inline void highbd_hadamard_col8x2_avx512(__m512i *in, int iter) {
+ __m512i a0 = in[0];
+ __m512i a1 = in[1];
+ __m512i a2 = in[2];
+ __m512i a3 = in[3];
+ __m512i a4 = in[4];
+ __m512i a5 = in[5];
+ __m512i a6 = in[6];
+ __m512i a7 = in[7];
+
+ __m512i b0 = _mm512_add_epi32(a0, a1);
+ __m512i b1 = _mm512_sub_epi32(a0, a1);
+ __m512i b2 = _mm512_add_epi32(a2, a3);
+ __m512i b3 = _mm512_sub_epi32(a2, a3);
+ __m512i b4 = _mm512_add_epi32(a4, a5);
+ __m512i b5 = _mm512_sub_epi32(a4, a5);
+ __m512i b6 = _mm512_add_epi32(a6, a7);
+ __m512i b7 = _mm512_sub_epi32(a6, a7);
+
+ a0 = _mm512_add_epi32(b0, b2);
+ a1 = _mm512_add_epi32(b1, b3);
+ a2 = _mm512_sub_epi32(b0, b2);
+ a3 = _mm512_sub_epi32(b1, b3);
+ a4 = _mm512_add_epi32(b4, b6);
+ a5 = _mm512_add_epi32(b5, b7);
+ a6 = _mm512_sub_epi32(b4, b6);
+ a7 = _mm512_sub_epi32(b5, b7);
+
+ if (iter == 0) {
+ b0 = _mm512_add_epi32(a0, a4);
+ b7 = _mm512_add_epi32(a1, a5);
+ b3 = _mm512_add_epi32(a2, a6);
+ b4 = _mm512_add_epi32(a3, a7);
+ b2 = _mm512_sub_epi32(a0, a4);
+ b6 = _mm512_sub_epi32(a1, a5);
+ b1 = _mm512_sub_epi32(a2, a6);
+ b5 = _mm512_sub_epi32(a3, a7);
+
+ a0 = _mm512_unpacklo_epi32(b0, b1);
+ a1 = _mm512_unpacklo_epi32(b2, b3);
+ a2 = _mm512_unpackhi_epi32(b0, b1);
+ a3 = _mm512_unpackhi_epi32(b2, b3);
+ a4 = _mm512_unpacklo_epi32(b4, b5);
+ a5 = _mm512_unpacklo_epi32(b6, b7);
+ a6 = _mm512_unpackhi_epi32(b4, b5);
+ a7 = _mm512_unpackhi_epi32(b6, b7);
+
+ b0 = _mm512_unpacklo_epi64(a0, a1);
+ b1 = _mm512_unpacklo_epi64(a4, a5);
+ b2 = _mm512_unpackhi_epi64(a0, a1);
+ b3 = _mm512_unpackhi_epi64(a4, a5);
+ b4 = _mm512_unpacklo_epi64(a2, a3);
+ b5 = _mm512_unpacklo_epi64(a6, a7);
+ b6 = _mm512_unpackhi_epi64(a2, a3);
+ b7 = _mm512_unpackhi_epi64(a6, a7);
+
+ const __m512i idx_lo = _mm512_setr_epi64(0, 1, 8, 9, 4, 5, 12, 13);
+ const __m512i idx_hi = _mm512_setr_epi64(2, 3, 10, 11, 6, 7, 14, 15);
+ in[0] = _mm512_permutex2var_epi64(b0, idx_lo, b1);
+ in[1] = _mm512_permutex2var_epi64(b0, idx_hi, b1);
+ in[2] = _mm512_permutex2var_epi64(b2, idx_lo, b3);
+ in[3] = _mm512_permutex2var_epi64(b2, idx_hi, b3);
+ in[4] = _mm512_permutex2var_epi64(b4, idx_lo, b5);
+ in[5] = _mm512_permutex2var_epi64(b4, idx_hi, b5);
+ in[6] = _mm512_permutex2var_epi64(b6, idx_lo, b7);
+ in[7] = _mm512_permutex2var_epi64(b6, idx_hi, b7);
+ } else {
+ in[0] = _mm512_add_epi32(a0, a4);
+ in[7] = _mm512_add_epi32(a1, a5);
+ in[3] = _mm512_add_epi32(a2, a6);
+ in[4] = _mm512_add_epi32(a3, a7);
+ in[2] = _mm512_sub_epi32(a0, a4);
+ in[6] = _mm512_sub_epi32(a1, a5);
+ in[1] = _mm512_sub_epi32(a2, a6);
+ in[5] = _mm512_sub_epi32(a3, a7);
+ }
+}
+
+static inline void highbd_hadamard_8x8_dual_avx512(const int16_t *src_diff,
+ ptrdiff_t src_stride,
+ tran_low_t *coeff) {
+ __m512i src32[8];
+ src32[0] =
+ _mm512_cvtepi16_epi32(_mm256_loadu_si256((const __m256i *)src_diff));
+ src32[1] = _mm512_cvtepi16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src_diff += src_stride)));
+ src32[2] = _mm512_cvtepi16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src_diff += src_stride)));
+ src32[3] = _mm512_cvtepi16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src_diff += src_stride)));
+ src32[4] = _mm512_cvtepi16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src_diff += src_stride)));
+ src32[5] = _mm512_cvtepi16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src_diff += src_stride)));
+ src32[6] = _mm512_cvtepi16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src_diff += src_stride)));
+ src32[7] = _mm512_cvtepi16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src_diff + src_stride)));
+
+ highbd_hadamard_col8x2_avx512(src32, 0);
+ highbd_hadamard_col8x2_avx512(src32, 1);
+
+ _mm512_storeu_si512((__m512i *)coeff,
+ _mm512_shuffle_i64x2(src32[0], src32[1], 0x44));
+ _mm512_storeu_si512((__m512i *)(coeff + 16),
+ _mm512_shuffle_i64x2(src32[2], src32[3], 0x44));
+ _mm512_storeu_si512((__m512i *)(coeff + 32),
+ _mm512_shuffle_i64x2(src32[4], src32[5], 0x44));
+ _mm512_storeu_si512((__m512i *)(coeff + 48),
+ _mm512_shuffle_i64x2(src32[6], src32[7], 0x44));
+ _mm512_storeu_si512((__m512i *)(coeff + 64),
+ _mm512_shuffle_i64x2(src32[0], src32[1], 0xEE));
+ _mm512_storeu_si512((__m512i *)(coeff + 80),
+ _mm512_shuffle_i64x2(src32[2], src32[3], 0xEE));
+ _mm512_storeu_si512((__m512i *)(coeff + 96),
+ _mm512_shuffle_i64x2(src32[4], src32[5], 0xEE));
+ _mm512_storeu_si512((__m512i *)(coeff + 112),
+ _mm512_shuffle_i64x2(src32[6], src32[7], 0xEE));
+}
+
+void aom_highbd_hadamard_16x16_avx512(const int16_t *src_diff,
+ ptrdiff_t src_stride, tran_low_t *coeff) {
+ tran_low_t *t_coeff = coeff;
+ highbd_hadamard_8x8_dual_avx512(src_diff, src_stride, t_coeff);
+ highbd_hadamard_8x8_dual_avx512(src_diff + 8 * src_stride, src_stride,
+ t_coeff + 128);
+
+ for (int idx = 0; idx < 64; idx += 16) {
+ __m512i coeff0 = _mm512_loadu_si512((const __m512i *)t_coeff);
+ __m512i coeff1 = _mm512_loadu_si512((const __m512i *)(t_coeff + 64));
+ __m512i coeff2 = _mm512_loadu_si512((const __m512i *)(t_coeff + 128));
+ __m512i coeff3 = _mm512_loadu_si512((const __m512i *)(t_coeff + 192));
+
+ __m512i b0 = _mm512_srai_epi32(_mm512_add_epi32(coeff0, coeff1), 1);
+ __m512i b1 = _mm512_srai_epi32(_mm512_sub_epi32(coeff0, coeff1), 1);
+ __m512i b2 = _mm512_srai_epi32(_mm512_add_epi32(coeff2, coeff3), 1);
+ __m512i b3 = _mm512_srai_epi32(_mm512_sub_epi32(coeff2, coeff3), 1);
+
+ _mm512_storeu_si512((__m512i *)coeff, _mm512_add_epi32(b0, b2));
+ _mm512_storeu_si512((__m512i *)(coeff + 64), _mm512_add_epi32(b1, b3));
+ _mm512_storeu_si512((__m512i *)(coeff + 128), _mm512_sub_epi32(b0, b2));
+ _mm512_storeu_si512((__m512i *)(coeff + 192), _mm512_sub_epi32(b1, b3));
+
+ coeff += 16;
+ t_coeff += 16;
+ }
+}
+
+void aom_highbd_hadamard_32x32_avx512(const int16_t *src_diff,
+ ptrdiff_t src_stride, tran_low_t *coeff) {
+ tran_low_t *t_coeff = coeff;
+ for (int idx = 0; idx < 4; ++idx) {
+ const int16_t *src_ptr =
+ src_diff + (idx >> 1) * 16 * src_stride + (idx & 0x01) * 16;
+ aom_highbd_hadamard_16x16_avx512(src_ptr, src_stride, t_coeff + idx * 256);
+ }
+
+ for (int idx = 0; idx < 256; idx += 16) {
+ __m512i coeff0 = _mm512_loadu_si512((const __m512i *)t_coeff);
+ __m512i coeff1 = _mm512_loadu_si512((const __m512i *)(t_coeff + 256));
+ __m512i coeff2 = _mm512_loadu_si512((const __m512i *)(t_coeff + 512));
+ __m512i coeff3 = _mm512_loadu_si512((const __m512i *)(t_coeff + 768));
+
+ __m512i b0 = _mm512_srai_epi32(_mm512_add_epi32(coeff0, coeff1), 2);
+ __m512i b1 = _mm512_srai_epi32(_mm512_sub_epi32(coeff0, coeff1), 2);
+ __m512i b2 = _mm512_srai_epi32(_mm512_add_epi32(coeff2, coeff3), 2);
+ __m512i b3 = _mm512_srai_epi32(_mm512_sub_epi32(coeff2, coeff3), 2);
+
+ _mm512_storeu_si512((__m512i *)coeff, _mm512_add_epi32(b0, b2));
+ _mm512_storeu_si512((__m512i *)(coeff + 256), _mm512_add_epi32(b1, b3));
+ _mm512_storeu_si512((__m512i *)(coeff + 512), _mm512_sub_epi32(b0, b2));
+ _mm512_storeu_si512((__m512i *)(coeff + 768), _mm512_sub_epi32(b1, b3));
+
+ coeff += 16;
+ t_coeff += 16;
+ }
+}
+#endif // CONFIG_AV1_HIGHBITDEPTH
+
+int aom_satd_avx512(const tran_low_t *coeff, int length) {
+ __m512i accum0 = _mm512_setzero_si512();
+ __m512i accum1 = _mm512_setzero_si512();
+ int i = 0;
+ for (; i + 32 <= length; i += 32, coeff += 32) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)coeff);
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(coeff + 16));
+ accum0 = _mm512_add_epi32(accum0, _mm512_abs_epi32(s0));
+ accum1 = _mm512_add_epi32(accum1, _mm512_abs_epi32(s1));
+ }
+ for (; i < length; i += 16, coeff += 16) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)coeff);
+ accum0 = _mm512_add_epi32(accum0, _mm512_abs_epi32(s0));
+ }
+ accum0 = _mm512_add_epi32(accum0, accum1);
+ return _mm512_reduce_add_epi32(accum0);
+}
+
+int aom_satd_lp_avx512(const int16_t *coeff, int length) {
+ if (length == 16) {
+ return aom_satd_lp_avx2(coeff, length);
+ }
+ const __m512i one = _mm512_set1_epi16(1);
+ __m512i accum0 = _mm512_setzero_si512();
+ __m512i accum1 = _mm512_setzero_si512();
+ int i = 0;
+ for (; i + 64 <= length; i += 64, coeff += 64) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)coeff);
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(coeff + 32));
+ accum0 =
+ _mm512_add_epi32(accum0, _mm512_madd_epi16(_mm512_abs_epi16(s0), one));
+ accum1 =
+ _mm512_add_epi32(accum1, _mm512_madd_epi16(_mm512_abs_epi16(s1), one));
+ }
+ for (; i < length; i += 32, coeff += 32) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)coeff);
+ accum0 =
+ _mm512_add_epi32(accum0, _mm512_madd_epi16(_mm512_abs_epi16(s0), one));
+ }
+ accum0 = _mm512_add_epi32(accum0, accum1);
+ return _mm512_reduce_add_epi32(accum0);
+}
+
+void aom_int_pro_row_avx512(int16_t *hbuf, const uint8_t *ref,
+ const int ref_stride, const int width,
+ const int height, int norm_factor) {
+ assert(width % 16 == 0 && height % 2 == 0);
+ if (width % 64 == 0) {
+ for (int wd = 0; wd < width; wd += 64) {
+ const uint8_t *ref_tmp = ref + wd;
+ __m512i s0 = _mm512_setzero_si512();
+ __m512i s1 = _mm512_setzero_si512();
+ for (int idx = 0; idx < height; idx += 2) {
+ const __m256i r0_lo = _mm256_loadu_si256((const __m256i *)ref_tmp);
+ const __m256i r0_hi =
+ _mm256_loadu_si256((const __m256i *)(ref_tmp + 32));
+ ref_tmp += ref_stride;
+ const __m256i r1_lo = _mm256_loadu_si256((const __m256i *)ref_tmp);
+ const __m256i r1_hi =
+ _mm256_loadu_si256((const __m256i *)(ref_tmp + 32));
+ ref_tmp += ref_stride;
+
+ s0 = _mm512_add_epi16(s0, _mm512_cvtepu8_epi16(r0_lo));
+ s1 = _mm512_add_epi16(s1, _mm512_cvtepu8_epi16(r0_hi));
+ s0 = _mm512_add_epi16(s0, _mm512_cvtepu8_epi16(r1_lo));
+ s1 = _mm512_add_epi16(s1, _mm512_cvtepu8_epi16(r1_hi));
+ }
+ s0 = _mm512_srai_epi16(s0, norm_factor);
+ s1 = _mm512_srai_epi16(s1, norm_factor);
+ _mm512_storeu_si512((__m512i *)(hbuf + wd), s0);
+ _mm512_storeu_si512((__m512i *)(hbuf + wd + 32), s1);
+ }
+ } else if (width == 32) {
+ const uint8_t *ref_tmp = ref;
+ __m512i s0 = _mm512_setzero_si512();
+ for (int idx = 0; idx < height; idx += 2) {
+ const __m256i r0 = _mm256_loadu_si256((const __m256i *)ref_tmp);
+ ref_tmp += ref_stride;
+ const __m256i r1 = _mm256_loadu_si256((const __m256i *)ref_tmp);
+ ref_tmp += ref_stride;
+ s0 = _mm512_add_epi16(s0, _mm512_cvtepu8_epi16(r0));
+ s0 = _mm512_add_epi16(s0, _mm512_cvtepu8_epi16(r1));
+ }
+ s0 = _mm512_srai_epi16(s0, norm_factor);
+ _mm512_storeu_si512((__m512i *)hbuf, s0);
+ } else {
+ aom_int_pro_row_sse2(hbuf, ref, ref_stride, width, height, norm_factor);
+ }
+}
+
+#define CALC_TOT_SAD_AND_STORE_AVX512 \
+ const __m512i r01 = _mm512_add_epi16(_mm512_bslli_epi128(r1, 2), r0); \
+ const __m512i r012 = _mm512_add_epi16(_mm512_bslli_epi128(r2, 4), r01); \
+ const __m512i result0 = _mm512_add_epi16(_mm512_bslli_epi128(r3, 6), r012); \
+ const __m256i res256 = _mm256_add_epi16( \
+ _mm512_castsi512_si256(result0), _mm512_extracti64x4_epi64(result0, 1)); \
+ const __m128i res128 = _mm_add_epi16(_mm256_castsi256_si128(res256), \
+ _mm256_extracti128_si256(res256, 1)); \
+ const __m128i results1 = _mm_add_epi16(res128, _mm_srli_si128(res128, 8)); \
+ _mm_storel_epi64((__m128i *)vbuf, _mm_srli_epi16(results1, norm_factor));
+
+void aom_int_pro_col_avx512(int16_t *vbuf, const uint8_t *ref,
+ const int ref_stride, const int width,
+ const int height, int norm_factor) {
+ assert(width % 16 == 0);
+ if (width == 128) {
+ const __m512i zero = _mm512_setzero_si512();
+ for (int ht = 0; ht < height; ht += 4) {
+ const __m512i s0_0 = _mm512_loadu_si512((const __m512i *)ref);
+ const __m512i s0_1 = _mm512_loadu_si512((const __m512i *)(ref + 64));
+ const __m512i s1_0 =
+ _mm512_loadu_si512((const __m512i *)(ref + ref_stride));
+ const __m512i s1_1 =
+ _mm512_loadu_si512((const __m512i *)(ref + ref_stride + 64));
+ const __m512i s2_0 =
+ _mm512_loadu_si512((const __m512i *)(ref + 2 * ref_stride));
+ const __m512i s2_1 =
+ _mm512_loadu_si512((const __m512i *)(ref + 2 * ref_stride + 64));
+ const __m512i s3_0 =
+ _mm512_loadu_si512((const __m512i *)(ref + 3 * ref_stride));
+ const __m512i s3_1 =
+ _mm512_loadu_si512((const __m512i *)(ref + 3 * ref_stride + 64));
+
+ const __m512i r0 = _mm512_add_epi16(_mm512_sad_epu8(s0_0, zero),
+ _mm512_sad_epu8(s0_1, zero));
+ const __m512i r1 = _mm512_add_epi16(_mm512_sad_epu8(s1_0, zero),
+ _mm512_sad_epu8(s1_1, zero));
+ const __m512i r2 = _mm512_add_epi16(_mm512_sad_epu8(s2_0, zero),
+ _mm512_sad_epu8(s2_1, zero));
+ const __m512i r3 = _mm512_add_epi16(_mm512_sad_epu8(s3_0, zero),
+ _mm512_sad_epu8(s3_1, zero));
+
+ CALC_TOT_SAD_AND_STORE_AVX512
+ vbuf += 4;
+ ref += ref_stride << 2;
+ }
+ } else if (width == 64) {
+ const __m512i zero = _mm512_setzero_si512();
+ for (int ht = 0; ht < height; ht += 4) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)ref);
+ const __m512i s1 =
+ _mm512_loadu_si512((const __m512i *)(ref + ref_stride));
+ const __m512i s2 =
+ _mm512_loadu_si512((const __m512i *)(ref + 2 * ref_stride));
+ const __m512i s3 =
+ _mm512_loadu_si512((const __m512i *)(ref + 3 * ref_stride));
+
+ const __m512i r0 = _mm512_sad_epu8(s0, zero);
+ const __m512i r1 = _mm512_sad_epu8(s1, zero);
+ const __m512i r2 = _mm512_sad_epu8(s2, zero);
+ const __m512i r3 = _mm512_sad_epu8(s3, zero);
+
+ CALC_TOT_SAD_AND_STORE_AVX512
+ vbuf += 4;
+ ref += ref_stride << 2;
+ }
+ } else {
+ aom_int_pro_col_avx2(vbuf, ref, ref_stride, width, height, norm_factor);
+ }
+}
+
+int aom_vector_var_avx512(const int16_t *ref, const int16_t *src, int bwl) {
+ const int width = 4 << bwl;
+ assert(width % 16 == 0 && width <= 128);
+ const __m512i one = _mm512_set1_epi16(1);
+
+ if (width == 128) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(src + 32));
+ const __m512i s2 = _mm512_loadu_si512((const __m512i *)(src + 64));
+ const __m512i s3 = _mm512_loadu_si512((const __m512i *)(src + 96));
+ const __m512i r0 = _mm512_loadu_si512((const __m512i *)ref);
+ const __m512i r1 = _mm512_loadu_si512((const __m512i *)(ref + 32));
+ const __m512i r2 = _mm512_loadu_si512((const __m512i *)(ref + 64));
+ const __m512i r3 = _mm512_loadu_si512((const __m512i *)(ref + 96));
+
+ const __m512i d0 = _mm512_sub_epi16(r0, s0);
+ const __m512i d1 = _mm512_sub_epi16(r1, s1);
+ const __m512i d2 = _mm512_sub_epi16(r2, s2);
+ const __m512i d3 = _mm512_sub_epi16(r3, s3);
+
+ const __m512i mean16 =
+ _mm512_add_epi16(_mm512_add_epi16(d0, d1), _mm512_add_epi16(d2, d3));
+ const __m512i sse0 =
+ _mm512_add_epi32(_mm512_madd_epi16(d0, d0), _mm512_madd_epi16(d1, d1));
+ const __m512i sse1 =
+ _mm512_add_epi32(_mm512_madd_epi16(d2, d2), _mm512_madd_epi16(d3, d3));
+ const __m512i sse32 = _mm512_add_epi32(sse0, sse1);
+ const __m512i mean32 = _mm512_madd_epi16(mean16, one);
+
+ const int mean_int = _mm512_reduce_add_epi32(mean32);
+ const int sse_int = _mm512_reduce_add_epi32(sse32);
+ const unsigned int mean_abs = (unsigned int)abs(mean_int);
+ return sse_int - (int)((mean_abs * mean_abs) >> (bwl + 2));
+ } else if (width == 64) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(src + 32));
+ const __m512i r0 = _mm512_loadu_si512((const __m512i *)ref);
+ const __m512i r1 = _mm512_loadu_si512((const __m512i *)(ref + 32));
+
+ const __m512i d0 = _mm512_sub_epi16(r0, s0);
+ const __m512i d1 = _mm512_sub_epi16(r1, s1);
+
+ const __m512i mean16 = _mm512_add_epi16(d0, d1);
+ const __m512i sse32 =
+ _mm512_add_epi32(_mm512_madd_epi16(d0, d0), _mm512_madd_epi16(d1, d1));
+ const __m512i mean32 = _mm512_madd_epi16(mean16, one);
+
+ const int mean_int = _mm512_reduce_add_epi32(mean32);
+ const int sse_int = _mm512_reduce_add_epi32(sse32);
+ const unsigned int mean_abs = (unsigned int)abs(mean_int);
+ return sse_int - (int)((mean_abs * mean_abs) >> (bwl + 2));
+ } else if (width == 32) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i r0 = _mm512_loadu_si512((const __m512i *)ref);
+ const __m512i d0 = _mm512_sub_epi16(r0, s0);
+ const __m512i sse32 = _mm512_madd_epi16(d0, d0);
+ const __m512i mean32 = _mm512_madd_epi16(d0, one);
+
+ const int mean_int = _mm512_reduce_add_epi32(mean32);
+ const int sse_int = _mm512_reduce_add_epi32(sse32);
+ const unsigned int mean_abs = (unsigned int)abs(mean_int);
+ return sse_int - (int)((mean_abs * mean_abs) >> (bwl + 2));
+ } else {
+ return aom_vector_var_avx2(ref, src, bwl);
+ }
+}
+
+static inline void init_one_b_qp_avx512(__m128i v128, __m512i *v512) {
+ const __m128i ac = _mm_unpackhi_epi64(v128, v128);
+ const __m256i dc_ac =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(v128), ac, 1);
+ const __m256i ac256 = _mm256_broadcastq_epi64(ac);
+ *v512 = _mm512_inserti64x4(_mm512_castsi256_si512(dc_ac), ac256, 1);
+}
+
+static inline void load_b_values_avx512(
+ const int16_t *zbin_ptr, __m512i *zbin, const int16_t *round_ptr,
+ __m512i *round, const int16_t *quant_ptr, __m512i *quant,
+ const int16_t *dequant_ptr, __m512i *dequant, const int16_t *shift_ptr,
+ __m512i *shift, int log_scale) {
+ __m128i zbin128 = _mm_loadu_si128((const __m128i *)zbin_ptr);
+ __m128i round128 = _mm_loadu_si128((const __m128i *)round_ptr);
+ const __m128i quant128 = _mm_loadu_si128((const __m128i *)quant_ptr);
+ const __m128i dequant128 = _mm_loadu_si128((const __m128i *)dequant_ptr);
+ const __m128i shift128 = _mm_loadu_si128((const __m128i *)shift_ptr);
+
+ if (log_scale > 0) {
+ const __m128i rnd = _mm_set1_epi16((int16_t)(1 << (log_scale - 1)));
+ zbin128 = _mm_srai_epi16(_mm_add_epi16(zbin128, rnd), log_scale);
+ round128 = _mm_srai_epi16(_mm_add_epi16(round128, rnd), log_scale);
+ }
+ zbin128 = _mm_sub_epi16(zbin128, _mm_set1_epi16(1));
+
+ init_one_b_qp_avx512(zbin128, zbin);
+ init_one_b_qp_avx512(round128, round);
+ init_one_b_qp_avx512(quant128, quant);
+ init_one_b_qp_avx512(dequant128, dequant);
+ init_one_b_qp_avx512(shift128, shift);
+}
+
+static inline __m512i load_b_coefficients_avx512(const tran_low_t *coeff_ptr) {
+ const __m512i coeff1 = _mm512_loadu_si512((const __m512i *)coeff_ptr);
+ const __m512i coeff2 = _mm512_loadu_si512((const __m512i *)(coeff_ptr + 16));
+ return _mm512_packs_epi32(coeff1, coeff2);
+}
+
+static inline void store_b_coefficients_avx512(__m512i coeff_vals,
+ tran_low_t *coeff_ptr) {
+ const __m512i coeff_sign = _mm512_srai_epi16(coeff_vals, 15);
+ const __m512i coeff_lo = _mm512_unpacklo_epi16(coeff_vals, coeff_sign);
+ const __m512i coeff_hi = _mm512_unpackhi_epi16(coeff_vals, coeff_sign);
+ _mm512_storeu_si512((__m512i *)coeff_ptr, coeff_lo);
+ _mm512_storeu_si512((__m512i *)(coeff_ptr + 16), coeff_hi);
+}
+
+static inline __m512i get_max_lane_eob_b_avx512(const int16_t *iscan,
+ __m512i v_eobmax,
+ __mmask32 nz_mask) {
+ const __m512i v_iscan = _mm512_loadu_si512((const __m512i *)iscan);
+ const __m512i perm_idx = _mm512_setr_epi64(0, 4, 1, 5, 2, 6, 3, 7);
+ const __m512i v_iscan_perm = _mm512_permutexvar_epi64(perm_idx, v_iscan);
+ const __m512i v_nz_iscan =
+ _mm512_maskz_add_epi16(nz_mask, v_iscan_perm, _mm512_set1_epi16(1));
+ return _mm512_max_epi16(v_eobmax, v_nz_iscan);
+}
+
+static inline uint16_t accumulate_eob512(__m512i eob512) {
+ const __m256i eob256 = _mm256_max_epi16(_mm512_castsi512_si256(eob512),
+ _mm512_extracti64x4_epi64(eob512, 1));
+ const __m128i eob_lo = _mm256_castsi256_si128(eob256);
+ const __m128i eob_hi = _mm256_extracti128_si256(eob256, 1);
+ __m128i eob_s = _mm_max_epi16(eob_lo, eob_hi);
+ eob_s = _mm_subs_epu16(_mm_set1_epi16(INT16_MAX), eob_s);
+ eob_s = _mm_minpos_epu16(eob_s);
+ return (uint16_t)(INT16_MAX - _mm_extract_epi16(eob_s, 0));
+}
+
+static inline __m512i mm512_sign_epi16(__m512i a, __m512i b) {
+ const __m512i zero = _mm512_setzero_si512();
+ const __mmask32 nz_mask = _mm512_cmpneq_epi16_mask(b, zero);
+ const __mmask32 neg_mask = _mm512_cmpgt_epi16_mask(zero, b);
+ const __m512i a_nz = _mm512_maskz_mov_epi16(nz_mask, a);
+ return _mm512_mask_sub_epi16(a_nz, neg_mask, zero, a_nz);
+}
+
+static AOM_FORCE_INLINE __mmask32 quantize_b_logscale0_32_avx512(
+ const tran_low_t *coeff_ptr, tran_low_t *qcoeff_ptr,
+ tran_low_t *dqcoeff_ptr, const __m512i *v_quant, const __m512i *v_dequant,
+ const __m512i *v_round, const __m512i *v_zbin,
+ const __m512i *v_quant_shift) {
+ const __m512i v_coeff = load_b_coefficients_avx512(coeff_ptr);
+ const __m512i v_abs_coeff = _mm512_abs_epi16(v_coeff);
+ const __mmask32 zbin_mask = _mm512_cmpgt_epi16_mask(v_abs_coeff, *v_zbin);
+
+ if (zbin_mask == 0) {
+ const __m512i zero = _mm512_setzero_si512();
+ _mm512_storeu_si512((__m512i *)qcoeff_ptr, zero);
+ _mm512_storeu_si512((__m512i *)(qcoeff_ptr + 16), zero);
+ _mm512_storeu_si512((__m512i *)dqcoeff_ptr, zero);
+ _mm512_storeu_si512((__m512i *)(dqcoeff_ptr + 16), zero);
+ return 0;
+ }
+
+ const __m512i v_tmp_rnd =
+ _mm512_maskz_adds_epi16(zbin_mask, v_abs_coeff, *v_round);
+ const __m512i v_tmp32_a = _mm512_mulhi_epi16(v_tmp_rnd, *v_quant);
+ const __m512i v_tmp32_b = _mm512_add_epi16(v_tmp32_a, v_tmp_rnd);
+ const __m512i v_tmp32 = _mm512_mulhi_epi16(v_tmp32_b, *v_quant_shift);
+ const __mmask32 nz_mask =
+ _mm512_cmpgt_epi16_mask(v_tmp32, _mm512_setzero_si512());
+ const __m512i v_qcoeff = mm512_sign_epi16(v_tmp32, v_coeff);
+ const __m512i v_dqcoeff = _mm512_mullo_epi16(v_qcoeff, *v_dequant);
+ store_b_coefficients_avx512(v_qcoeff, qcoeff_ptr);
+ store_b_coefficients_avx512(v_dqcoeff, dqcoeff_ptr);
+ return nz_mask;
+}
+
+void aom_quantize_b_avx512(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
+ const int16_t *zbin_ptr, const int16_t *round_ptr,
+ const int16_t *quant_ptr,
+ const int16_t *quant_shift_ptr,
+ tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
+ const int16_t *dequant_ptr, uint16_t *eob_ptr,
+ const int16_t *scan, const int16_t *iscan) {
+ if (n_coeffs < 32) {
+ aom_quantize_b_avx2(coeff_ptr, n_coeffs, zbin_ptr, round_ptr, quant_ptr,
+ quant_shift_ptr, qcoeff_ptr, dqcoeff_ptr, dequant_ptr,
+ eob_ptr, scan, iscan);
+ return;
+ }
+ (void)scan;
+ __m512i v_zbin, v_round, v_quant, v_dequant, v_quant_shift;
+ __m512i v_eobmax = _mm512_setzero_si512();
+
+ load_b_values_avx512(zbin_ptr, &v_zbin, round_ptr, &v_round, quant_ptr,
+ &v_quant, dequant_ptr, &v_dequant, quant_shift_ptr,
+ &v_quant_shift, 0);
+
+ __mmask32 nz_mask = quantize_b_logscale0_32_avx512(
+ coeff_ptr, qcoeff_ptr, dqcoeff_ptr, &v_quant, &v_dequant, &v_round,
+ &v_zbin, &v_quant_shift);
+ if (nz_mask) v_eobmax = get_max_lane_eob_b_avx512(iscan, v_eobmax, nz_mask);
+
+ v_round = _mm512_unpackhi_epi64(v_round, v_round);
+ v_quant = _mm512_unpackhi_epi64(v_quant, v_quant);
+ v_dequant = _mm512_unpackhi_epi64(v_dequant, v_dequant);
+ v_quant_shift = _mm512_unpackhi_epi64(v_quant_shift, v_quant_shift);
+ v_zbin = _mm512_unpackhi_epi64(v_zbin, v_zbin);
+
+ for (intptr_t count = n_coeffs - 32; count > 0; count -= 32) {
+ coeff_ptr += 32;
+ qcoeff_ptr += 32;
+ dqcoeff_ptr += 32;
+ iscan += 32;
+ nz_mask = quantize_b_logscale0_32_avx512(coeff_ptr, qcoeff_ptr, dqcoeff_ptr,
+ &v_quant, &v_dequant, &v_round,
+ &v_zbin, &v_quant_shift);
+ if (nz_mask) v_eobmax = get_max_lane_eob_b_avx512(iscan, v_eobmax, nz_mask);
+ }
+
+ *eob_ptr = accumulate_eob512(v_eobmax);
+}
+
+static AOM_FORCE_INLINE __mmask32 quantize_b_logscale_32_avx512(
+ const tran_low_t *coeff_ptr, tran_low_t *qcoeff_ptr,
+ tran_low_t *dqcoeff_ptr, const __m512i *v_quant, const __m512i *v_dequant,
+ const __m512i *v_round, const __m512i *v_zbin, const __m512i *v_quant_shift,
+ int log_scale) {
+ const __m512i v_coeff = load_b_coefficients_avx512(coeff_ptr);
+ const __m512i v_abs_coeff = _mm512_abs_epi16(v_coeff);
+ const __mmask32 zbin_mask = _mm512_cmpgt_epi16_mask(v_abs_coeff, *v_zbin);
+
+ if (zbin_mask == 0) {
+ const __m512i zero = _mm512_setzero_si512();
+ _mm512_storeu_si512((__m512i *)qcoeff_ptr, zero);
+ _mm512_storeu_si512((__m512i *)(qcoeff_ptr + 16), zero);
+ _mm512_storeu_si512((__m512i *)dqcoeff_ptr, zero);
+ _mm512_storeu_si512((__m512i *)(dqcoeff_ptr + 16), zero);
+ return 0;
+ }
+
+ const __m512i v_tmp_rnd =
+ _mm512_maskz_adds_epi16(zbin_mask, v_abs_coeff, *v_round);
+ const __m512i v_tmp32_a = _mm512_mulhi_epi16(v_tmp_rnd, *v_quant);
+ const __m512i v_tmp32_b = _mm512_add_epi16(v_tmp32_a, v_tmp_rnd);
+ const __m512i v_tmp32_hi = _mm512_slli_epi16(
+ _mm512_mulhi_epi16(v_tmp32_b, *v_quant_shift), (unsigned int)log_scale);
+ const __m512i v_tmp32_lo =
+ _mm512_srli_epi16(_mm512_mullo_epi16(v_tmp32_b, *v_quant_shift),
+ (unsigned int)(16 - log_scale));
+ const __m512i v_tmp32 = _mm512_or_si512(v_tmp32_hi, v_tmp32_lo);
+ const __m512i v_dqcoeff_hi = _mm512_slli_epi16(
+ _mm512_mulhi_epi16(v_tmp32, *v_dequant), (unsigned int)(16 - log_scale));
+ const __m512i v_dqcoeff_lo = _mm512_srli_epi16(
+ _mm512_mullo_epi16(v_tmp32, *v_dequant), (unsigned int)log_scale);
+ const __m512i v_dqcoeff =
+ mm512_sign_epi16(_mm512_or_si512(v_dqcoeff_hi, v_dqcoeff_lo), v_coeff);
+ const __m512i v_qcoeff = mm512_sign_epi16(v_tmp32, v_coeff);
+ const __mmask32 nz_mask =
+ _mm512_cmpgt_epi16_mask(v_tmp32, _mm512_setzero_si512());
+ store_b_coefficients_avx512(v_qcoeff, qcoeff_ptr);
+ store_b_coefficients_avx512(v_dqcoeff, dqcoeff_ptr);
+ return nz_mask;
+}
+
+static AOM_FORCE_INLINE void quantize_b_no_qmatrix_avx512(
+ const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
+ const int16_t *round_ptr, const int16_t *quant_ptr,
+ const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
+ tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
+ const int16_t *iscan, int log_scale) {
+ __m512i v_zbin, v_round, v_quant, v_dequant, v_quant_shift;
+ __m512i v_eobmax = _mm512_setzero_si512();
+
+ load_b_values_avx512(zbin_ptr, &v_zbin, round_ptr, &v_round, quant_ptr,
+ &v_quant, dequant_ptr, &v_dequant, quant_shift_ptr,
+ &v_quant_shift, log_scale);
+
+ __mmask32 nz_mask = quantize_b_logscale_32_avx512(
+ coeff_ptr, qcoeff_ptr, dqcoeff_ptr, &v_quant, &v_dequant, &v_round,
+ &v_zbin, &v_quant_shift, log_scale);
+ if (nz_mask) v_eobmax = get_max_lane_eob_b_avx512(iscan, v_eobmax, nz_mask);
+
+ v_round = _mm512_unpackhi_epi64(v_round, v_round);
+ v_quant = _mm512_unpackhi_epi64(v_quant, v_quant);
+ v_dequant = _mm512_unpackhi_epi64(v_dequant, v_dequant);
+ v_quant_shift = _mm512_unpackhi_epi64(v_quant_shift, v_quant_shift);
+ v_zbin = _mm512_unpackhi_epi64(v_zbin, v_zbin);
+
+ for (intptr_t count = n_coeffs - 32; count > 0; count -= 32) {
+ coeff_ptr += 32;
+ qcoeff_ptr += 32;
+ dqcoeff_ptr += 32;
+ iscan += 32;
+ nz_mask = quantize_b_logscale_32_avx512(coeff_ptr, qcoeff_ptr, dqcoeff_ptr,
+ &v_quant, &v_dequant, &v_round,
+ &v_zbin, &v_quant_shift, log_scale);
+ if (nz_mask) v_eobmax = get_max_lane_eob_b_avx512(iscan, v_eobmax, nz_mask);
+ }
+
+ *eob_ptr = accumulate_eob512(v_eobmax);
+}
+
+void aom_quantize_b_32x32_avx512(
+ const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
+ const int16_t *round_ptr, const int16_t *quant_ptr,
+ const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
+ tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
+ const int16_t *scan, const int16_t *iscan) {
+ (void)scan;
+ quantize_b_no_qmatrix_avx512(coeff_ptr, n_coeffs, zbin_ptr, round_ptr,
+ quant_ptr, quant_shift_ptr, qcoeff_ptr,
+ dqcoeff_ptr, dequant_ptr, eob_ptr, iscan, 1);
+}
+
+void aom_quantize_b_64x64_avx512(
+ const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
+ const int16_t *round_ptr, const int16_t *quant_ptr,
+ const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
+ tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
+ const int16_t *scan, const int16_t *iscan) {
+ (void)scan;
+ quantize_b_no_qmatrix_avx512(coeff_ptr, n_coeffs, zbin_ptr, round_ptr,
+ quant_ptr, quant_shift_ptr, qcoeff_ptr,
+ dqcoeff_ptr, dequant_ptr, eob_ptr, iscan, 2);
+}
diff --git a/aom_dsp/x86/sad_avx512.c b/aom_dsp/x86/sad_avx512.c
new file mode 100644
index 0000000000..9f6a262b1e
--- /dev/null
+++ b/aom_dsp/x86/sad_avx512.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <immintrin.h>
+#include <stdint.h>
+
+#include "config/aom_config.h"
+#include "config/aom_dsp_rtcd.h"
+#include "aom_dsp/x86/synonyms.h"
+#include "aom_dsp/x86/synonyms_avx2.h"
+#include "aom_ports/mem.h"
+
+static AOM_FORCE_INLINE unsigned int hsum_sad_zmm(__m512i sum_sad) {
+ const __m256i sum256 = _mm256_add_epi32(
+ _mm512_castsi512_si256(sum_sad), _mm512_extracti64x4_epi64(sum_sad, 1));
+ const __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum256),
+ _mm256_extracti128_si256(sum256, 1));
+ const __m128i sum64 = _mm_add_epi32(sum128, _mm_srli_si128(sum128, 8));
+ return (unsigned int)_mm_cvtsi128_si32(sum64);
+}
+
+static AOM_FORCE_INLINE void aggregate_and_store_sum_zmm(uint32_t *res,
+ __m512i sum_ref0,
+ __m512i sum_ref1,
+ __m512i sum_ref2,
+ __m512i sum_ref3) {
+ __m256i s0 = _mm256_add_epi32(_mm512_castsi512_si256(sum_ref0),
+ _mm512_extracti64x4_epi64(sum_ref0, 1));
+ __m256i s1 = _mm256_add_epi32(_mm512_castsi512_si256(sum_ref1),
+ _mm512_extracti64x4_epi64(sum_ref1, 1));
+ __m256i s2 = _mm256_add_epi32(_mm512_castsi512_si256(sum_ref2),
+ _mm512_extracti64x4_epi64(sum_ref2, 1));
+ __m256i s3 = _mm256_add_epi32(_mm512_castsi512_si256(sum_ref3),
+ _mm512_extracti64x4_epi64(sum_ref3, 1));
+
+ const __m256i sum_even = _mm256_unpacklo_epi32(s0, s1);
+ const __m256i sum_odd = _mm256_unpackhi_epi32(s0, s1);
+ const __m256i sum_01 = _mm256_add_epi32(sum_even, sum_odd);
+
+ const __m256i sum_even23 = _mm256_unpacklo_epi32(s2, s3);
+ const __m256i sum_odd23 = _mm256_unpackhi_epi32(s2, s3);
+ const __m256i sum_23 = _mm256_add_epi32(sum_even23, sum_odd23);
+
+ const __m256i sum = _mm256_unpacklo_epi64(sum_01, sum_23);
+ const __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum),
+ _mm256_extracti128_si256(sum, 1));
+ _mm_storeu_si128((__m128i *)res, sum128);
+}
+
+static AOM_FORCE_INLINE void aggregate_and_store_sum_3d_zmm(uint32_t *res,
+ __m512i sum_ref0,
+ __m512i sum_ref1,
+ __m512i sum_ref2) {
+ __m256i s0 = _mm256_add_epi32(_mm512_castsi512_si256(sum_ref0),
+ _mm512_extracti64x4_epi64(sum_ref0, 1));
+ __m256i s1 = _mm256_add_epi32(_mm512_castsi512_si256(sum_ref1),
+ _mm512_extracti64x4_epi64(sum_ref1, 1));
+ __m256i s2 = _mm256_add_epi32(_mm512_castsi512_si256(sum_ref2),
+ _mm512_extracti64x4_epi64(sum_ref2, 1));
+
+ const __m256i sum_even = _mm256_unpacklo_epi32(s0, s1);
+ const __m256i sum_odd = _mm256_unpackhi_epi32(s0, s1);
+ const __m256i sum_01 = _mm256_add_epi32(sum_even, sum_odd);
+
+ const __m256i sum_even2 = _mm256_unpacklo_epi32(s2, _mm256_setzero_si256());
+ const __m256i sum_odd2 = _mm256_unpackhi_epi32(s2, _mm256_setzero_si256());
+ const __m256i sum_23 = _mm256_add_epi32(sum_even2, sum_odd2);
+
+ const __m256i sum = _mm256_unpacklo_epi64(sum_01, sum_23);
+ const __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum),
+ _mm256_extracti128_si256(sum, 1));
+ _mm_storeu_si128((__m128i *)res, sum128);
+}
+
+#if !CONFIG_HIGHWAY || !CONFIG_REALTIME_ONLY
+static AOM_FORCE_INLINE unsigned int sad64xh_avx512(const uint8_t *src_ptr,
+ int src_stride,
+ const uint8_t *ref_ptr,
+ int ref_stride, int h) {
+ __m512i sum_sad = _mm512_setzero_si512();
+ for (int i = 0; i < h; i += 2) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src_ptr);
+ const __m512i r0 = _mm512_loadu_si512((const __m512i *)ref_ptr);
+ const __m512i s1 =
+ _mm512_loadu_si512((const __m512i *)(src_ptr + src_stride));
+ const __m512i r1 =
+ _mm512_loadu_si512((const __m512i *)(ref_ptr + ref_stride));
+ sum_sad = _mm512_add_epi32(sum_sad, _mm512_sad_epu8(r0, s0));
+ sum_sad = _mm512_add_epi32(sum_sad, _mm512_sad_epu8(r1, s1));
+ src_ptr += src_stride * 2;
+ ref_ptr += ref_stride * 2;
+ }
+ return hsum_sad_zmm(sum_sad);
+}
+
+static AOM_FORCE_INLINE unsigned int sad64xh_avg_avx512(
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr,
+ int ref_stride, int h, const uint8_t *second_pred) {
+ __m512i sum_sad = _mm512_setzero_si512();
+ for (int i = 0; i < h; i += 2) {
+ const __m512i r0 =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)ref_ptr),
+ _mm512_loadu_si512((const __m512i *)second_pred));
+ const __m512i r1 = _mm512_avg_epu8(
+ _mm512_loadu_si512((const __m512i *)(ref_ptr + ref_stride)),
+ _mm512_loadu_si512((const __m512i *)(second_pred + 64)));
+ sum_sad = _mm512_add_epi32(
+ sum_sad,
+ _mm512_sad_epu8(r0, _mm512_loadu_si512((const __m512i *)src_ptr)));
+ sum_sad = _mm512_add_epi32(
+ sum_sad,
+ _mm512_sad_epu8(
+ r1, _mm512_loadu_si512((const __m512i *)(src_ptr + src_stride))));
+ src_ptr += src_stride * 2;
+ ref_ptr += ref_stride * 2;
+ second_pred += 128;
+ }
+ return hsum_sad_zmm(sum_sad);
+}
+
+static AOM_FORCE_INLINE void sad64xhx4d_avx512(int h, const uint8_t *src,
+ int src_stride,
+ const uint8_t *const ref[4],
+ int ref_stride, uint32_t *res) {
+ const uint8_t *ref0 = ref[0];
+ const uint8_t *ref1 = ref[1];
+ const uint8_t *ref2 = ref[2];
+ const uint8_t *ref3 = ref[3];
+ __m512i sum_ref0 = _mm512_setzero_si512();
+ __m512i sum_ref1 = _mm512_setzero_si512();
+ __m512i sum_ref2 = _mm512_setzero_si512();
+ __m512i sum_ref3 = _mm512_setzero_si512();
+
+ for (int i = 0; i < h; i++) {
+ const __m512i s = _mm512_loadu_si512((const __m512i *)src);
+ sum_ref0 = _mm512_add_epi32(
+ sum_ref0,
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref0), s));
+ sum_ref1 = _mm512_add_epi32(
+ sum_ref1,
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref1), s));
+ sum_ref2 = _mm512_add_epi32(
+ sum_ref2,
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref2), s));
+ sum_ref3 = _mm512_add_epi32(
+ sum_ref3,
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref3), s));
+ src += src_stride;
+ ref0 += ref_stride;
+ ref1 += ref_stride;
+ ref2 += ref_stride;
+ ref3 += ref_stride;
+ }
+ aggregate_and_store_sum_zmm(res, sum_ref0, sum_ref1, sum_ref2, sum_ref3);
+}
+
+static AOM_FORCE_INLINE void sad64xhx3d_avx512(int h, const uint8_t *src,
+ int src_stride,
+ const uint8_t *const ref[4],
+ int ref_stride, uint32_t *res) {
+ const uint8_t *ref0 = ref[0];
+ const uint8_t *ref1 = ref[1];
+ const uint8_t *ref2 = ref[2];
+ __m512i sum_ref0 = _mm512_setzero_si512();
+ __m512i sum_ref1 = _mm512_setzero_si512();
+ __m512i sum_ref2 = _mm512_setzero_si512();
+
+ for (int i = 0; i < h; i++) {
+ const __m512i s = _mm512_loadu_si512((const __m512i *)src);
+ sum_ref0 = _mm512_add_epi32(
+ sum_ref0,
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref0), s));
+ sum_ref1 = _mm512_add_epi32(
+ sum_ref1,
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref1), s));
+ sum_ref2 = _mm512_add_epi32(
+ sum_ref2,
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref2), s));
+ src += src_stride;
+ ref0 += ref_stride;
+ ref1 += ref_stride;
+ ref2 += ref_stride;
+ }
+ aggregate_and_store_sum_3d_zmm(res, sum_ref0, sum_ref1, sum_ref2);
+}
+#endif // !CONFIG_HIGHWAY || !CONFIG_REALTIME_ONLY
+
+#if !CONFIG_HIGHWAY
+static AOM_FORCE_INLINE unsigned int sad128xh_avx512(const uint8_t *src_ptr,
+ int src_stride,
+ const uint8_t *ref_ptr,
+ int ref_stride, int h) {
+ __m512i sum_sad0 = _mm512_setzero_si512();
+ __m512i sum_sad1 = _mm512_setzero_si512();
+ for (int i = 0; i < h; i++) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src_ptr);
+ const __m512i r0 = _mm512_loadu_si512((const __m512i *)ref_ptr);
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(src_ptr + 64));
+ const __m512i r1 = _mm512_loadu_si512((const __m512i *)(ref_ptr + 64));
+ sum_sad0 = _mm512_add_epi32(sum_sad0, _mm512_sad_epu8(r0, s0));
+ sum_sad1 = _mm512_add_epi32(sum_sad1, _mm512_sad_epu8(r1, s1));
+ src_ptr += src_stride;
+ ref_ptr += ref_stride;
+ }
+ return hsum_sad_zmm(_mm512_add_epi32(sum_sad0, sum_sad1));
+}
+
+static AOM_FORCE_INLINE unsigned int sad128xh_avg_avx512(
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr,
+ int ref_stride, int h, const uint8_t *second_pred) {
+ __m512i sum_sad0 = _mm512_setzero_si512();
+ __m512i sum_sad1 = _mm512_setzero_si512();
+ for (int i = 0; i < h; i++) {
+ const __m512i r0 =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)ref_ptr),
+ _mm512_loadu_si512((const __m512i *)second_pred));
+ const __m512i r1 = _mm512_avg_epu8(
+ _mm512_loadu_si512((const __m512i *)(ref_ptr + 64)),
+ _mm512_loadu_si512((const __m512i *)(second_pred + 64)));
+ sum_sad0 = _mm512_add_epi32(
+ sum_sad0,
+ _mm512_sad_epu8(r0, _mm512_loadu_si512((const __m512i *)src_ptr)));
+ sum_sad1 = _mm512_add_epi32(
+ sum_sad1, _mm512_sad_epu8(
+ r1, _mm512_loadu_si512((const __m512i *)(src_ptr + 64))));
+ src_ptr += src_stride;
+ ref_ptr += ref_stride;
+ second_pred += 128;
+ }
+ return hsum_sad_zmm(_mm512_add_epi32(sum_sad0, sum_sad1));
+}
+
+static AOM_FORCE_INLINE void sad128xhx4d_avx512(int h, const uint8_t *src,
+ int src_stride,
+ const uint8_t *const ref[4],
+ int ref_stride, uint32_t *res) {
+ const uint8_t *ref0 = ref[0];
+ const uint8_t *ref1 = ref[1];
+ const uint8_t *ref2 = ref[2];
+ const uint8_t *ref3 = ref[3];
+ __m512i sum_ref0 = _mm512_setzero_si512();
+ __m512i sum_ref1 = _mm512_setzero_si512();
+ __m512i sum_ref2 = _mm512_setzero_si512();
+ __m512i sum_ref3 = _mm512_setzero_si512();
+
+ for (int i = 0; i < h; i++) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(src + 64));
+ sum_ref0 = _mm512_add_epi32(
+ sum_ref0,
+ _mm512_add_epi32(
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref0), s0),
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)(ref0 + 64)),
+ s1)));
+ sum_ref1 = _mm512_add_epi32(
+ sum_ref1,
+ _mm512_add_epi32(
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref1), s0),
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)(ref1 + 64)),
+ s1)));
+ sum_ref2 = _mm512_add_epi32(
+ sum_ref2,
+ _mm512_add_epi32(
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref2), s0),
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)(ref2 + 64)),
+ s1)));
+ sum_ref3 = _mm512_add_epi32(
+ sum_ref3,
+ _mm512_add_epi32(
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref3), s0),
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)(ref3 + 64)),
+ s1)));
+ src += src_stride;
+ ref0 += ref_stride;
+ ref1 += ref_stride;
+ ref2 += ref_stride;
+ ref3 += ref_stride;
+ }
+ aggregate_and_store_sum_zmm(res, sum_ref0, sum_ref1, sum_ref2, sum_ref3);
+}
+
+static AOM_FORCE_INLINE void sad128xhx3d_avx512(int h, const uint8_t *src,
+ int src_stride,
+ const uint8_t *const ref[4],
+ int ref_stride, uint32_t *res) {
+ const uint8_t *ref0 = ref[0];
+ const uint8_t *ref1 = ref[1];
+ const uint8_t *ref2 = ref[2];
+ __m512i sum_ref0 = _mm512_setzero_si512();
+ __m512i sum_ref1 = _mm512_setzero_si512();
+ __m512i sum_ref2 = _mm512_setzero_si512();
+
+ for (int i = 0; i < h; i++) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(src + 64));
+ sum_ref0 = _mm512_add_epi32(
+ sum_ref0,
+ _mm512_add_epi32(
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref0), s0),
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)(ref0 + 64)),
+ s1)));
+ sum_ref1 = _mm512_add_epi32(
+ sum_ref1,
+ _mm512_add_epi32(
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref1), s0),
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)(ref1 + 64)),
+ s1)));
+ sum_ref2 = _mm512_add_epi32(
+ sum_ref2,
+ _mm512_add_epi32(
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)ref2), s0),
+ _mm512_sad_epu8(_mm512_loadu_si512((const __m512i *)(ref2 + 64)),
+ s1)));
+ src += src_stride;
+ ref0 += ref_stride;
+ ref1 += ref_stride;
+ ref2 += ref_stride;
+ }
+ aggregate_and_store_sum_3d_zmm(res, sum_ref0, sum_ref1, sum_ref2);
+}
+
+#define SAD64_AVX512(h) \
+ unsigned int aom_sad64x##h##_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *ref_ptr, \
+ int ref_stride) { \
+ return sad64xh_avx512(src_ptr, src_stride, ref_ptr, ref_stride, h); \
+ } \
+ unsigned int aom_sad_skip_64x##h##_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
+ int ref_stride) { \
+ return 2 * sad64xh_avx512(src_ptr, src_stride * 2, ref_ptr, \
+ ref_stride * 2, (h) / 2); \
+ } \
+ unsigned int aom_sad64x##h##_avg_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
+ int ref_stride, const uint8_t *second_pred) { \
+ return sad64xh_avg_avx512(src_ptr, src_stride, ref_ptr, ref_stride, h, \
+ second_pred); \
+ } \
+ void aom_sad64x##h##x4d_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad64xhx4d_avx512(h, src_ptr, src_stride, ref_ptr, ref_stride, sad_array); \
+ } \
+ void aom_sad_skip_64x##h##x4d_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad64xhx4d_avx512((h) >> 1, src_ptr, src_stride << 1, ref_ptr, \
+ ref_stride << 1, sad_array); \
+ sad_array[0] <<= 1; \
+ sad_array[1] <<= 1; \
+ sad_array[2] <<= 1; \
+ sad_array[3] <<= 1; \
+ } \
+ void aom_sad64x##h##x3d_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad64xhx3d_avx512(h, src_ptr, src_stride, ref_ptr, ref_stride, sad_array); \
+ }
+
+#define SAD128_AVX512(h) \
+ unsigned int aom_sad128x##h##_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *ref_ptr, \
+ int ref_stride) { \
+ return sad128xh_avx512(src_ptr, src_stride, ref_ptr, ref_stride, h); \
+ } \
+ unsigned int aom_sad_skip_128x##h##_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
+ int ref_stride) { \
+ return 2 * sad128xh_avx512(src_ptr, src_stride * 2, ref_ptr, \
+ ref_stride * 2, (h) / 2); \
+ } \
+ unsigned int aom_sad128x##h##_avg_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
+ int ref_stride, const uint8_t *second_pred) { \
+ return sad128xh_avg_avx512(src_ptr, src_stride, ref_ptr, ref_stride, h, \
+ second_pred); \
+ } \
+ void aom_sad128x##h##x4d_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad128xhx4d_avx512(h, src_ptr, src_stride, ref_ptr, ref_stride, \
+ sad_array); \
+ } \
+ void aom_sad_skip_128x##h##x4d_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad128xhx4d_avx512((h) >> 1, src_ptr, src_stride << 1, ref_ptr, \
+ ref_stride << 1, sad_array); \
+ sad_array[0] <<= 1; \
+ sad_array[1] <<= 1; \
+ sad_array[2] <<= 1; \
+ sad_array[3] <<= 1; \
+ } \
+ void aom_sad128x##h##x3d_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad128xhx3d_avx512(h, src_ptr, src_stride, ref_ptr, ref_stride, \
+ sad_array); \
+ }
+
+SAD128_AVX512(128)
+SAD128_AVX512(64)
+SAD64_AVX512(128)
+SAD64_AVX512(64)
+SAD64_AVX512(32)
+#endif // !CONFIG_HIGHWAY
+
+#if !CONFIG_REALTIME_ONLY
+// 64x16 is not provided by Highway, so always compile it under AVX-512.
+unsigned int aom_sad64x16_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *ref_ptr, int ref_stride) {
+ return sad64xh_avx512(src_ptr, src_stride, ref_ptr, ref_stride, 16);
+}
+
+unsigned int aom_sad_skip_64x16_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *ref_ptr, int ref_stride) {
+ return 2 *
+ sad64xh_avx512(src_ptr, src_stride * 2, ref_ptr, ref_stride * 2, 8);
+}
+
+unsigned int aom_sad64x16_avg_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *ref_ptr, int ref_stride,
+ const uint8_t *second_pred) {
+ return sad64xh_avg_avx512(src_ptr, src_stride, ref_ptr, ref_stride, 16,
+ second_pred);
+}
+
+void aom_sad64x16x4d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4], int ref_stride,
+ uint32_t sad_array[4]) {
+ sad64xhx4d_avx512(16, src_ptr, src_stride, ref_ptr, ref_stride, sad_array);
+}
+
+void aom_sad_skip_64x16x4d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4],
+ int ref_stride, uint32_t sad_array[4]) {
+ sad64xhx4d_avx512(8, src_ptr, src_stride << 1, ref_ptr, ref_stride << 1,
+ sad_array);
+ sad_array[0] <<= 1;
+ sad_array[1] <<= 1;
+ sad_array[2] <<= 1;
+ sad_array[3] <<= 1;
+}
+
+void aom_sad64x16x3d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4], int ref_stride,
+ uint32_t sad_array[4]) {
+ sad64xhx3d_avx512(16, src_ptr, src_stride, ref_ptr, ref_stride, sad_array);
+}
+#endif // !CONFIG_REALTIME_ONLY
+
+// 32xh blocks: pack 2 rows (64 bytes) per 512-bit ZMM register.
+static AOM_FORCE_INLINE __m512i loadu2_256_zmm(const uint8_t *hi,
+ const uint8_t *lo) {
+ return _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm256_loadu_si256((const __m256i *)lo)),
+ _mm256_loadu_si256((const __m256i *)hi), 1);
+}
+
+static AOM_FORCE_INLINE unsigned int sad32xh_avx512(const uint8_t *src_ptr,
+ int src_stride,
+ const uint8_t *ref_ptr,
+ int ref_stride, int h) {
+ __m512i sum_sad = _mm512_setzero_si512();
+ for (int i = 0; i < h; i += 2) {
+ const __m512i s = loadu2_256_zmm(src_ptr + src_stride, src_ptr);
+ const __m512i r = loadu2_256_zmm(ref_ptr + ref_stride, ref_ptr);
+ sum_sad = _mm512_add_epi32(sum_sad, _mm512_sad_epu8(r, s));
+ src_ptr += src_stride * 2;
+ ref_ptr += ref_stride * 2;
+ }
+ return hsum_sad_zmm(sum_sad);
+}
+
+static AOM_FORCE_INLINE unsigned int sad32xh_avg_avx512(
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr,
+ int ref_stride, int h, const uint8_t *second_pred) {
+ __m512i sum_sad = _mm512_setzero_si512();
+ for (int i = 0; i < h; i += 2) {
+ const __m512i s = loadu2_256_zmm(src_ptr + src_stride, src_ptr);
+ const __m512i r =
+ _mm512_avg_epu8(loadu2_256_zmm(ref_ptr + ref_stride, ref_ptr),
+ _mm512_loadu_si512((const __m512i *)second_pred));
+ sum_sad = _mm512_add_epi32(sum_sad, _mm512_sad_epu8(r, s));
+ src_ptr += src_stride * 2;
+ ref_ptr += ref_stride * 2;
+ second_pred += 64;
+ }
+ return hsum_sad_zmm(sum_sad);
+}
+
+static AOM_FORCE_INLINE void sad32xhx4d_avx512(int h, const uint8_t *src,
+ int src_stride,
+ const uint8_t *const ref[4],
+ int ref_stride, uint32_t *res) {
+ const uint8_t *ref0 = ref[0];
+ const uint8_t *ref1 = ref[1];
+ const uint8_t *ref2 = ref[2];
+ const uint8_t *ref3 = ref[3];
+ __m512i sum_ref0 = _mm512_setzero_si512();
+ __m512i sum_ref1 = _mm512_setzero_si512();
+ __m512i sum_ref2 = _mm512_setzero_si512();
+ __m512i sum_ref3 = _mm512_setzero_si512();
+
+ for (int i = 0; i < h; i += 2) {
+ const __m512i s = loadu2_256_zmm(src + src_stride, src);
+ const __m512i r0 = loadu2_256_zmm(ref0 + ref_stride, ref0);
+ const __m512i r1 = loadu2_256_zmm(ref1 + ref_stride, ref1);
+ const __m512i r2 = loadu2_256_zmm(ref2 + ref_stride, ref2);
+ const __m512i r3 = loadu2_256_zmm(ref3 + ref_stride, ref3);
+ sum_ref0 = _mm512_add_epi32(sum_ref0, _mm512_sad_epu8(r0, s));
+ sum_ref1 = _mm512_add_epi32(sum_ref1, _mm512_sad_epu8(r1, s));
+ sum_ref2 = _mm512_add_epi32(sum_ref2, _mm512_sad_epu8(r2, s));
+ sum_ref3 = _mm512_add_epi32(sum_ref3, _mm512_sad_epu8(r3, s));
+ src += src_stride * 2;
+ ref0 += ref_stride * 2;
+ ref1 += ref_stride * 2;
+ ref2 += ref_stride * 2;
+ ref3 += ref_stride * 2;
+ }
+ aggregate_and_store_sum_zmm(res, sum_ref0, sum_ref1, sum_ref2, sum_ref3);
+}
+
+static AOM_FORCE_INLINE void sad32xhx3d_avx512(int h, const uint8_t *src,
+ int src_stride,
+ const uint8_t *const ref[4],
+ int ref_stride, uint32_t *res) {
+ const uint8_t *ref0 = ref[0];
+ const uint8_t *ref1 = ref[1];
+ const uint8_t *ref2 = ref[2];
+ __m512i sum_ref0 = _mm512_setzero_si512();
+ __m512i sum_ref1 = _mm512_setzero_si512();
+ __m512i sum_ref2 = _mm512_setzero_si512();
+
+ for (int i = 0; i < h; i += 2) {
+ const __m512i s = loadu2_256_zmm(src + src_stride, src);
+ const __m512i r0 = loadu2_256_zmm(ref0 + ref_stride, ref0);
+ const __m512i r1 = loadu2_256_zmm(ref1 + ref_stride, ref1);
+ const __m512i r2 = loadu2_256_zmm(ref2 + ref_stride, ref2);
+ sum_ref0 = _mm512_add_epi32(sum_ref0, _mm512_sad_epu8(r0, s));
+ sum_ref1 = _mm512_add_epi32(sum_ref1, _mm512_sad_epu8(r1, s));
+ sum_ref2 = _mm512_add_epi32(sum_ref2, _mm512_sad_epu8(r2, s));
+ src += src_stride * 2;
+ ref0 += ref_stride * 2;
+ ref1 += ref_stride * 2;
+ ref2 += ref_stride * 2;
+ }
+ aggregate_and_store_sum_3d_zmm(res, sum_ref0, sum_ref1, sum_ref2);
+}
+
+#define SAD32_AVX512(h) \
+ unsigned int aom_sad32x##h##_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *ref_ptr, \
+ int ref_stride) { \
+ return sad32xh_avx512(src_ptr, src_stride, ref_ptr, ref_stride, h); \
+ } \
+ unsigned int aom_sad_skip_32x##h##_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
+ int ref_stride) { \
+ return 2 * sad32xh_avx512(src_ptr, src_stride * 2, ref_ptr, \
+ ref_stride * 2, (h) / 2); \
+ } \
+ unsigned int aom_sad32x##h##_avg_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
+ int ref_stride, const uint8_t *second_pred) { \
+ return sad32xh_avg_avx512(src_ptr, src_stride, ref_ptr, ref_stride, h, \
+ second_pred); \
+ } \
+ void aom_sad32x##h##x4d_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad32xhx4d_avx512(h, src_ptr, src_stride, ref_ptr, ref_stride, sad_array); \
+ } \
+ void aom_sad_skip_32x##h##x4d_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad32xhx4d_avx512((h) >> 1, src_ptr, src_stride << 1, ref_ptr, \
+ ref_stride << 1, sad_array); \
+ sad_array[0] <<= 1; \
+ sad_array[1] <<= 1; \
+ sad_array[2] <<= 1; \
+ sad_array[3] <<= 1; \
+ } \
+ void aom_sad32x##h##x3d_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad32xhx3d_avx512(h, src_ptr, src_stride, ref_ptr, ref_stride, sad_array); \
+ }
+
+SAD32_AVX512(64)
+SAD32_AVX512(32)
+SAD32_AVX512(16)
+
+#if !CONFIG_REALTIME_ONLY
+unsigned int aom_sad32x8_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *ref_ptr, int ref_stride) {
+ return sad32xh_avx512(src_ptr, src_stride, ref_ptr, ref_stride, 8);
+}
+
+unsigned int aom_sad32x8_avg_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *ref_ptr, int ref_stride,
+ const uint8_t *second_pred) {
+ return sad32xh_avg_avx512(src_ptr, src_stride, ref_ptr, ref_stride, 8,
+ second_pred);
+}
+
+void aom_sad32x8x4d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4], int ref_stride,
+ uint32_t sad_array[4]) {
+ sad32xhx4d_avx512(8, src_ptr, src_stride, ref_ptr, ref_stride, sad_array);
+}
+
+void aom_sad32x8x3d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4], int ref_stride,
+ uint32_t sad_array[4]) {
+ sad32xhx3d_avx512(8, src_ptr, src_stride, ref_ptr, ref_stride, sad_array);
+}
+#endif // !CONFIG_REALTIME_ONLY
+
+// 16xh blocks: pack 4 rows (64 bytes) per 512-bit ZMM register.
+static AOM_FORCE_INLINE __m512i loadu4_128_zmm(const uint8_t *p, int stride) {
+ const __m256i lo = yy_loadu2_128(p + stride, p);
+ const __m256i hi = yy_loadu2_128(p + stride * 3, p + stride * 2);
+ return _mm512_inserti64x4(_mm512_castsi256_si512(lo), hi, 1);
+}
+
+static AOM_FORCE_INLINE unsigned int sad16xh_avx512(const uint8_t *src_ptr,
+ int src_stride,
+ const uint8_t *ref_ptr,
+ int ref_stride, int h) {
+ __m512i sum_sad = _mm512_setzero_si512();
+ for (int i = 0; i < h; i += 4) {
+ const __m512i s = loadu4_128_zmm(src_ptr, src_stride);
+ const __m512i r = loadu4_128_zmm(ref_ptr, ref_stride);
+ sum_sad = _mm512_add_epi32(sum_sad, _mm512_sad_epu8(r, s));
+ src_ptr += src_stride * 4;
+ ref_ptr += ref_stride * 4;
+ }
+ return hsum_sad_zmm(sum_sad);
+}
+
+static AOM_FORCE_INLINE unsigned int sad16xh_avg_avx512(
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr,
+ int ref_stride, int h, const uint8_t *second_pred) {
+ __m512i sum_sad = _mm512_setzero_si512();
+ for (int i = 0; i < h; i += 4) {
+ const __m512i s = loadu4_128_zmm(src_ptr, src_stride);
+ const __m512i r =
+ _mm512_avg_epu8(loadu4_128_zmm(ref_ptr, ref_stride),
+ _mm512_loadu_si512((const __m512i *)second_pred));
+ sum_sad = _mm512_add_epi32(sum_sad, _mm512_sad_epu8(r, s));
+ src_ptr += src_stride * 4;
+ ref_ptr += ref_stride * 4;
+ second_pred += 64;
+ }
+ return hsum_sad_zmm(sum_sad);
+}
+
+static AOM_FORCE_INLINE void sad16xhx4d_avx512(int h, const uint8_t *src,
+ int src_stride,
+ const uint8_t *const ref[4],
+ int ref_stride, uint32_t *res) {
+ const uint8_t *ref0 = ref[0];
+ const uint8_t *ref1 = ref[1];
+ const uint8_t *ref2 = ref[2];
+ const uint8_t *ref3 = ref[3];
+ __m512i sum_ref0 = _mm512_setzero_si512();
+ __m512i sum_ref1 = _mm512_setzero_si512();
+ __m512i sum_ref2 = _mm512_setzero_si512();
+ __m512i sum_ref3 = _mm512_setzero_si512();
+
+ for (int i = 0; i < h; i += 4) {
+ const __m512i s = loadu4_128_zmm(src, src_stride);
+ const __m512i r0 = loadu4_128_zmm(ref0, ref_stride);
+ const __m512i r1 = loadu4_128_zmm(ref1, ref_stride);
+ const __m512i r2 = loadu4_128_zmm(ref2, ref_stride);
+ const __m512i r3 = loadu4_128_zmm(ref3, ref_stride);
+ sum_ref0 = _mm512_add_epi32(sum_ref0, _mm512_sad_epu8(r0, s));
+ sum_ref1 = _mm512_add_epi32(sum_ref1, _mm512_sad_epu8(r1, s));
+ sum_ref2 = _mm512_add_epi32(sum_ref2, _mm512_sad_epu8(r2, s));
+ sum_ref3 = _mm512_add_epi32(sum_ref3, _mm512_sad_epu8(r3, s));
+ src += src_stride * 4;
+ ref0 += ref_stride * 4;
+ ref1 += ref_stride * 4;
+ ref2 += ref_stride * 4;
+ ref3 += ref_stride * 4;
+ }
+ aggregate_and_store_sum_zmm(res, sum_ref0, sum_ref1, sum_ref2, sum_ref3);
+}
+
+static AOM_FORCE_INLINE void sad16xhx3d_avx512(int h, const uint8_t *src,
+ int src_stride,
+ const uint8_t *const ref[4],
+ int ref_stride, uint32_t *res) {
+ const uint8_t *ref0 = ref[0];
+ const uint8_t *ref1 = ref[1];
+ const uint8_t *ref2 = ref[2];
+ __m512i sum_ref0 = _mm512_setzero_si512();
+ __m512i sum_ref1 = _mm512_setzero_si512();
+ __m512i sum_ref2 = _mm512_setzero_si512();
+
+ for (int i = 0; i < h; i += 4) {
+ const __m512i s = loadu4_128_zmm(src, src_stride);
+ const __m512i r0 = loadu4_128_zmm(ref0, ref_stride);
+ const __m512i r1 = loadu4_128_zmm(ref1, ref_stride);
+ const __m512i r2 = loadu4_128_zmm(ref2, ref_stride);
+ sum_ref0 = _mm512_add_epi32(sum_ref0, _mm512_sad_epu8(r0, s));
+ sum_ref1 = _mm512_add_epi32(sum_ref1, _mm512_sad_epu8(r1, s));
+ sum_ref2 = _mm512_add_epi32(sum_ref2, _mm512_sad_epu8(r2, s));
+ src += src_stride * 4;
+ ref0 += ref_stride * 4;
+ ref1 += ref_stride * 4;
+ ref2 += ref_stride * 4;
+ }
+ aggregate_and_store_sum_3d_zmm(res, sum_ref0, sum_ref1, sum_ref2);
+}
+
+#define SAD16_AVX512(h) \
+ unsigned int aom_sad16x##h##_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *ref_ptr, \
+ int ref_stride) { \
+ return sad16xh_avx512(src_ptr, src_stride, ref_ptr, ref_stride, h); \
+ } \
+ unsigned int aom_sad_skip_16x##h##_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
+ int ref_stride) { \
+ return 2 * sad16xh_avx512(src_ptr, src_stride * 2, ref_ptr, \
+ ref_stride * 2, (h) / 2); \
+ } \
+ unsigned int aom_sad16x##h##_avg_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
+ int ref_stride, const uint8_t *second_pred) { \
+ return sad16xh_avg_avx512(src_ptr, src_stride, ref_ptr, ref_stride, h, \
+ second_pred); \
+ } \
+ void aom_sad16x##h##x4d_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad16xhx4d_avx512(h, src_ptr, src_stride, ref_ptr, ref_stride, sad_array); \
+ } \
+ void aom_sad_skip_16x##h##x4d_avx512( \
+ const uint8_t *src_ptr, int src_stride, const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad16xhx4d_avx512((h) >> 1, src_ptr, src_stride << 1, ref_ptr, \
+ ref_stride << 1, sad_array); \
+ sad_array[0] <<= 1; \
+ sad_array[1] <<= 1; \
+ sad_array[2] <<= 1; \
+ sad_array[3] <<= 1; \
+ } \
+ void aom_sad16x##h##x3d_avx512(const uint8_t *src_ptr, int src_stride, \
+ const uint8_t *const ref_ptr[4], \
+ int ref_stride, uint32_t sad_array[4]) { \
+ sad16xhx3d_avx512(h, src_ptr, src_stride, ref_ptr, ref_stride, sad_array); \
+ }
+
+SAD16_AVX512(32)
+SAD16_AVX512(16)
+
+unsigned int aom_sad16x8_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *ref_ptr, int ref_stride) {
+ return sad16xh_avx512(src_ptr, src_stride, ref_ptr, ref_stride, 8);
+}
+
+unsigned int aom_sad16x8_avg_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *ref_ptr, int ref_stride,
+ const uint8_t *second_pred) {
+ return sad16xh_avg_avx512(src_ptr, src_stride, ref_ptr, ref_stride, 8,
+ second_pred);
+}
+
+void aom_sad16x8x4d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4], int ref_stride,
+ uint32_t sad_array[4]) {
+ sad16xhx4d_avx512(8, src_ptr, src_stride, ref_ptr, ref_stride, sad_array);
+}
+
+void aom_sad16x8x3d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4], int ref_stride,
+ uint32_t sad_array[4]) {
+ sad16xhx3d_avx512(8, src_ptr, src_stride, ref_ptr, ref_stride, sad_array);
+}
+
+#if !CONFIG_REALTIME_ONLY
+SAD16_AVX512(64)
+
+unsigned int aom_sad16x4_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *ref_ptr, int ref_stride) {
+ return sad16xh_avx512(src_ptr, src_stride, ref_ptr, ref_stride, 4);
+}
+
+void aom_sad16x4x4d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4], int ref_stride,
+ uint32_t sad_array[4]) {
+ sad16xhx4d_avx512(4, src_ptr, src_stride, ref_ptr, ref_stride, sad_array);
+}
+
+void aom_sad16x4x3d_avx512(const uint8_t *src_ptr, int src_stride,
+ const uint8_t *const ref_ptr[4], int ref_stride,
+ uint32_t sad_array[4]) {
+ sad16xhx3d_avx512(4, src_ptr, src_stride, ref_ptr, ref_stride, sad_array);
+}
+#endif // !CONFIG_REALTIME_ONLY
diff --git a/aom_dsp/x86/subtract_avx512.c b/aom_dsp/x86/subtract_avx512.c
new file mode 100644
index 0000000000..43c0c47950
--- /dev/null
+++ b/aom_dsp/x86/subtract_avx512.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <assert.h>
+#include <immintrin.h>
+
+#include "config/aom_config.h"
+#include "config/aom_dsp_rtcd.h"
+#include "aom/aom_integer.h"
+
+static inline void subtract32_avx512(int16_t *diff_ptr, const uint8_t *src_ptr,
+ const uint8_t *pred_ptr) {
+ const __m256i s = _mm256_loadu_si256((const __m256i *)src_ptr);
+ const __m256i p = _mm256_loadu_si256((const __m256i *)pred_ptr);
+ const __m512i d =
+ _mm512_sub_epi16(_mm512_cvtepu8_epi16(s), _mm512_cvtepu8_epi16(p));
+ _mm512_storeu_si512((__m512i *)diff_ptr, d);
+}
+
+static inline void subtract_block_4xn_avx512(
+ int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
+ int32_t j = 0;
+ for (; j + 3 < rows; j += 4) {
+ const __m128i s = _mm_setr_epi32(
+ *(const int32_t *)(src_ptr), *(const int32_t *)(src_ptr + src_stride),
+ *(const int32_t *)(src_ptr + src_stride * 2),
+ *(const int32_t *)(src_ptr + src_stride * 3));
+ const __m128i p =
+ _mm_setr_epi32(*(const int32_t *)(pred_ptr),
+ *(const int32_t *)(pred_ptr + pred_stride),
+ *(const int32_t *)(pred_ptr + pred_stride * 2),
+ *(const int32_t *)(pred_ptr + pred_stride * 3));
+ const __m256i d =
+ _mm256_sub_epi16(_mm256_cvtepu8_epi16(s), _mm256_cvtepu8_epi16(p));
+ const __m128i d_lo = _mm256_castsi256_si128(d);
+ const __m128i d_hi = _mm256_extracti128_si256(d, 1);
+ _mm_storel_epi64((__m128i *)(diff_ptr), d_lo);
+ _mm_storeh_pi((__m64 *)(diff_ptr + diff_stride), _mm_castsi128_ps(d_lo));
+ _mm_storel_epi64((__m128i *)(diff_ptr + diff_stride * 2), d_hi);
+ _mm_storeh_pi((__m64 *)(diff_ptr + diff_stride * 3),
+ _mm_castsi128_ps(d_hi));
+ src_ptr += src_stride * 4;
+ pred_ptr += pred_stride * 4;
+ diff_ptr += diff_stride * 4;
+ }
+ for (; j < rows; j += 2) {
+ const __m128i s =
+ _mm_setr_epi32(*(const int32_t *)(src_ptr),
+ *(const int32_t *)(src_ptr + src_stride), 0, 0);
+ const __m128i p =
+ _mm_setr_epi32(*(const int32_t *)(pred_ptr),
+ *(const int32_t *)(pred_ptr + pred_stride), 0, 0);
+ const __m128i d = _mm_sub_epi16(_mm_cvtepu8_epi16(s), _mm_cvtepu8_epi16(p));
+ _mm_storel_epi64((__m128i *)(diff_ptr), d);
+ _mm_storeh_pi((__m64 *)(diff_ptr + diff_stride), _mm_castsi128_ps(d));
+ src_ptr += src_stride * 2;
+ pred_ptr += pred_stride * 2;
+ diff_ptr += diff_stride * 2;
+ }
+}
+
+static inline void subtract_block_8xn_avx512(
+ int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
+ int32_t j = 0;
+ for (; j + 3 < rows; j += 4) {
+ const __m128i s01 = _mm_unpacklo_epi64(
+ _mm_loadl_epi64((const __m128i *)(src_ptr)),
+ _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride)));
+ const __m128i s23 = _mm_unpacklo_epi64(
+ _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride * 2)),
+ _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride * 3)));
+ const __m128i p01 = _mm_unpacklo_epi64(
+ _mm_loadl_epi64((const __m128i *)(pred_ptr)),
+ _mm_loadl_epi64((const __m128i *)(pred_ptr + pred_stride)));
+ const __m128i p23 = _mm_unpacklo_epi64(
+ _mm_loadl_epi64((const __m128i *)(pred_ptr + pred_stride * 2)),
+ _mm_loadl_epi64((const __m128i *)(pred_ptr + pred_stride * 3)));
+ const __m256i s =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(s01), s23, 1);
+ const __m256i p =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(p01), p23, 1);
+ const __m512i d =
+ _mm512_sub_epi16(_mm512_cvtepu8_epi16(s), _mm512_cvtepu8_epi16(p));
+ _mm_storeu_si128((__m128i *)(diff_ptr), _mm512_castsi512_si128(d));
+ _mm_storeu_si128((__m128i *)(diff_ptr + diff_stride),
+ _mm512_extracti32x4_epi32(d, 1));
+ _mm_storeu_si128((__m128i *)(diff_ptr + diff_stride * 2),
+ _mm512_extracti32x4_epi32(d, 2));
+ _mm_storeu_si128((__m128i *)(diff_ptr + diff_stride * 3),
+ _mm512_extracti32x4_epi32(d, 3));
+ src_ptr += src_stride * 4;
+ pred_ptr += pred_stride * 4;
+ diff_ptr += diff_stride * 4;
+ }
+ for (; j < rows; j += 2) {
+ const __m128i s = _mm_unpacklo_epi64(
+ _mm_loadl_epi64((const __m128i *)(src_ptr)),
+ _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride)));
+ const __m128i p = _mm_unpacklo_epi64(
+ _mm_loadl_epi64((const __m128i *)(pred_ptr)),
+ _mm_loadl_epi64((const __m128i *)(pred_ptr + pred_stride)));
+ const __m256i d =
+ _mm256_sub_epi16(_mm256_cvtepu8_epi16(s), _mm256_cvtepu8_epi16(p));
+ _mm_storeu_si128((__m128i *)(diff_ptr), _mm256_castsi256_si128(d));
+ _mm_storeu_si128((__m128i *)(diff_ptr + diff_stride),
+ _mm256_extracti128_si256(d, 1));
+ src_ptr += src_stride * 2;
+ pred_ptr += pred_stride * 2;
+ diff_ptr += diff_stride * 2;
+ }
+}
+
+static inline void subtract_block_16xn_avx512(
+ int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
+ for (int32_t j = 0; j < rows; j += 2) {
+ const __m128i s0 = _mm_loadu_si128((const __m128i *)(src_ptr));
+ const __m128i p0 = _mm_loadu_si128((const __m128i *)(pred_ptr));
+ const __m128i s1 = _mm_loadu_si128((const __m128i *)(src_ptr + src_stride));
+ const __m128i p1 =
+ _mm_loadu_si128((const __m128i *)(pred_ptr + pred_stride));
+ const __m256i s =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(s0), s1, 1);
+ const __m256i p =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(p0), p1, 1);
+ const __m512i d =
+ _mm512_sub_epi16(_mm512_cvtepu8_epi16(s), _mm512_cvtepu8_epi16(p));
+ _mm256_storeu_si256((__m256i *)(diff_ptr), _mm512_castsi512_si256(d));
+ _mm256_storeu_si256((__m256i *)(diff_ptr + diff_stride),
+ _mm512_extracti64x4_epi64(d, 1));
+ src_ptr += src_stride * 2;
+ pred_ptr += pred_stride * 2;
+ diff_ptr += diff_stride * 2;
+ }
+}
+
+static inline void subtract_block_32xn_avx512(
+ int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
+ for (int32_t j = 0; j < rows; j += 2) {
+ subtract32_avx512(diff_ptr, src_ptr, pred_ptr);
+ subtract32_avx512(diff_ptr + diff_stride, src_ptr + src_stride,
+ pred_ptr + pred_stride);
+ src_ptr += src_stride * 2;
+ pred_ptr += pred_stride * 2;
+ diff_ptr += diff_stride * 2;
+ }
+}
+
+static inline void subtract_block_64xn_avx512(
+ int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
+ for (int32_t j = 0; j < rows; ++j) {
+ subtract32_avx512(diff_ptr, src_ptr, pred_ptr);
+ subtract32_avx512(diff_ptr + 32, src_ptr + 32, pred_ptr + 32);
+ src_ptr += src_stride;
+ pred_ptr += pred_stride;
+ diff_ptr += diff_stride;
+ }
+}
+
+static inline void subtract_block_128xn_avx512(
+ int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) {
+ for (int32_t j = 0; j < rows; ++j) {
+ subtract32_avx512(diff_ptr, src_ptr, pred_ptr);
+ subtract32_avx512(diff_ptr + 32, src_ptr + 32, pred_ptr + 32);
+ subtract32_avx512(diff_ptr + 64, src_ptr + 64, pred_ptr + 64);
+ subtract32_avx512(diff_ptr + 96, src_ptr + 96, pred_ptr + 96);
+ src_ptr += src_stride;
+ pred_ptr += pred_stride;
+ diff_ptr += diff_stride;
+ }
+}
+
+void aom_subtract_block_avx512(int rows, int cols, int16_t *diff_ptr,
+ ptrdiff_t diff_stride, const uint8_t *src_ptr,
+ ptrdiff_t src_stride, const uint8_t *pred_ptr,
+ ptrdiff_t pred_stride) {
+ switch (cols) {
+ case 4:
+ subtract_block_4xn_avx512(rows, diff_ptr, diff_stride, src_ptr,
+ src_stride, pred_ptr, pred_stride);
+ break;
+ case 8:
+ subtract_block_8xn_avx512(rows, diff_ptr, diff_stride, src_ptr,
+ src_stride, pred_ptr, pred_stride);
+ break;
+ case 16:
+ subtract_block_16xn_avx512(rows, diff_ptr, diff_stride, src_ptr,
+ src_stride, pred_ptr, pred_stride);
+ break;
+ case 32:
+ subtract_block_32xn_avx512(rows, diff_ptr, diff_stride, src_ptr,
+ src_stride, pred_ptr, pred_stride);
+ break;
+ case 64:
+ subtract_block_64xn_avx512(rows, diff_ptr, diff_stride, src_ptr,
+ src_stride, pred_ptr, pred_stride);
+ break;
+ case 128:
+ subtract_block_128xn_avx512(rows, diff_ptr, diff_stride, src_ptr,
+ src_stride, pred_ptr, pred_stride);
+ break;
+ default:
+#if HAVE_X86_ASM
+ aom_subtract_block_sse2(rows, cols, diff_ptr, diff_stride, src_ptr,
+ src_stride, pred_ptr, pred_stride);
+#else
+ aom_subtract_block_c(rows, cols, diff_ptr, diff_stride, src_ptr,
+ src_stride, pred_ptr, pred_stride);
+#endif
+ break;
+ }
+}
diff --git a/aom_dsp/x86/variance_avx512.c b/aom_dsp/x86/variance_avx512.c
new file mode 100644
index 0000000000..15f900959e
--- /dev/null
+++ b/aom_dsp/x86/variance_avx512.c
@@ -0,0 +1,1783 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <assert.h>
+#include <immintrin.h>
+
+#include "config/aom_config.h"
+#include "config/aom_dsp_rtcd.h"
+
+#include "aom/aom_integer.h"
+#include "aom_dsp/aom_dsp_common.h"
+#include "aom_dsp/aom_filter.h"
+#include "aom_dsp/blend.h"
+#include "aom_dsp/x86/masked_sad_intrin_ssse3.h"
+#include "aom_dsp/x86/obmc_intrinsic_sse4.h"
+#include "aom_dsp/x86/obmc_intrinsic_ssse3.h"
+#include "aom_dsp/x86/synonyms.h"
+#include "aom_dsp/x86/synonyms_avx2.h"
+#include "aom_dsp/x86/variance_impl_ssse3.h"
+#include "aom_ports/mem.h"
+
+static AOM_FORCE_INLINE int32_t hsum_epi32_zmm(__m512i v) {
+ const __m256i v256 = _mm256_add_epi32(_mm512_castsi512_si256(v),
+ _mm512_extracti64x4_epi64(v, 1));
+ const __m128i v128 = _mm_add_epi32(_mm256_castsi256_si128(v256),
+ _mm256_extracti128_si256(v256, 1));
+ const __m128i s1 = _mm_hadd_epi32(v128, v128);
+ const __m128i s2 = _mm_hadd_epi32(s1, s1);
+ return _mm_cvtsi128_si32(s2);
+}
+
+static AOM_FORCE_INLINE int64_t hsum_epi64_zmm(__m512i v) {
+ const __m256i v256 = _mm256_add_epi64(_mm512_castsi512_si256(v),
+ _mm512_extracti64x4_epi64(v, 1));
+ const __m128i v128 = _mm_add_epi64(_mm256_castsi256_si128(v256),
+ _mm256_extracti128_si256(v256, 1));
+ const __m128i s = _mm_add_epi64(v128, _mm_srli_si128(v128, 8));
+ return _mm_cvtsi128_si64(s);
+}
+
+static AOM_FORCE_INLINE void variance_kernel_zmm(const __m512i src,
+ const __m512i ref,
+ __m512i *const sse,
+ __m512i *const sum) {
+ const __m512i adj_sub = _mm512_set1_epi16((int16_t)0xff01);
+ const __m512i s_lo = _mm512_unpacklo_epi8(src, ref);
+ const __m512i s_hi = _mm512_unpackhi_epi8(src, ref);
+ const __m512i diff_lo = _mm512_maddubs_epi16(s_lo, adj_sub);
+ const __m512i diff_hi = _mm512_maddubs_epi16(s_hi, adj_sub);
+
+ *sum = _mm512_add_epi16(*sum, _mm512_add_epi16(diff_lo, diff_hi));
+ *sse = _mm512_add_epi32(
+ *sse, _mm512_add_epi32(_mm512_madd_epi16(diff_lo, diff_lo),
+ _mm512_madd_epi16(diff_hi, diff_hi)));
+}
+
+static AOM_FORCE_INLINE int variance_final_from_16bit_sum_zmm(
+ __m512i vsse, __m512i vsum, unsigned int *const sse) {
+ const __m512i vsum32 = _mm512_madd_epi16(vsum, _mm512_set1_epi16(1));
+ const __m256i sse256 = _mm256_add_epi32(_mm512_castsi512_si256(vsse),
+ _mm512_extracti64x4_epi64(vsse, 1));
+ const __m256i sum256 = _mm256_add_epi32(_mm512_castsi512_si256(vsum32),
+ _mm512_extracti64x4_epi64(vsum32, 1));
+ const __m128i sse128 = _mm_add_epi32(_mm256_castsi256_si128(sse256),
+ _mm256_extracti128_si256(sse256, 1));
+ const __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum256),
+ _mm256_extracti128_si256(sum256, 1));
+ const __m128i sse_sum = _mm_hadd_epi32(sse128, sum128);
+ const __m128i res = _mm_hadd_epi32(sse_sum, sse_sum);
+ *sse = (unsigned int)_mm_cvtsi128_si32(res);
+ return _mm_extract_epi32(res, 1);
+}
+
+static AOM_FORCE_INLINE int variance_final_from_32bit_sum_zmm(
+ __m512i vsse, __m512i vsum32, unsigned int *const sse) {
+ const __m256i sse256 = _mm256_add_epi32(_mm512_castsi512_si256(vsse),
+ _mm512_extracti64x4_epi64(vsse, 1));
+ const __m256i sum256 = _mm256_add_epi32(_mm512_castsi512_si256(vsum32),
+ _mm512_extracti64x4_epi64(vsum32, 1));
+ const __m128i sse128 = _mm_add_epi32(_mm256_castsi256_si128(sse256),
+ _mm256_extracti128_si256(sse256, 1));
+ const __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum256),
+ _mm256_extracti128_si256(sum256, 1));
+ const __m128i sse_sum = _mm_hadd_epi32(sse128, sum128);
+ const __m128i res = _mm_hadd_epi32(sse_sum, sse_sum);
+ *sse = (unsigned int)_mm_cvtsi128_si32(res);
+ return _mm_extract_epi32(res, 1);
+}
+
+static AOM_FORCE_INLINE __m512i loadu2_256_zmm(const uint8_t *hi,
+ const uint8_t *lo) {
+ return _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm256_loadu_si256((const __m256i *)lo)),
+ _mm256_loadu_si256((const __m256i *)hi), 1);
+}
+
+static AOM_FORCE_INLINE __m512i loadu4_128_zmm(const uint8_t *p, int stride) {
+ const __m256i lo = yy_loadu2_128(p + stride, p);
+ const __m256i hi = yy_loadu2_128(p + stride * 3, p + stride * 2);
+ return _mm512_inserti64x4(_mm512_castsi256_si512(lo), hi, 1);
+}
+
+static AOM_FORCE_INLINE void variance16_avx512(const uint8_t *src,
+ int src_stride,
+ const uint8_t *ref,
+ int ref_stride, int h,
+ __m512i *vsse, __m512i *vsum) {
+ *vsum = _mm512_setzero_si512();
+ for (int i = 0; i < h; i += 4) {
+ const __m512i s = loadu4_128_zmm(src, src_stride);
+ const __m512i r = loadu4_128_zmm(ref, ref_stride);
+ variance_kernel_zmm(s, r, vsse, vsum);
+ src += 4 * src_stride;
+ ref += 4 * ref_stride;
+ }
+}
+
+static AOM_FORCE_INLINE void variance32_avx512(const uint8_t *src,
+ int src_stride,
+ const uint8_t *ref,
+ int ref_stride, int h,
+ __m512i *vsse, __m512i *vsum) {
+ *vsum = _mm512_setzero_si512();
+ for (int i = 0; i < h; i += 2) {
+ const __m512i s = loadu2_256_zmm(src + src_stride, src);
+ const __m512i r = loadu2_256_zmm(ref + ref_stride, ref);
+ variance_kernel_zmm(s, r, vsse, vsum);
+ src += 2 * src_stride;
+ ref += 2 * ref_stride;
+ }
+}
+
+static AOM_FORCE_INLINE void variance64_avx512(const uint8_t *src,
+ int src_stride,
+ const uint8_t *ref,
+ int ref_stride, int h,
+ __m512i *vsse, __m512i *vsum) {
+ *vsum = _mm512_setzero_si512();
+ for (int i = 0; i < h; i++) {
+ const __m512i s = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i r = _mm512_loadu_si512((const __m512i *)ref);
+ variance_kernel_zmm(s, r, vsse, vsum);
+ src += src_stride;
+ ref += ref_stride;
+ }
+}
+
+static AOM_FORCE_INLINE void variance128_avx512(const uint8_t *src,
+ int src_stride,
+ const uint8_t *ref,
+ int ref_stride, int h,
+ __m512i *vsse, __m512i *vsum) {
+ *vsum = _mm512_setzero_si512();
+ for (int i = 0; i < h; i++) {
+ variance_kernel_zmm(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)ref), vsse, vsum);
+ variance_kernel_zmm(_mm512_loadu_si512((const __m512i *)(src + 64)),
+ _mm512_loadu_si512((const __m512i *)(ref + 64)), vsse,
+ vsum);
+ src += src_stride;
+ ref += ref_stride;
+ }
+}
+
+// In a 512-bit ZMM register, vsum has 32 int16_t lanes.
+// Each 64-byte ZMM kernel adds 2 pixels per lane, so up to 64 rows * 64 cols
+// (= 4096 pixels, 128 pixels per lane, max 128*255 = 32640 <= 32767) fits in
+// 16-bit vsum without any inner chunk loop!
+#define AOM_VAR_NO_LOOP_AVX512(bw, bh, bits) \
+ unsigned int aom_variance##bw##x##bh##_avx512( \
+ const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \
+ unsigned int *sse) { \
+ __m512i vsse = _mm512_setzero_si512(); \
+ __m512i vsum; \
+ variance##bw##_avx512(src, src_stride, ref, ref_stride, bh, &vsse, &vsum); \
+ const int sum = variance_final_from_16bit_sum_zmm(vsse, vsum, sse); \
+ return *sse - (uint32_t)(((int64_t)sum * sum) >> (bits)); \
+ }
+
+AOM_VAR_NO_LOOP_AVX512(16, 8, 7)
+AOM_VAR_NO_LOOP_AVX512(16, 16, 8)
+AOM_VAR_NO_LOOP_AVX512(16, 32, 9)
+
+AOM_VAR_NO_LOOP_AVX512(32, 16, 9)
+AOM_VAR_NO_LOOP_AVX512(32, 32, 10)
+AOM_VAR_NO_LOOP_AVX512(32, 64, 11)
+
+AOM_VAR_NO_LOOP_AVX512(64, 32, 11)
+AOM_VAR_NO_LOOP_AVX512(64, 64, 12)
+
+#if !CONFIG_REALTIME_ONLY
+AOM_VAR_NO_LOOP_AVX512(16, 4, 6)
+AOM_VAR_NO_LOOP_AVX512(16, 64, 10)
+AOM_VAR_NO_LOOP_AVX512(32, 8, 8)
+AOM_VAR_NO_LOOP_AVX512(64, 16, 10)
+#endif // !CONFIG_REALTIME_ONLY
+
+#define AOM_VAR_LOOP_AVX512(bw, bh, bits, uh) \
+ unsigned int aom_variance##bw##x##bh##_avx512( \
+ const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \
+ unsigned int *sse) { \
+ __m512i vsse = _mm512_setzero_si512(); \
+ __m512i vsum32 = _mm512_setzero_si512(); \
+ const __m512i one = _mm512_set1_epi16(1); \
+ for (int i = 0; i < (bh) / (uh); i++) { \
+ __m512i vsum16; \
+ variance##bw##_avx512(src, src_stride, ref, ref_stride, uh, &vsse, \
+ &vsum16); \
+ vsum32 = _mm512_add_epi32(vsum32, _mm512_madd_epi16(vsum16, one)); \
+ src += (uh) * src_stride; \
+ ref += (uh) * ref_stride; \
+ } \
+ const int sum = variance_final_from_32bit_sum_zmm(vsse, vsum32, sse); \
+ return *sse - (unsigned int)(((int64_t)sum * sum) >> (bits)); \
+ }
+
+AOM_VAR_LOOP_AVX512(64, 128, 13, 64)
+AOM_VAR_LOOP_AVX512(128, 64, 13, 32)
+AOM_VAR_LOOP_AVX512(128, 128, 14, 32)
+
+unsigned int aom_mse16x16_avx512(const uint8_t *src, int src_stride,
+ const uint8_t *ref, int ref_stride,
+ unsigned int *sse) {
+ aom_variance16x16_avx512(src, src_stride, ref, ref_stride, sse);
+ return *sse;
+}
+
+// -----------------------------------------------------------------------------
+// 512-bit ZMM Subpixel Variance & Subpixel Avg Variance
+// -----------------------------------------------------------------------------
+
+static AOM_FORCE_INLINE __m512i bilinear_filter_zmm(int offset) {
+ const int f0 = 16 - 2 * offset;
+ const int f1 = 2 * offset;
+ return _mm512_set1_epi16((int16_t)(f0 | (f1 << 8)));
+}
+
+static AOM_FORCE_INLINE int sub_pixel_variance64xh_imp_avx512(
+ const uint8_t *src, int src_stride, int x_offset, int y_offset,
+ const uint8_t *dst, int dst_stride, int height, unsigned int *sse) {
+ __m512i sum_reg = _mm512_setzero_si512();
+ __m512i sse_reg = _mm512_setzero_si512();
+ const __m512i zero_reg = _mm512_setzero_si512();
+ const __m512i pw8 = _mm512_set1_epi16(8);
+
+#define ACCUM_DIFF_ZMM(exp_src_lo, exp_src_hi, dst_reg) \
+ do { \
+ const __m512i exp_dst_lo = _mm512_unpacklo_epi8(dst_reg, zero_reg); \
+ const __m512i exp_dst_hi = _mm512_unpackhi_epi8(dst_reg, zero_reg); \
+ const __m512i d_lo = _mm512_sub_epi16(exp_src_lo, exp_dst_lo); \
+ const __m512i d_hi = _mm512_sub_epi16(exp_src_hi, exp_dst_hi); \
+ sum_reg = _mm512_add_epi16(sum_reg, _mm512_add_epi16(d_lo, d_hi)); \
+ sse_reg = _mm512_add_epi32( \
+ sse_reg, _mm512_add_epi32(_mm512_madd_epi16(d_lo, d_lo), \
+ _mm512_madd_epi16(d_hi, d_hi))); \
+ } while (0)
+
+#define FILTER_PAIR_ZMM(s0, s1, filt, out_lo, out_hi) \
+ do { \
+ out_lo = _mm512_maddubs_epi16(_mm512_unpacklo_epi8(s0, s1), filt); \
+ out_hi = _mm512_maddubs_epi16(_mm512_unpackhi_epi8(s0, s1), filt); \
+ out_lo = _mm512_srai_epi16(_mm512_add_epi16(out_lo, pw8), 4); \
+ out_hi = _mm512_srai_epi16(_mm512_add_epi16(out_hi, pw8), 4); \
+ } while (0)
+
+ if (x_offset == 0) {
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i++) {
+ const __m512i s = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride;
+ dst += dst_stride;
+ }
+ } else if (y_offset == 4) {
+ for (int i = 0; i < height; i++) {
+ const __m512i s = _mm512_avg_epu8(
+ _mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + src_stride)));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride;
+ dst += dst_stride;
+ }
+ } else {
+ const __m512i filter = bilinear_filter_zmm(y_offset);
+ for (int i = 0; i < height; i++) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i s1 =
+ _mm512_loadu_si512((const __m512i *)(src + src_stride));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(s0, s1, filter, exp_lo, exp_hi);
+ ACCUM_DIFF_ZMM(exp_lo, exp_hi, d);
+ src += src_stride;
+ dst += dst_stride;
+ }
+ }
+ } else if (x_offset == 4) {
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i++) {
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride;
+ dst += dst_stride;
+ }
+ } else if (y_offset == 4) {
+ __m512i s_prev =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ for (int i = 0; i < height; i++) {
+ src += src_stride;
+ const __m512i s_curr =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ const __m512i s_avg = _mm512_avg_epu8(s_prev, s_curr);
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s_avg, d, &sse_reg, &sum_reg);
+ s_prev = s_curr;
+ dst += dst_stride;
+ }
+ } else {
+ const __m512i filter = bilinear_filter_zmm(y_offset);
+ __m512i s_prev =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ for (int i = 0; i < height; i++) {
+ src += src_stride;
+ const __m512i s_curr =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(s_prev, s_curr, filter, exp_lo, exp_hi);
+ ACCUM_DIFF_ZMM(exp_lo, exp_hi, d);
+ s_prev = s_curr;
+ dst += dst_stride;
+ }
+ }
+ } else {
+ const __m512i xfilter = bilinear_filter_zmm(x_offset);
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i++) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)src);
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(src + 1));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(s0, s1, xfilter, exp_lo, exp_hi);
+ ACCUM_DIFF_ZMM(exp_lo, exp_hi, d);
+ src += src_stride;
+ dst += dst_stride;
+ }
+ } else if (y_offset == 4) {
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ __m512i src_pack = _mm512_packus_epi16(exp_lo, exp_hi);
+ for (int i = 0; i < height; i++) {
+ src += src_stride;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ const __m512i src_curr = _mm512_packus_epi16(exp_lo, exp_hi);
+ const __m512i src_avg = _mm512_avg_epu8(src_pack, src_curr);
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(src_avg, d, &sse_reg, &sum_reg);
+ src_pack = src_curr;
+ dst += dst_stride;
+ }
+ } else {
+ const __m512i yfilter = bilinear_filter_zmm(y_offset);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ __m512i src_pack = _mm512_packus_epi16(exp_lo, exp_hi);
+ for (int i = 0; i < height; i++) {
+ src += src_stride;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ const __m512i src_curr = _mm512_packus_epi16(exp_lo, exp_hi);
+ __m512i v_lo, v_hi;
+ FILTER_PAIR_ZMM(src_pack, src_curr, yfilter, v_lo, v_hi);
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ ACCUM_DIFF_ZMM(v_lo, v_hi, d);
+ src_pack = src_curr;
+ dst += dst_stride;
+ }
+ }
+ }
+ return variance_final_from_16bit_sum_zmm(sse_reg, sum_reg, sse);
+}
+
+static AOM_FORCE_INLINE int sub_pixel_avg_variance64xh_imp_avx512(
+ const uint8_t *src, int src_stride, int x_offset, int y_offset,
+ const uint8_t *dst, int dst_stride, const uint8_t *sec, int sec_stride,
+ int height, unsigned int *sse) {
+ __m512i sum_reg = _mm512_setzero_si512();
+ __m512i sse_reg = _mm512_setzero_si512();
+ const __m512i pw8 = _mm512_set1_epi16(8);
+
+ if (x_offset == 0) {
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i++) {
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ } else if (y_offset == 4) {
+ for (int i = 0; i < height; i++) {
+ __m512i s = _mm512_avg_epu8(
+ _mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + src_stride)));
+ s = _mm512_avg_epu8(s, _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ } else {
+ const __m512i filter = bilinear_filter_zmm(y_offset);
+ for (int i = 0; i < height; i++) {
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + src_stride)),
+ filter, exp_lo, exp_hi);
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_packus_epi16(exp_lo, exp_hi),
+ _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ }
+ } else if (x_offset == 4) {
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i++) {
+ __m512i s =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ s = _mm512_avg_epu8(s, _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ } else if (y_offset == 4) {
+ __m512i s_prev =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ for (int i = 0; i < height; i++) {
+ src += src_stride;
+ const __m512i s_curr =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ const __m512i s_avg =
+ _mm512_avg_epu8(_mm512_avg_epu8(s_prev, s_curr),
+ _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s_avg, d, &sse_reg, &sum_reg);
+ s_prev = s_curr;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ } else {
+ const __m512i filter = bilinear_filter_zmm(y_offset);
+ __m512i s_prev =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ for (int i = 0; i < height; i++) {
+ src += src_stride;
+ const __m512i s_curr =
+ _mm512_avg_epu8(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)));
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(s_prev, s_curr, filter, exp_lo, exp_hi);
+ const __m512i s_avg =
+ _mm512_avg_epu8(_mm512_packus_epi16(exp_lo, exp_hi),
+ _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s_avg, d, &sse_reg, &sum_reg);
+ s_prev = s_curr;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ }
+ } else {
+ const __m512i xfilter = bilinear_filter_zmm(x_offset);
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i++) {
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_packus_epi16(exp_lo, exp_hi),
+ _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ } else if (y_offset == 4) {
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ __m512i src_pack = _mm512_packus_epi16(exp_lo, exp_hi);
+ for (int i = 0; i < height; i++) {
+ src += src_stride;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ const __m512i src_curr = _mm512_packus_epi16(exp_lo, exp_hi);
+ const __m512i src_avg =
+ _mm512_avg_epu8(_mm512_avg_epu8(src_pack, src_curr),
+ _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(src_avg, d, &sse_reg, &sum_reg);
+ src_pack = src_curr;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ } else {
+ const __m512i yfilter = bilinear_filter_zmm(y_offset);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ __m512i src_pack = _mm512_packus_epi16(exp_lo, exp_hi);
+ for (int i = 0; i < height; i++) {
+ src += src_stride;
+ FILTER_PAIR_ZMM(_mm512_loadu_si512((const __m512i *)src),
+ _mm512_loadu_si512((const __m512i *)(src + 1)), xfilter,
+ exp_lo, exp_hi);
+ const __m512i src_curr = _mm512_packus_epi16(exp_lo, exp_hi);
+ __m512i v_lo, v_hi;
+ FILTER_PAIR_ZMM(src_pack, src_curr, yfilter, v_lo, v_hi);
+ const __m512i src_avg =
+ _mm512_avg_epu8(_mm512_packus_epi16(v_lo, v_hi),
+ _mm512_loadu_si512((const __m512i *)sec));
+ const __m512i d = _mm512_loadu_si512((const __m512i *)dst);
+ variance_kernel_zmm(src_avg, d, &sse_reg, &sum_reg);
+ src_pack = src_curr;
+ dst += dst_stride;
+ sec += sec_stride;
+ }
+ }
+ }
+ return variance_final_from_16bit_sum_zmm(sse_reg, sum_reg, sse);
+}
+
+// 32xh subpixel variance packing 2 rows of 32 bytes per 512-bit ZMM register.
+static AOM_FORCE_INLINE int sub_pixel_variance32xh_imp_avx512(
+ const uint8_t *src, int src_stride, int x_offset, int y_offset,
+ const uint8_t *dst, int dst_stride, int height, unsigned int *sse) {
+ __m512i sum_reg = _mm512_setzero_si512();
+ __m512i sse_reg = _mm512_setzero_si512();
+ const __m512i zero_reg = _mm512_setzero_si512();
+ const __m512i pw8 = _mm512_set1_epi16(8);
+
+ if (x_offset == 0) {
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s = loadu2_256_zmm(src + src_stride, src);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ } else if (y_offset == 4) {
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s0 = loadu2_256_zmm(src + src_stride, src);
+ const __m512i s1 =
+ loadu2_256_zmm(src + src_stride * 2, src + src_stride);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(_mm512_avg_epu8(s0, s1), d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ } else {
+ const __m512i filter = bilinear_filter_zmm(y_offset);
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s0 = loadu2_256_zmm(src + src_stride, src);
+ const __m512i s1 =
+ loadu2_256_zmm(src + src_stride * 2, src + src_stride);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(s0, s1, filter, exp_lo, exp_hi);
+ ACCUM_DIFF_ZMM(exp_lo, exp_hi, d);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ }
+ } else if (x_offset == 4) {
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s0 = loadu2_256_zmm(src + src_stride, src);
+ const __m512i s1 = loadu2_256_zmm(src + src_stride + 1, src + 1);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(_mm512_avg_epu8(s0, s1), d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ } else if (y_offset == 4) {
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s_row01 =
+ _mm512_avg_epu8(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1));
+ const __m512i s_row12 = _mm512_avg_epu8(
+ loadu2_256_zmm(src + src_stride * 2, src + src_stride),
+ loadu2_256_zmm(src + src_stride * 2 + 1, src + src_stride + 1));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(_mm512_avg_epu8(s_row01, s_row12), d, &sse_reg,
+ &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ } else {
+ const __m512i filter = bilinear_filter_zmm(y_offset);
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s_row01 =
+ _mm512_avg_epu8(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1));
+ const __m512i s_row12 = _mm512_avg_epu8(
+ loadu2_256_zmm(src + src_stride * 2, src + src_stride),
+ loadu2_256_zmm(src + src_stride * 2 + 1, src + src_stride + 1));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(s_row01, s_row12, filter, exp_lo, exp_hi);
+ ACCUM_DIFF_ZMM(exp_lo, exp_hi, d);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ }
+ } else {
+ const __m512i xfilter = bilinear_filter_zmm(x_offset);
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s0 = loadu2_256_zmm(src + src_stride, src);
+ const __m512i s1 = loadu2_256_zmm(src + src_stride + 1, src + 1);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(s0, s1, xfilter, exp_lo, exp_hi);
+ ACCUM_DIFF_ZMM(exp_lo, exp_hi, d);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ } else if (y_offset == 4) {
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ __m512i p01 = _mm512_packus_epi16(exp_lo, exp_hi);
+ src += src_stride * 2;
+ for (int i = 0; i < height - 2; i += 2) {
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ const __m512i p23 = _mm512_packus_epi16(exp_lo, exp_hi);
+ const __m512i p12 = _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm512_extracti64x4_epi64(p01, 1)),
+ _mm512_castsi512_si256(p23), 1);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(_mm512_avg_epu8(p01, p12), d, &sse_reg, &sum_reg);
+ p01 = p23;
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ {
+ const __m256i s0 = _mm256_loadu_si256((const __m256i *)src);
+ const __m256i s1 = _mm256_loadu_si256((const __m256i *)(src + 1));
+ const __m256i xf256 = _mm512_castsi512_si256(xfilter);
+ const __m256i pw8_256 = _mm256_set1_epi16(8);
+ const __m256i l = _mm256_srai_epi16(
+ _mm256_add_epi16(
+ _mm256_maddubs_epi16(_mm256_unpacklo_epi8(s0, s1), xf256),
+ pw8_256),
+ 4);
+ const __m256i h = _mm256_srai_epi16(
+ _mm256_add_epi16(
+ _mm256_maddubs_epi16(_mm256_unpackhi_epi8(s0, s1), xf256),
+ pw8_256),
+ 4);
+ const __m256i p_last = _mm256_packus_epi16(l, h);
+ const __m512i p12 = _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm512_extracti64x4_epi64(p01, 1)), p_last,
+ 1);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(_mm512_avg_epu8(p01, p12), d, &sse_reg, &sum_reg);
+ }
+ } else {
+ const __m512i yfilter = bilinear_filter_zmm(y_offset);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ __m512i p01 = _mm512_packus_epi16(exp_lo, exp_hi);
+ src += src_stride * 2;
+ for (int i = 0; i < height - 2; i += 2) {
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ const __m512i p23 = _mm512_packus_epi16(exp_lo, exp_hi);
+ const __m512i p12 = _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm512_extracti64x4_epi64(p01, 1)),
+ _mm512_castsi512_si256(p23), 1);
+ __m512i v_lo, v_hi;
+ FILTER_PAIR_ZMM(p01, p12, yfilter, v_lo, v_hi);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ ACCUM_DIFF_ZMM(v_lo, v_hi, d);
+ p01 = p23;
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ }
+ {
+ const __m256i s0 = _mm256_loadu_si256((const __m256i *)src);
+ const __m256i s1 = _mm256_loadu_si256((const __m256i *)(src + 1));
+ const __m256i xf256 = _mm512_castsi512_si256(xfilter);
+ const __m256i pw8_256 = _mm256_set1_epi16(8);
+ const __m256i l = _mm256_srai_epi16(
+ _mm256_add_epi16(
+ _mm256_maddubs_epi16(_mm256_unpacklo_epi8(s0, s1), xf256),
+ pw8_256),
+ 4);
+ const __m256i h = _mm256_srai_epi16(
+ _mm256_add_epi16(
+ _mm256_maddubs_epi16(_mm256_unpackhi_epi8(s0, s1), xf256),
+ pw8_256),
+ 4);
+ const __m256i p_last = _mm256_packus_epi16(l, h);
+ const __m512i p12 = _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm512_extracti64x4_epi64(p01, 1)), p_last,
+ 1);
+ __m512i v_lo, v_hi;
+ FILTER_PAIR_ZMM(p01, p12, yfilter, v_lo, v_hi);
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ ACCUM_DIFF_ZMM(v_lo, v_hi, d);
+ }
+ }
+ }
+ return variance_final_from_16bit_sum_zmm(sse_reg, sum_reg, sse);
+}
+
+static AOM_FORCE_INLINE int sub_pixel_avg_variance32xh_imp_avx512(
+ const uint8_t *src, int src_stride, int x_offset, int y_offset,
+ const uint8_t *dst, int dst_stride, const uint8_t *sec, int sec_stride,
+ int height, unsigned int *sse) {
+ __m512i sum_reg = _mm512_setzero_si512();
+ __m512i sse_reg = _mm512_setzero_si512();
+ const __m512i pw8 = _mm512_set1_epi16(8);
+
+ if (x_offset == 0) {
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s =
+ _mm512_avg_epu8(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ } else if (y_offset == 4) {
+ for (int i = 0; i < height; i += 2) {
+ __m512i s = _mm512_avg_epu8(
+ loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride * 2, src + src_stride));
+ s = _mm512_avg_epu8(s, loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ } else {
+ const __m512i filter = bilinear_filter_zmm(y_offset);
+ for (int i = 0; i < height; i += 2) {
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride * 2, src + src_stride),
+ filter, exp_lo, exp_hi);
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_packus_epi16(exp_lo, exp_hi),
+ loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ }
+ } else if (x_offset == 4) {
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i += 2) {
+ __m512i s =
+ _mm512_avg_epu8(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1));
+ s = _mm512_avg_epu8(s, loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ } else if (y_offset == 4) {
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s_row01 =
+ _mm512_avg_epu8(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1));
+ const __m512i s_row12 = _mm512_avg_epu8(
+ loadu2_256_zmm(src + src_stride * 2, src + src_stride),
+ loadu2_256_zmm(src + src_stride * 2 + 1, src + src_stride + 1));
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_avg_epu8(s_row01, s_row12),
+ loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ } else {
+ const __m512i filter = bilinear_filter_zmm(y_offset);
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s_row01 =
+ _mm512_avg_epu8(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1));
+ const __m512i s_row12 = _mm512_avg_epu8(
+ loadu2_256_zmm(src + src_stride * 2, src + src_stride),
+ loadu2_256_zmm(src + src_stride * 2 + 1, src + src_stride + 1));
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(s_row01, s_row12, filter, exp_lo, exp_hi);
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_packus_epi16(exp_lo, exp_hi),
+ loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ }
+ } else {
+ const __m512i xfilter = bilinear_filter_zmm(x_offset);
+ if (y_offset == 0) {
+ for (int i = 0; i < height; i += 2) {
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_packus_epi16(exp_lo, exp_hi),
+ loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ } else if (y_offset == 4) {
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ __m512i p01 = _mm512_packus_epi16(exp_lo, exp_hi);
+ src += src_stride * 2;
+ for (int i = 0; i < height - 2; i += 2) {
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ const __m512i p23 = _mm512_packus_epi16(exp_lo, exp_hi);
+ const __m512i p12 = _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm512_extracti64x4_epi64(p01, 1)),
+ _mm512_castsi512_si256(p23), 1);
+ const __m512i s = _mm512_avg_epu8(
+ _mm512_avg_epu8(p01, p12), loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ p01 = p23;
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ {
+ const __m256i s0 = _mm256_loadu_si256((const __m256i *)src);
+ const __m256i s1 = _mm256_loadu_si256((const __m256i *)(src + 1));
+ const __m256i xf256 = _mm512_castsi512_si256(xfilter);
+ const __m256i pw8_256 = _mm256_set1_epi16(8);
+ const __m256i l = _mm256_srai_epi16(
+ _mm256_add_epi16(
+ _mm256_maddubs_epi16(_mm256_unpacklo_epi8(s0, s1), xf256),
+ pw8_256),
+ 4);
+ const __m256i h = _mm256_srai_epi16(
+ _mm256_add_epi16(
+ _mm256_maddubs_epi16(_mm256_unpackhi_epi8(s0, s1), xf256),
+ pw8_256),
+ 4);
+ const __m256i p_last = _mm256_packus_epi16(l, h);
+ const __m512i p12 = _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm512_extracti64x4_epi64(p01, 1)), p_last,
+ 1);
+ const __m512i s = _mm512_avg_epu8(
+ _mm512_avg_epu8(p01, p12), loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ }
+ } else {
+ const __m512i yfilter = bilinear_filter_zmm(y_offset);
+ __m512i exp_lo, exp_hi;
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ __m512i p01 = _mm512_packus_epi16(exp_lo, exp_hi);
+ src += src_stride * 2;
+ for (int i = 0; i < height - 2; i += 2) {
+ FILTER_PAIR_ZMM(loadu2_256_zmm(src + src_stride, src),
+ loadu2_256_zmm(src + src_stride + 1, src + 1), xfilter,
+ exp_lo, exp_hi);
+ const __m512i p23 = _mm512_packus_epi16(exp_lo, exp_hi);
+ const __m512i p12 = _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm512_extracti64x4_epi64(p01, 1)),
+ _mm512_castsi512_si256(p23), 1);
+ __m512i v_lo, v_hi;
+ FILTER_PAIR_ZMM(p01, p12, yfilter, v_lo, v_hi);
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_packus_epi16(v_lo, v_hi),
+ loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ p01 = p23;
+ src += src_stride * 2;
+ dst += dst_stride * 2;
+ sec += sec_stride * 2;
+ }
+ {
+ const __m256i s0 = _mm256_loadu_si256((const __m256i *)src);
+ const __m256i s1 = _mm256_loadu_si256((const __m256i *)(src + 1));
+ const __m256i xf256 = _mm512_castsi512_si256(xfilter);
+ const __m256i pw8_256 = _mm256_set1_epi16(8);
+ const __m256i l = _mm256_srai_epi16(
+ _mm256_add_epi16(
+ _mm256_maddubs_epi16(_mm256_unpacklo_epi8(s0, s1), xf256),
+ pw8_256),
+ 4);
+ const __m256i h = _mm256_srai_epi16(
+ _mm256_add_epi16(
+ _mm256_maddubs_epi16(_mm256_unpackhi_epi8(s0, s1), xf256),
+ pw8_256),
+ 4);
+ const __m256i p_last = _mm256_packus_epi16(l, h);
+ const __m512i p12 = _mm512_inserti64x4(
+ _mm512_castsi256_si512(_mm512_extracti64x4_epi64(p01, 1)), p_last,
+ 1);
+ __m512i v_lo, v_hi;
+ FILTER_PAIR_ZMM(p01, p12, yfilter, v_lo, v_hi);
+ const __m512i s =
+ _mm512_avg_epu8(_mm512_packus_epi16(v_lo, v_hi),
+ loadu2_256_zmm(sec + sec_stride, sec));
+ const __m512i d = loadu2_256_zmm(dst + dst_stride, dst);
+ variance_kernel_zmm(s, d, &sse_reg, &sum_reg);
+ }
+ }
+ }
+ return variance_final_from_16bit_sum_zmm(sse_reg, sum_reg, sse);
+}
+
+#undef ACCUM_DIFF_ZMM
+#undef FILTER_PAIR_ZMM
+
+#define MAKE_SUB_PIXEL_VAR_32XH_AVX512(h, log2h) \
+ unsigned int aom_sub_pixel_variance32x##h##_avx512( \
+ const uint8_t *src, int src_stride, int x_offset, int y_offset, \
+ const uint8_t *dst, int dst_stride, unsigned int *sse) { \
+ const int sum = sub_pixel_variance32xh_imp_avx512( \
+ src, src_stride, x_offset, y_offset, dst, dst_stride, h, sse); \
+ return *sse - (unsigned int)(((int64_t)sum * sum) >> (5 + (log2h))); \
+ } \
+ unsigned int aom_sub_pixel_avg_variance32x##h##_avx512( \
+ const uint8_t *src, int src_stride, int x_offset, int y_offset, \
+ const uint8_t *dst, int dst_stride, unsigned int *sse, \
+ const uint8_t *sec_ptr) { \
+ const int sum = sub_pixel_avg_variance32xh_imp_avx512( \
+ src, src_stride, x_offset, y_offset, dst, dst_stride, sec_ptr, 32, h, \
+ sse); \
+ return *sse - (unsigned int)(((int64_t)sum * sum) >> (5 + (log2h))); \
+ }
+
+MAKE_SUB_PIXEL_VAR_32XH_AVX512(64, 6)
+MAKE_SUB_PIXEL_VAR_32XH_AVX512(32, 5)
+MAKE_SUB_PIXEL_VAR_32XH_AVX512(16, 4)
+#if !CONFIG_REALTIME_ONLY
+MAKE_SUB_PIXEL_VAR_32XH_AVX512(8, 3)
+#endif
+
+#define MAKE_SUB_PIXEL_VAR_64_128_AVX512(w, h, hf, wlog2, hlog2) \
+ unsigned int aom_sub_pixel_variance##w##x##h##_avx512( \
+ const uint8_t *src, int src_stride, int x_offset, int y_offset, \
+ const uint8_t *dst, int dst_stride, unsigned int *sse_ptr) { \
+ unsigned int sse = 0; \
+ int se = 0; \
+ for (int i = 0; i < (w) / 64; ++i) { \
+ const uint8_t *src_ptr = src; \
+ const uint8_t *dst_ptr = dst; \
+ for (int j = 0; j < (h) / (hf); ++j) { \
+ unsigned int sse2; \
+ const int se2 = sub_pixel_variance64xh_imp_avx512( \
+ src_ptr, src_stride, x_offset, y_offset, dst_ptr, dst_stride, hf, \
+ &sse2); \
+ dst_ptr += (hf) * dst_stride; \
+ src_ptr += (hf) * src_stride; \
+ se += se2; \
+ sse += sse2; \
+ } \
+ src += 64; \
+ dst += 64; \
+ } \
+ *sse_ptr = sse; \
+ return sse - (unsigned int)(((int64_t)se * se) >> ((wlog2) + (hlog2))); \
+ } \
+ unsigned int aom_sub_pixel_avg_variance##w##x##h##_avx512( \
+ const uint8_t *src, int src_stride, int x_offset, int y_offset, \
+ const uint8_t *dst, int dst_stride, unsigned int *sse_ptr, \
+ const uint8_t *sec) { \
+ unsigned int sse = 0; \
+ int se = 0; \
+ for (int i = 0; i < (w) / 64; ++i) { \
+ const uint8_t *src_ptr = src; \
+ const uint8_t *dst_ptr = dst; \
+ const uint8_t *sec_ptr = sec; \
+ for (int j = 0; j < (h) / (hf); ++j) { \
+ unsigned int sse2; \
+ const int se2 = sub_pixel_avg_variance64xh_imp_avx512( \
+ src_ptr, src_stride, x_offset, y_offset, dst_ptr, dst_stride, \
+ sec_ptr, w, hf, &sse2); \
+ dst_ptr += (hf) * dst_stride; \
+ src_ptr += (hf) * src_stride; \
+ sec_ptr += (hf) * (w); \
+ se += se2; \
+ sse += sse2; \
+ } \
+ src += 64; \
+ dst += 64; \
+ sec += 64; \
+ } \
+ *sse_ptr = sse; \
+ return sse - (unsigned int)(((int64_t)se * se) >> ((wlog2) + (hlog2))); \
+ }
+
+MAKE_SUB_PIXEL_VAR_64_128_AVX512(128, 128, 64, 7, 7)
+MAKE_SUB_PIXEL_VAR_64_128_AVX512(128, 64, 64, 7, 6)
+MAKE_SUB_PIXEL_VAR_64_128_AVX512(64, 128, 64, 6, 7)
+MAKE_SUB_PIXEL_VAR_64_128_AVX512(64, 64, 64, 6, 6)
+MAKE_SUB_PIXEL_VAR_64_128_AVX512(64, 32, 32, 6, 5)
+#if !CONFIG_REALTIME_ONLY
+MAKE_SUB_PIXEL_VAR_64_128_AVX512(64, 16, 16, 6, 4)
+#endif
+
+// -----------------------------------------------------------------------------
+// Compound Average & Masked Prediction (512-bit ZMM)
+// -----------------------------------------------------------------------------
+
+static AOM_FORCE_INLINE void comp_mask_pred_line_zmm(const __m512i s0,
+ const __m512i s1,
+ const __m512i a,
+ uint8_t *comp_pred) {
+ const __m512i alpha_max = _mm512_set1_epi8(AOM_BLEND_A64_MAX_ALPHA);
+ const int16_t round_bits = 15 - AOM_BLEND_A64_ROUND_BITS;
+ const __m512i round_offset = _mm512_set1_epi16(1 << round_bits);
+ const __m512i ma = _mm512_sub_epi8(alpha_max, a);
+
+ const __m512i ssAL = _mm512_unpacklo_epi8(s0, s1);
+ const __m512i aaAL = _mm512_unpacklo_epi8(a, ma);
+ const __m512i ssAH = _mm512_unpackhi_epi8(s0, s1);
+ const __m512i aaAH = _mm512_unpackhi_epi8(a, ma);
+
+ const __m512i blendAL = _mm512_maddubs_epi16(ssAL, aaAL);
+ const __m512i blendAH = _mm512_maddubs_epi16(ssAH, aaAH);
+ const __m512i roundAL = _mm512_mulhrs_epi16(blendAL, round_offset);
+ const __m512i roundAH = _mm512_mulhrs_epi16(blendAH, round_offset);
+
+ const __m512i roundA = _mm512_packus_epi16(roundAL, roundAH);
+ _mm512_storeu_si512((__m512i *)comp_pred, roundA);
+}
+
+void aom_comp_avg_pred_avx512(uint8_t *comp_pred, const uint8_t *pred,
+ int width, int height, const uint8_t *ref,
+ int ref_stride) {
+ int row = 0;
+ if (width == 8) {
+ do {
+ const __m256i pred_0123 = _mm256_loadu_si256((const __m256i *)pred);
+ const __m128i ref_0 = _mm_loadl_epi64((const __m128i *)ref);
+ const __m128i ref_1 =
+ _mm_loadl_epi64((const __m128i *)(ref + ref_stride));
+ const __m128i ref_2 =
+ _mm_loadl_epi64((const __m128i *)(ref + 2 * ref_stride));
+ const __m128i ref_3 =
+ _mm_loadl_epi64((const __m128i *)(ref + 3 * ref_stride));
+ const __m128i ref_01 = _mm_unpacklo_epi64(ref_0, ref_1);
+ const __m128i ref_23 = _mm_unpacklo_epi64(ref_2, ref_3);
+ const __m256i ref_0123 =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(ref_01), ref_23, 1);
+ _mm256_storeu_si256((__m256i *)comp_pred,
+ _mm256_avg_epu8(pred_0123, ref_0123));
+ row += 4;
+ pred += 32;
+ comp_pred += 32;
+ ref += 4 * ref_stride;
+ } while (row < height);
+ } else if (width == 16) {
+ do {
+ const __m512i pred_0123 = _mm512_loadu_si512((const __m512i *)pred);
+ const __m512i ref_0123 = loadu4_128_zmm(ref, ref_stride);
+ _mm512_storeu_si512((__m512i *)comp_pred,
+ _mm512_avg_epu8(pred_0123, ref_0123));
+ row += 4;
+ pred += 64;
+ comp_pred += 64;
+ ref += 4 * ref_stride;
+ } while (row < height);
+ } else if (width == 32) {
+ do {
+ const __m512i pred_01 = _mm512_loadu_si512((const __m512i *)pred);
+ const __m512i ref_01 = loadu2_256_zmm(ref + ref_stride, ref);
+ _mm512_storeu_si512((__m512i *)comp_pred,
+ _mm512_avg_epu8(pred_01, ref_01));
+ row += 2;
+ pred += 64;
+ comp_pred += 64;
+ ref += 2 * ref_stride;
+ } while (row < height);
+ } else if (width % 64 == 0) {
+ do {
+ for (int x = 0; x < width; x += 64) {
+ const __m512i p = _mm512_loadu_si512((const __m512i *)(pred + x));
+ const __m512i r = _mm512_loadu_si512((const __m512i *)(ref + x));
+ _mm512_storeu_si512((__m512i *)(comp_pred + x), _mm512_avg_epu8(p, r));
+ }
+ row++;
+ pred += width;
+ comp_pred += width;
+ ref += ref_stride;
+ } while (row < height);
+ } else {
+ aom_comp_avg_pred_c(comp_pred, pred, width, height, ref, ref_stride);
+ }
+}
+
+void aom_comp_mask_pred_avx512(uint8_t *comp_pred, const uint8_t *pred,
+ int width, int height, const uint8_t *ref,
+ int ref_stride, const uint8_t *mask,
+ int mask_stride, int invert_mask) {
+ int i = 0;
+ const uint8_t *src0 = invert_mask ? pred : ref;
+ const uint8_t *src1 = invert_mask ? ref : pred;
+ const int stride0 = invert_mask ? width : ref_stride;
+ const int stride1 = invert_mask ? ref_stride : width;
+ if (width == 8) {
+ aom_comp_mask_pred_avx2(comp_pred, pred, width, height, ref, ref_stride,
+ mask, mask_stride, invert_mask);
+ } else if (width == 16) {
+ do {
+ const __m512i s0 = loadu4_128_zmm(src0, stride0);
+ const __m512i s1 = loadu4_128_zmm(src1, stride1);
+ const __m512i a = loadu4_128_zmm(mask, mask_stride);
+ comp_mask_pred_line_zmm(s0, s1, a, comp_pred);
+ src0 += stride0 * 4;
+ src1 += stride1 * 4;
+ mask += mask_stride * 4;
+ comp_pred += 64;
+ i += 4;
+ } while (i < height);
+ } else if (width == 32) {
+ do {
+ const __m512i s0 = loadu2_256_zmm(src0 + stride0, src0);
+ const __m512i s1 = loadu2_256_zmm(src1 + stride1, src1);
+ const __m512i a = loadu2_256_zmm(mask + mask_stride, mask);
+ comp_mask_pred_line_zmm(s0, s1, a, comp_pred);
+ src0 += stride0 * 2;
+ src1 += stride1 * 2;
+ mask += mask_stride * 2;
+ comp_pred += 64;
+ i += 2;
+ } while (i < height);
+ } else {
+ do {
+ for (int x = 0; x < width; x += 64) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)(src0 + x));
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(src1 + x));
+ const __m512i a = _mm512_loadu_si512((const __m512i *)(mask + x));
+ comp_mask_pred_line_zmm(s0, s1, a, comp_pred);
+ comp_pred += 64;
+ }
+ src0 += stride0;
+ src1 += stride1;
+ mask += mask_stride;
+ i++;
+ } while (i < height);
+ }
+}
+
+#if CONFIG_AV1_HIGHBITDEPTH
+static AOM_FORCE_INLINE __m512i highbd_comp_mask_pred_line_zmm(
+ const __m512i s0, const __m512i s1, const __m512i a) {
+ const __m512i alpha_max = _mm512_set1_epi16(1 << AOM_BLEND_A64_ROUND_BITS);
+ const __m512i round_const =
+ _mm512_set1_epi32((1 << AOM_BLEND_A64_ROUND_BITS) >> 1);
+ const __m512i a_inv = _mm512_sub_epi16(alpha_max, a);
+
+ const __m512i s_lo = _mm512_unpacklo_epi16(s0, s1);
+ const __m512i a_lo = _mm512_unpacklo_epi16(a, a_inv);
+ const __m512i pred_l = _mm512_srai_epi32(
+ _mm512_add_epi32(_mm512_madd_epi16(s_lo, a_lo), round_const),
+ AOM_BLEND_A64_ROUND_BITS);
+
+ const __m512i s_hi = _mm512_unpackhi_epi16(s0, s1);
+ const __m512i a_hi = _mm512_unpackhi_epi16(a, a_inv);
+ const __m512i pred_h = _mm512_srai_epi32(
+ _mm512_add_epi32(_mm512_madd_epi16(s_hi, a_hi), round_const),
+ AOM_BLEND_A64_ROUND_BITS);
+
+ return _mm512_packs_epi32(pred_l, pred_h);
+}
+
+void aom_highbd_comp_mask_pred_avx512(uint8_t *comp_pred8, const uint8_t *pred8,
+ int width, int height,
+ const uint8_t *ref8, int ref_stride,
+ const uint8_t *mask, int mask_stride,
+ int invert_mask) {
+ if (width < 16) {
+ aom_highbd_comp_mask_pred_avx2(comp_pred8, pred8, width, height, ref8,
+ ref_stride, mask, mask_stride, invert_mask);
+ return;
+ }
+ uint16_t *pred = CONVERT_TO_SHORTPTR(pred8);
+ uint16_t *ref = CONVERT_TO_SHORTPTR(ref8);
+ uint16_t *comp_pred = CONVERT_TO_SHORTPTR(comp_pred8);
+ const uint16_t *src0 = invert_mask ? pred : ref;
+ const uint16_t *src1 = invert_mask ? ref : pred;
+ const int stride0 = invert_mask ? width : ref_stride;
+ const int stride1 = invert_mask ? ref_stride : width;
+
+ if (width == 16) {
+ for (int i = 0; i < height; i += 2) {
+ const __m512i s0 = loadu2_256_zmm((const uint8_t *)(src0 + stride0),
+ (const uint8_t *)src0);
+ const __m512i s1 = loadu2_256_zmm((const uint8_t *)(src1 + stride1),
+ (const uint8_t *)src1);
+ const __m256i m8 = yy_loadu2_128(mask + mask_stride, mask);
+ const __m512i m16 = _mm512_cvtepu8_epi16(m8);
+ const __m512i comp = highbd_comp_mask_pred_line_zmm(s0, s1, m16);
+ _mm512_storeu_si512((__m512i *)comp_pred, comp);
+ src0 += stride0 * 2;
+ src1 += stride1 * 2;
+ mask += mask_stride * 2;
+ comp_pred += 32;
+ }
+ } else {
+ for (int i = 0; i < height; i++) {
+ for (int x = 0; x < width; x += 32) {
+ const __m512i s0 = _mm512_loadu_si512((const __m512i *)(src0 + x));
+ const __m512i s1 = _mm512_loadu_si512((const __m512i *)(src1 + x));
+ const __m256i m8 = _mm256_loadu_si256((const __m256i *)(mask + x));
+ const __m512i m16 = _mm512_cvtepu8_epi16(m8);
+ const __m512i comp = highbd_comp_mask_pred_line_zmm(s0, s1, m16);
+ _mm512_storeu_si512((__m512i *)comp_pred, comp);
+ comp_pred += 32;
+ }
+ src0 += stride0;
+ src1 += stride1;
+ mask += mask_stride;
+ }
+ }
+}
+#endif // CONFIG_AV1_HIGHBITDEPTH
+
+// -----------------------------------------------------------------------------
+// Block SSE & Sum (aom_get_blk_sse_sum_avx512)
+// -----------------------------------------------------------------------------
+
+void aom_get_blk_sse_sum_avx512(const int16_t *data, int stride, int bw, int bh,
+ int *x_sum, int64_t *x2_sum) {
+ if (bw < 32) {
+ aom_get_blk_sse_sum_avx2(data, stride, bw, bh, x_sum, x2_sum);
+ return;
+ }
+ const __m512i one = _mm512_set1_epi16(1);
+ __m512i sum_32 = _mm512_setzero_si512();
+ __m512i sse_64 = _mm512_setzero_si512();
+
+ for (int i = 0; i < bh; ++i) {
+ for (int j = 0; j < bw; j += 32) {
+ const __m512i d = _mm512_loadu_si512((const __m512i *)(data + j));
+ sum_32 = _mm512_add_epi32(sum_32, _mm512_madd_epi16(d, one));
+ const __m512i sq = _mm512_madd_epi16(d, d);
+ const __m512i sq_lo = _mm512_cvtepi32_epi64(_mm512_castsi512_si256(sq));
+ const __m512i sq_hi =
+ _mm512_cvtepi32_epi64(_mm512_extracti64x4_epi64(sq, 1));
+ sse_64 = _mm512_add_epi64(sse_64, _mm512_add_epi64(sq_lo, sq_hi));
+ }
+ data += stride;
+ }
+ *x_sum = hsum_epi32_zmm(sum_32);
+ *x2_sum = hsum_epi64_zmm(sse_64);
+}
+
+// -----------------------------------------------------------------------------
+// Single-pass ZMM Register-Pipelined Variance Stat
+// -----------------------------------------------------------------------------
+
+static AOM_FORCE_INLINE void load_row32_horiz_filter_zmm(const uint8_t *src_row,
+ int x, int bw,
+ __m512i *u16_curr_out,
+ __m512i *u16_H_out) {
+ const __m256i v_curr = _mm256_loadu_si256((const __m256i *)(src_row + x));
+ __m256i v_left, v_right;
+ if (x == 0) {
+ const __m256i shifted = _mm256_alignr_epi8(
+ v_curr, _mm256_permute2x128_si256(v_curr, v_curr, 0x08), 15);
+ v_left = _mm256_insert_epi8(shifted, (int8_t)src_row[0], 0);
+ } else {
+ v_left = _mm256_loadu_si256((const __m256i *)(src_row + x - 1));
+ }
+ if (x + 32 < bw) {
+ v_right = _mm256_loadu_si256((const __m256i *)(src_row + x + 1));
+ } else {
+ const __m256i shifted = _mm256_alignr_epi8(
+ _mm256_permute2x128_si256(v_curr, v_curr, 0x81), v_curr, 1);
+ v_right = _mm256_insert_epi8(shifted, (int8_t)src_row[bw - 1], 31);
+ }
+ const __m512i u16_left = _mm512_cvtepu8_epi16(v_left);
+ const __m512i u16_curr = _mm512_cvtepu8_epi16(v_curr);
+ const __m512i u16_right = _mm512_cvtepu8_epi16(v_right);
+ *u16_curr_out = u16_curr;
+ *u16_H_out = _mm512_add_epi16(_mm512_add_epi16(u16_left, u16_right),
+ _mm512_slli_epi16(u16_curr, 1));
+}
+
+int64_t aom_calc_variance_stat_avx512(const uint8_t *src, int stride, int bw,
+ int bh) {
+ if (bw < 32) {
+ return aom_calc_variance_stat_avx2(src, stride, bw, bh);
+ }
+ __m512i acc_var_512 = _mm512_setzero_si512();
+
+ for (int x = 0; x < bw; x += 32) {
+ __m512i u16_curr, H_curr;
+ load_row32_horiz_filter_zmm(src, x, bw, &u16_curr, &H_curr);
+ __m512i H_top = H_curr;
+
+ for (int y = 0; y < bh - 1; ++y) {
+ __m512i u16_next, H_bot;
+ load_row32_horiz_filter_zmm(src + (y + 1) * stride, x, bw, &u16_next,
+ &H_bot);
+ const __m512i u16_V = _mm512_add_epi16(_mm512_add_epi16(H_top, H_bot),
+ _mm512_slli_epi16(H_curr, 1));
+ const __m512i u16_sum = _mm512_srli_epi16(u16_V, 4);
+ const __m512i diff = _mm512_sub_epi16(u16_curr, u16_sum);
+ acc_var_512 =
+ _mm512_add_epi32(acc_var_512, _mm512_madd_epi16(diff, diff));
+ H_top = H_curr;
+ H_curr = H_bot;
+ u16_curr = u16_next;
+ }
+ // Last row (y = bh - 1): H_bot == H_curr
+ {
+ const __m512i u16_V = _mm512_add_epi16(_mm512_add_epi16(H_top, H_curr),
+ _mm512_slli_epi16(H_curr, 1));
+ const __m512i u16_sum = _mm512_srli_epi16(u16_V, 4);
+ const __m512i diff = _mm512_sub_epi16(u16_curr, u16_sum);
+ acc_var_512 =
+ _mm512_add_epi32(acc_var_512, _mm512_madd_epi16(diff, diff));
+ }
+ }
+ return ((int64_t)hsum_epi32_zmm(acc_var_512)) << 4;
+}
+
+#if CONFIG_AV1_HIGHBITDEPTH
+static AOM_FORCE_INLINE void highbd_load_row32_horiz_filter_zmm(
+ const uint16_t *src_row, int x, int bw, __m512i *v_curr_out,
+ __m512i *u16_H_out) {
+ const __m512i v_curr = _mm512_loadu_si512((const __m512i *)(src_row + x));
+ __m512i v_left, v_right;
+ if (x == 0) {
+ uint16_t tmp[32];
+ tmp[0] = src_row[0];
+ memcpy(&tmp[1], src_row, 31 * sizeof(uint16_t));
+ v_left = _mm512_loadu_si512((const __m512i *)tmp);
+ } else {
+ v_left = _mm512_loadu_si512((const __m512i *)(src_row + x - 1));
+ }
+ if (x + 32 < bw) {
+ v_right = _mm512_loadu_si512((const __m512i *)(src_row + x + 1));
+ } else {
+ uint16_t tmp[32];
+ memcpy(tmp, src_row + x + 1, 31 * sizeof(uint16_t));
+ tmp[31] = src_row[bw - 1];
+ v_right = _mm512_loadu_si512((const __m512i *)tmp);
+ }
+ *v_curr_out = v_curr;
+ *u16_H_out = _mm512_add_epi16(_mm512_add_epi16(v_left, v_right),
+ _mm512_slli_epi16(v_curr, 1));
+}
+
+int64_t aom_highbd_calc_variance_stat_avx512(const uint16_t *src, int stride,
+ int bw, int bh) {
+ if (bw < 32) {
+ return aom_highbd_calc_variance_stat_avx2(src, stride, bw, bh);
+ }
+ __m512i acc_var_64 = _mm512_setzero_si512();
+
+ for (int x = 0; x < bw; x += 32) {
+ __m512i v_curr, H_curr;
+ highbd_load_row32_horiz_filter_zmm(src, x, bw, &v_curr, &H_curr);
+ __m512i H_top = H_curr;
+
+ for (int y = 0; y < bh - 1; ++y) {
+ __m512i v_next, H_bot;
+ highbd_load_row32_horiz_filter_zmm(src + (y + 1) * stride, x, bw, &v_next,
+ &H_bot);
+ const __m512i u16_V = _mm512_add_epi16(_mm512_add_epi16(H_top, H_bot),
+ _mm512_slli_epi16(H_curr, 1));
+ const __m512i u16_sum = _mm512_srli_epi16(u16_V, 4);
+ const __m512i diff = _mm512_sub_epi16(v_curr, u16_sum);
+ const __m512i diff_sq = _mm512_madd_epi16(diff, diff);
+ acc_var_64 = _mm512_add_epi64(
+ acc_var_64,
+ _mm512_add_epi64(
+ _mm512_cvtepi32_epi64(_mm512_castsi512_si256(diff_sq)),
+ _mm512_cvtepi32_epi64(_mm512_extracti64x4_epi64(diff_sq, 1))));
+ H_top = H_curr;
+ H_curr = H_bot;
+ v_curr = v_next;
+ }
+ {
+ const __m512i u16_V = _mm512_add_epi16(_mm512_add_epi16(H_top, H_curr),
+ _mm512_slli_epi16(H_curr, 1));
+ const __m512i u16_sum = _mm512_srli_epi16(u16_V, 4);
+ const __m512i diff = _mm512_sub_epi16(v_curr, u16_sum);
+ const __m512i diff_sq = _mm512_madd_epi16(diff, diff);
+ acc_var_64 = _mm512_add_epi64(
+ acc_var_64,
+ _mm512_add_epi64(
+ _mm512_cvtepi32_epi64(_mm512_castsi512_si256(diff_sq)),
+ _mm512_cvtepi32_epi64(_mm512_extracti64x4_epi64(diff_sq, 1))));
+ }
+ }
+ return hsum_epi64_zmm(acc_var_64) << 4;
+}
+#endif // CONFIG_AV1_HIGHBITDEPTH
+
+// -----------------------------------------------------------------------------
+// OBMC SAD & OBMC Variance (512-bit ZMM)
+// -----------------------------------------------------------------------------
+
+#if !CONFIG_REALTIME_ONLY
+static AOM_FORCE_INLINE unsigned int obmc_sad_w16n_avx512(
+ const uint8_t *pre, const int pre_stride, const int32_t *wsrc,
+ const int32_t *mask, const int width, const int height) {
+ const int pre_step = pre_stride - width;
+ int n = 0;
+ __m512i v_sad_d = _mm512_setzero_si512();
+ const __m512i v_bias_d = _mm512_set1_epi32((1 << 12) >> 1);
+
+ do {
+ const __m128i v_p0_b = _mm_loadu_si128((const __m128i *)(pre + n));
+ const __m512i v_m0_d = _mm512_loadu_si512((const __m512i *)(mask + n));
+ const __m512i v_w0_d = _mm512_loadu_si512((const __m512i *)(wsrc + n));
+ const __m512i v_p0_d = _mm512_cvtepu8_epi32(v_p0_b);
+ const __m512i v_pm0_d = _mm512_madd_epi16(v_p0_d, v_m0_d);
+ const __m512i v_diff0_d = _mm512_sub_epi32(v_w0_d, v_pm0_d);
+ const __m512i v_absdiff0_d = _mm512_abs_epi32(v_diff0_d);
+ const __m512i v_rad0_d =
+ _mm512_srli_epi32(_mm512_add_epi32(v_absdiff0_d, v_bias_d), 12);
+ v_sad_d = _mm512_add_epi32(v_sad_d, v_rad0_d);
+ n += 16;
+ if ((n & (width - 1)) == 0) pre += pre_step;
+ } while (n < width * height);
+
+ return (unsigned int)hsum_epi32_zmm(v_sad_d);
+}
+
+#define OBMCSADWXH_AVX512(w, h) \
+ unsigned int aom_obmc_sad##w##x##h##_avx512( \
+ const uint8_t *pre, int pre_stride, const int32_t *wsrc, \
+ const int32_t *msk) { \
+ if ((w) >= 16) { \
+ return obmc_sad_w16n_avx512(pre, pre_stride, wsrc, msk, w, h); \
+ } else { \
+ return aom_obmc_sad##w##x##h##_avx2(pre, pre_stride, wsrc, msk); \
+ } \
+ }
+
+OBMCSADWXH_AVX512(128, 128)
+OBMCSADWXH_AVX512(128, 64)
+OBMCSADWXH_AVX512(64, 128)
+OBMCSADWXH_AVX512(64, 64)
+OBMCSADWXH_AVX512(64, 32)
+OBMCSADWXH_AVX512(32, 64)
+OBMCSADWXH_AVX512(32, 32)
+OBMCSADWXH_AVX512(32, 16)
+OBMCSADWXH_AVX512(16, 32)
+OBMCSADWXH_AVX512(16, 16)
+OBMCSADWXH_AVX512(16, 8)
+OBMCSADWXH_AVX512(8, 16)
+OBMCSADWXH_AVX512(8, 8)
+OBMCSADWXH_AVX512(8, 4)
+OBMCSADWXH_AVX512(4, 8)
+OBMCSADWXH_AVX512(4, 4)
+OBMCSADWXH_AVX512(4, 16)
+OBMCSADWXH_AVX512(16, 4)
+OBMCSADWXH_AVX512(8, 32)
+OBMCSADWXH_AVX512(32, 8)
+OBMCSADWXH_AVX512(16, 64)
+OBMCSADWXH_AVX512(64, 16)
+
+static AOM_FORCE_INLINE void obmc_variance_w16n_avx512(
+ const uint8_t *pre, const int pre_stride, const int32_t *wsrc,
+ const int32_t *mask, unsigned int *const sse, int *const sum, const int w,
+ const int h) {
+ int n = 0;
+ const __m512i v_bias_d = _mm512_set1_epi32((1 << 12) >> 1);
+ __m512i v_sum_d = _mm512_setzero_si512();
+ __m512i v_sse_d = _mm512_setzero_si512();
+
+ for (int row = 0; row < h; row++) {
+ for (int col = 0; col < w; col += 16) {
+ const __m128i v_p_b = _mm_loadu_si128((const __m128i *)(pre + col));
+ const __m512i v_m_d = _mm512_loadu_si512((const __m512i *)(mask + n));
+ const __m512i v_w_d = _mm512_loadu_si512((const __m512i *)(wsrc + n));
+ const __m512i v_p_d = _mm512_cvtepu8_epi32(v_p_b);
+ const __m512i v_pm_d = _mm512_madd_epi16(v_p_d, v_m_d);
+ const __m512i v_diff_d = _mm512_sub_epi32(v_w_d, v_pm_d);
+ const __m512i v_sign_d = _mm512_srai_epi32(v_diff_d, 31);
+ const __m512i v_tmp_d =
+ _mm512_add_epi32(_mm512_add_epi32(v_diff_d, v_bias_d), v_sign_d);
+ const __m512i v_rdiff_d = _mm512_srai_epi32(v_tmp_d, 12);
+
+ v_sum_d = _mm512_add_epi32(v_sum_d, v_rdiff_d);
+ v_sse_d =
+ _mm512_add_epi32(v_sse_d, _mm512_mullo_epi32(v_rdiff_d, v_rdiff_d));
+ n += 16;
+ }
+ pre += pre_stride;
+ }
+ *sum = variance_final_from_32bit_sum_zmm(v_sse_d, v_sum_d, sse);
+}
+
+#define OBMCVARWXH_AVX512(W, H) \
+ unsigned int aom_obmc_variance##W##x##H##_avx512( \
+ const uint8_t *pre, int pre_stride, const int32_t *wsrc, \
+ const int32_t *mask, unsigned int *sse) { \
+ if ((W) >= 16) { \
+ int sum; \
+ obmc_variance_w16n_avx512(pre, pre_stride, wsrc, mask, sse, &sum, W, H); \
+ return *sse - (unsigned int)(((int64_t)sum * sum) / ((W) * (H))); \
+ } else { \
+ return aom_obmc_variance##W##x##H##_avx2(pre, pre_stride, wsrc, mask, \
+ sse); \
+ } \
+ }
+
+OBMCVARWXH_AVX512(128, 128)
+OBMCVARWXH_AVX512(128, 64)
+OBMCVARWXH_AVX512(64, 128)
+OBMCVARWXH_AVX512(64, 64)
+OBMCVARWXH_AVX512(64, 32)
+OBMCVARWXH_AVX512(32, 64)
+OBMCVARWXH_AVX512(32, 32)
+OBMCVARWXH_AVX512(32, 16)
+OBMCVARWXH_AVX512(16, 32)
+OBMCVARWXH_AVX512(16, 16)
+OBMCVARWXH_AVX512(16, 8)
+OBMCVARWXH_AVX512(8, 16)
+OBMCVARWXH_AVX512(8, 8)
+OBMCVARWXH_AVX512(8, 4)
+OBMCVARWXH_AVX512(4, 8)
+OBMCVARWXH_AVX512(4, 4)
+OBMCVARWXH_AVX512(4, 16)
+OBMCVARWXH_AVX512(16, 4)
+OBMCVARWXH_AVX512(8, 32)
+OBMCVARWXH_AVX512(32, 8)
+OBMCVARWXH_AVX512(16, 64)
+OBMCVARWXH_AVX512(64, 16)
+#endif // !CONFIG_REALTIME_ONLY
+
+// -----------------------------------------------------------------------------
+// Masked SAD (512-bit ZMM)
+// -----------------------------------------------------------------------------
+
+static AOM_FORCE_INLINE __m512i masked_sad_step_zmm(
+ __m512i res, const __m512i src, const __m512i a, const __m512i b,
+ const __m512i m, const __m512i mask_max, const __m512i round_scale) {
+ const __m512i m_inv = _mm512_sub_epi8(mask_max, m);
+ const __m512i data_l = _mm512_unpacklo_epi8(a, b);
+ const __m512i mask_l = _mm512_unpacklo_epi8(m, m_inv);
+ const __m512i pred_l =
+ _mm512_mulhrs_epi16(_mm512_maddubs_epi16(data_l, mask_l), round_scale);
+
+ const __m512i data_r = _mm512_unpackhi_epi8(a, b);
+ const __m512i mask_r = _mm512_unpackhi_epi8(m, m_inv);
+ const __m512i pred_r =
+ _mm512_mulhrs_epi16(_mm512_maddubs_epi16(data_r, mask_r), round_scale);
+
+ const __m512i pred = _mm512_packus_epi16(pred_l, pred_r);
+ return _mm512_add_epi32(res, _mm512_sad_epu8(pred, src));
+}
+
+static AOM_FORCE_INLINE unsigned int masked_sad64xh_avx512(
+ const uint8_t *src_ptr, int src_stride, const uint8_t *a_ptr, int a_stride,
+ const uint8_t *b_ptr, int b_stride, const uint8_t *m_ptr, int m_stride,
+ int width, int height) {
+ __m512i res = _mm512_setzero_si512();
+ const __m512i mask_max = _mm512_set1_epi8(1 << AOM_BLEND_A64_ROUND_BITS);
+ const __m512i round_scale =
+ _mm512_set1_epi16(1 << (15 - AOM_BLEND_A64_ROUND_BITS));
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x += 64) {
+ res = masked_sad_step_zmm(
+ res, _mm512_loadu_si512((const __m512i *)&src_ptr[x]),
+ _mm512_loadu_si512((const __m512i *)&a_ptr[x]),
+ _mm512_loadu_si512((const __m512i *)&b_ptr[x]),
+ _mm512_loadu_si512((const __m512i *)&m_ptr[x]), mask_max,
+ round_scale);
+ }
+ src_ptr += src_stride;
+ a_ptr += a_stride;
+ b_ptr += b_stride;
+ m_ptr += m_stride;
+ }
+ const __m256i r256 = _mm256_add_epi32(_mm512_castsi512_si256(res),
+ _mm512_extracti64x4_epi64(res, 1));
+ const __m128i r128 = _mm_add_epi32(_mm256_castsi256_si128(r256),
+ _mm256_extracti128_si256(r256, 1));
+ return (unsigned int)_mm_cvtsi128_si32(
+ _mm_add_epi32(r128, _mm_srli_si128(r128, 8)));
+}
+
+static AOM_FORCE_INLINE unsigned int masked_sad32xh_avx512(
+ const uint8_t *src_ptr, int src_stride, const uint8_t *a_ptr, int a_stride,
+ const uint8_t *b_ptr, int b_stride, const uint8_t *m_ptr, int m_stride,
+ int height) {
+ __m512i res = _mm512_setzero_si512();
+ const __m512i mask_max = _mm512_set1_epi8(1 << AOM_BLEND_A64_ROUND_BITS);
+ const __m512i round_scale =
+ _mm512_set1_epi16(1 << (15 - AOM_BLEND_A64_ROUND_BITS));
+ for (int y = 0; y < height; y += 2) {
+ res = masked_sad_step_zmm(
+ res, loadu2_256_zmm(src_ptr + src_stride, src_ptr),
+ loadu2_256_zmm(a_ptr + a_stride, a_ptr),
+ loadu2_256_zmm(b_ptr + b_stride, b_ptr),
+ loadu2_256_zmm(m_ptr + m_stride, m_ptr), mask_max, round_scale);
+ src_ptr += src_stride * 2;
+ a_ptr += a_stride * 2;
+ b_ptr += b_stride * 2;
+ m_ptr += m_stride * 2;
+ }
+ const __m256i r256 = _mm256_add_epi32(_mm512_castsi512_si256(res),
+ _mm512_extracti64x4_epi64(res, 1));
+ const __m128i r128 = _mm_add_epi32(_mm256_castsi256_si128(r256),
+ _mm256_extracti128_si256(r256, 1));
+ return (unsigned int)_mm_cvtsi128_si32(
+ _mm_add_epi32(r128, _mm_srli_si128(r128, 8)));
+}
+
+static AOM_FORCE_INLINE unsigned int masked_sad16xh_avx512(
+ const uint8_t *src_ptr, int src_stride, const uint8_t *a_ptr, int a_stride,
+ const uint8_t *b_ptr, int b_stride, const uint8_t *m_ptr, int m_stride,
+ int height) {
+ __m512i res = _mm512_setzero_si512();
+ const __m512i mask_max = _mm512_set1_epi8(1 << AOM_BLEND_A64_ROUND_BITS);
+ const __m512i round_scale =
+ _mm512_set1_epi16(1 << (15 - AOM_BLEND_A64_ROUND_BITS));
+ for (int y = 0; y < height; y += 4) {
+ res = masked_sad_step_zmm(
+ res, loadu4_128_zmm(src_ptr, src_stride),
+ loadu4_128_zmm(a_ptr, a_stride), loadu4_128_zmm(b_ptr, b_stride),
+ loadu4_128_zmm(m_ptr, m_stride), mask_max, round_scale);
+ src_ptr += src_stride * 4;
+ a_ptr += a_stride * 4;
+ b_ptr += b_stride * 4;
+ m_ptr += m_stride * 4;
+ }
+ const __m256i r256 = _mm256_add_epi32(_mm512_castsi512_si256(res),
+ _mm512_extracti64x4_epi64(res, 1));
+ const __m128i r128 = _mm_add_epi32(_mm256_castsi256_si128(r256),
+ _mm256_extracti128_si256(r256, 1));
+ return (unsigned int)_mm_cvtsi128_si32(
+ _mm_add_epi32(r128, _mm_srli_si128(r128, 8)));
+}
+
+static AOM_FORCE_INLINE unsigned int aom_masked_sad_avx512(
+ const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride,
+ const uint8_t *second_pred, const uint8_t *msk, int msk_stride,
+ int invert_mask, int m, int n) {
+ const uint8_t *a_ptr = invert_mask ? second_pred : ref;
+ const uint8_t *b_ptr = invert_mask ? ref : second_pred;
+ const int a_stride = invert_mask ? m : ref_stride;
+ const int b_stride = invert_mask ? ref_stride : m;
+ switch (m) {
+ case 4:
+ return aom_masked_sad4xh_ssse3(src, src_stride, a_ptr, a_stride, b_ptr,
+ b_stride, msk, msk_stride, n);
+ case 8:
+ return aom_masked_sad8xh_ssse3(src, src_stride, a_ptr, a_stride, b_ptr,
+ b_stride, msk, msk_stride, n);
+ case 16:
+ return masked_sad16xh_avx512(src, src_stride, a_ptr, a_stride, b_ptr,
+ b_stride, msk, msk_stride, n);
+ case 32:
+ return masked_sad32xh_avx512(src, src_stride, a_ptr, a_stride, b_ptr,
+ b_stride, msk, msk_stride, n);
+ default:
+ return masked_sad64xh_avx512(src, src_stride, a_ptr, a_stride, b_ptr,
+ b_stride, msk, msk_stride, m, n);
+ }
+}
+
+#define MASKSADMXN_AVX512(m, n) \
+ unsigned int aom_masked_sad##m##x##n##_avx512( \
+ const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \
+ const uint8_t *second_pred, const uint8_t *msk, int msk_stride, \
+ int invert_mask) { \
+ return aom_masked_sad_avx512(src, src_stride, ref, ref_stride, \
+ second_pred, msk, msk_stride, invert_mask, m, \
+ n); \
+ }
+
+MASKSADMXN_AVX512(4, 4)
+MASKSADMXN_AVX512(4, 8)
+MASKSADMXN_AVX512(8, 4)
+MASKSADMXN_AVX512(8, 8)
+MASKSADMXN_AVX512(8, 16)
+MASKSADMXN_AVX512(16, 8)
+MASKSADMXN_AVX512(16, 16)
+MASKSADMXN_AVX512(16, 32)
+MASKSADMXN_AVX512(32, 16)
+MASKSADMXN_AVX512(32, 32)
+MASKSADMXN_AVX512(32, 64)
+MASKSADMXN_AVX512(64, 32)
+MASKSADMXN_AVX512(64, 64)
+MASKSADMXN_AVX512(64, 128)
+MASKSADMXN_AVX512(128, 64)
+MASKSADMXN_AVX512(128, 128)
+
+#if !CONFIG_REALTIME_ONLY
+MASKSADMXN_AVX512(4, 16)
+MASKSADMXN_AVX512(16, 4)
+MASKSADMXN_AVX512(8, 32)
+MASKSADMXN_AVX512(32, 8)
+MASKSADMXN_AVX512(16, 64)
+MASKSADMXN_AVX512(64, 16)
+#endif
diff --git a/aom_ports/x86.h b/aom_ports/x86.h
index 4d00d7241c..3ed95d9ce9 100644
--- a/aom_ports/x86.h
+++ b/aom_ports/x86.h
@@ -234,15 +234,10 @@ static inline int x86_simd_caps(void) {
cpuid(7, 0, reg_eax, reg_ebx, reg_ecx, reg_edx);
flags |= FEATURE_SET(reg_ebx, AVX2) ? HAS_AVX2 : 0;
// Check for OS-support of ZMM and YMM state. Necessary for AVX512.
- // Only set HAS_AVX512 flag if AVX512_DL feature are supported.
- // Older AVX512 implementations (such as Skylake) have turbo curves that
- // are currently problematic for mixed AVX512/AVX2 code
if ((xgetbv() & 0xe6) == 0xe6) {
- flags |=
- FEATURE_SET(reg_ebx, AVX512) && FEATURE_SET(reg_ecx, AVX512_DL)
- ? HAS_AVX512
- : 0;
+ flags |= FEATURE_SET(reg_ebx, AVX512) ? HAS_AVX512 : 0;
}
+ (void)reg_ecx;
}
}
}
diff --git a/av1/av1.cmake b/av1/av1.cmake
index c95a0478c1..270dacb3fc 100644
--- a/av1/av1.cmake
+++ b/av1/av1.cmake
@@ -389,6 +389,13 @@ if(NOT CONFIG_EXCLUDE_SIMD_MISMATCH)
"${AOM_ROOT}/av1/encoder/x86/ml_avx2.c")
endif()
+list(APPEND AOM_AV1_ENCODER_INTRIN_AVX512
+ "${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm_avx512.h"
+ "${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm2d_avx512.c"
+ "${AOM_ROOT}/av1/encoder/x86/av1_quantize_avx512.c"
+ "${AOM_ROOT}/av1/encoder/x86/encodetxb_avx512.c"
+ "${AOM_ROOT}/av1/encoder/x86/temporal_filter_avx512.c")
+
if(CONFIG_HIGHWAY)
list(APPEND AOM_AV1_ENCODER_INTRIN_AVX2
"${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm2d_hwy_avx2.cc")
@@ -669,6 +676,9 @@ if(CONFIG_REALTIME_ONLY)
"${AOM_ROOT}/av1/encoder/x86/temporal_filter_avx2.c"
"${AOM_ROOT}/av1/encoder/x86/cnn_avx2.c")
+ list(REMOVE_ITEM AOM_AV1_ENCODER_INTRIN_AVX512
+ "${AOM_ROOT}/av1/encoder/x86/temporal_filter_avx512.c")
+
list(REMOVE_ITEM AOM_AV1_ENCODER_INTRIN_NEON
"${AOM_ROOT}/av1/encoder/arm/cnn_neon.c"
"${AOM_ROOT}/av1/encoder/arm/highbd_pickrst_neon.c"
@@ -823,10 +833,10 @@ function(setup_av1_targets)
endif()
endif()
- if(HAVE_AVX512 AND CONFIG_AV1_ENCODER AND CONFIG_HIGHWAY)
- add_intrinsics_object_library("-march=skylake-avx512" "avx512"
- "aom_av1_encoder"
- "AOM_AV1_ENCODER_INTRIN_AVX512")
+ if(HAVE_AVX512 AND CONFIG_AV1_ENCODER)
+ add_intrinsics_object_library(
+ "-mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl" "avx512"
+ "aom_av1_encoder" "AOM_AV1_ENCODER_INTRIN_AVX512")
endif()
if(HAVE_AVX512 AND CONFIG_HIGHWAY)
diff --git a/av1/common/av1_rtcd_defs.pl b/av1/common/av1_rtcd_defs.pl
index 6d3c3034e3..10e611ab12 100644
--- a/av1/common/av1_rtcd_defs.pl
+++ b/av1/common/av1_rtcd_defs.pl
@@ -295,22 +295,22 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
# the transform coefficients are held in 32-bit
# values, so the assembler code for av1_block_error can no longer be used.
add_proto qw/int64_t av1_block_error/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz";
- specialize qw/av1_block_error avx2 neon sve/, "$sse2_asm";
+ specialize qw/av1_block_error avx2 avx512 neon sve/, "$sse2_asm";
add_proto qw/int64_t av1_block_error_lp/, "const int16_t *coeff, const int16_t *dqcoeff, intptr_t block_size";
- specialize qw/av1_block_error_lp sse2 avx2 neon sve/;
+ specialize qw/av1_block_error_lp sse2 avx2 avx512 neon sve/;
add_proto qw/void av1_quantize_fp/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
- specialize qw/av1_quantize_fp sse2 avx2 neon/;
+ specialize qw/av1_quantize_fp sse2 avx2 avx512 neon/;
add_proto qw/void av1_quantize_lp/, "const int16_t *coeff_ptr, intptr_t n_coeffs, const int16_t *round_ptr, const int16_t *quant_ptr, int16_t *qcoeff_ptr, int16_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
- specialize qw/av1_quantize_lp sse2 avx2 neon/;
+ specialize qw/av1_quantize_lp sse2 avx2 avx512 neon/;
add_proto qw/void av1_quantize_fp_32x32/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
- specialize qw/av1_quantize_fp_32x32 neon avx2/;
+ specialize qw/av1_quantize_fp_32x32 neon avx2 avx512/;
add_proto qw/void av1_quantize_fp_64x64/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
- specialize qw/av1_quantize_fp_64x64 neon avx2/;
+ specialize qw/av1_quantize_fp_64x64 neon avx2 avx512/;
add_proto qw/void av1_quantize_fp_qm/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *round_ptr, const int16_t *quant_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan, const qm_val_t *qm_ptr, const qm_val_t *iqm_ptr, int log_scale";
specialize qw/av1_quantize_fp_qm avx2/;
@@ -328,7 +328,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
#fwd txfm
add_proto qw/void av1_lowbd_fwd_txfm/, "const int16_t *src_diff, tran_low_t *coeff, int diff_stride, TxfmParam *txfm_param";
- specialize qw/av1_lowbd_fwd_txfm sse4_1 avx2 neon/, $sse2_x86;
+ specialize qw/av1_lowbd_fwd_txfm sse4_1 avx2 avx512 neon/, $sse2_x86;
add_proto qw/void av1_fwd_txfm2d_4x8/, "const int16_t *input, int32_t *output, int stride, TX_TYPE tx_type, int bd";
specialize qw/av1_fwd_txfm2d_4x8 sse4_1 neon/;
@@ -362,7 +362,6 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
specialize qw/av1_fwd_txfm2d_16x4 sse4_1 neon/;
if (aom_config("CONFIG_HIGHWAY") eq "yes") {
- specialize qw/av1_lowbd_fwd_txfm avx512/;
specialize qw/av1_fwd_txfm2d_4x8 avx512/;
specialize qw/av1_fwd_txfm2d_8x4 avx512/;
specialize qw/av1_fwd_txfm2d_8x16 avx512/;
@@ -404,16 +403,16 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
#
if (aom_config("CONFIG_REALTIME_ONLY") ne "yes") {
add_proto qw/void av1_apply_temporal_filter/, "const struct yv12_buffer_config *frame_to_filter, const struct macroblockd *mbd, const BLOCK_SIZE block_size, const int mb_row, const int mb_col, const int num_planes, const double *noise_levels, const MV *subblock_mvs, const int *subblock_mses, const int q_factor, const int filter_strength, int tf_wgt_calc_lvl, const uint8_t *pred, uint32_t *accum, uint16_t *count";
- specialize qw/av1_apply_temporal_filter sse2 avx2 neon neon_dotprod/;
+ specialize qw/av1_apply_temporal_filter sse2 avx2 avx512 neon neon_dotprod/;
add_proto qw/double av1_estimate_noise_from_single_plane/, "const uint8_t *src, int height, int width, int stride, int edge_thresh";
- specialize qw/av1_estimate_noise_from_single_plane avx2 neon/;
+ specialize qw/av1_estimate_noise_from_single_plane avx2 avx512 neon/;
if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") {
add_proto qw/void av1_highbd_apply_temporal_filter/, "const struct yv12_buffer_config *frame_to_filter, const struct macroblockd *mbd, const BLOCK_SIZE block_size, const int mb_row, const int mb_col, const int num_planes, const double *noise_levels, const MV *subblock_mvs, const int *subblock_mses, const int q_factor, const int filter_strength, int tf_wgt_calc_lvl, const uint8_t *pred, uint32_t *accum, uint16_t *count";
- specialize qw/av1_highbd_apply_temporal_filter sse2 avx2 neon/;
+ specialize qw/av1_highbd_apply_temporal_filter sse2 avx2 avx512 neon/;
add_proto qw/double av1_highbd_estimate_noise_from_single_plane/, "const uint16_t *src, int height, int width, int stride, int bit_depth, int edge_thresh";
- specialize qw/av1_highbd_estimate_noise_from_single_plane neon/;
+ specialize qw/av1_highbd_estimate_noise_from_single_plane avx512 neon/;
}
}
@@ -451,16 +450,16 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
# txb
add_proto qw/void av1_get_nz_map_contexts/, "const uint8_t *const levels, const int16_t *const scan, const int eob, const TX_SIZE tx_size, const TX_CLASS tx_class, int8_t *const coeff_contexts";
- specialize qw/av1_get_nz_map_contexts sse2 neon/;
+ specialize qw/av1_get_nz_map_contexts sse2 avx512 neon/;
add_proto qw/void av1_txb_init_levels/, "const tran_low_t *const coeff, const int width, const int height, uint8_t *const levels";
- specialize qw/av1_txb_init_levels sse4_1 avx2 neon/;
+ specialize qw/av1_txb_init_levels sse4_1 avx2 avx512 neon/;
add_proto qw/uint64_t av1_wedge_sse_from_residuals/, "const int16_t *r1, const int16_t *d, const uint8_t *m, int N";
- specialize qw/av1_wedge_sse_from_residuals sse2 avx2 neon sve/;
+ specialize qw/av1_wedge_sse_from_residuals sse2 avx2 avx512 neon sve/;
add_proto qw/int8_t av1_wedge_sign_from_residuals/, "const int16_t *ds, const uint8_t *m, int N, int64_t limit";
- specialize qw/av1_wedge_sign_from_residuals sse2 avx2 neon sve/;
+ specialize qw/av1_wedge_sign_from_residuals sse2 avx2 avx512 neon sve/;
add_proto qw/void av1_wedge_compute_delta_squares/, "int16_t *d, const int16_t *a, const int16_t *b, int N";
- specialize qw/av1_wedge_compute_delta_squares sse2 avx2 neon/;
+ specialize qw/av1_wedge_compute_delta_squares sse2 avx2 avx512 neon/;
# hash
add_proto qw/uint32_t av1_get_crc32c_value/, "void *crc_calculator, const uint8_t *p, size_t length";
diff --git a/av1/encoder/x86/av1_fwd_txfm2d_avx512.c b/av1/encoder/x86/av1_fwd_txfm2d_avx512.c
new file mode 100644
index 0000000000..5b7848ccea
--- /dev/null
+++ b/av1/encoder/x86/av1_fwd_txfm2d_avx512.c
@@ -0,0 +1,1373 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <assert.h>
+#include <immintrin.h>
+#include <string.h>
+
+#include "config/aom_config.h"
+#include "config/av1_rtcd.h"
+
+#include "aom_dsp/x86/txfm_common_avx2.h"
+#include "av1/common/av1_txfm.h"
+#include "av1/common/enums.h"
+#include "av1/common/x86/av1_txfm_sse2.h"
+#include "av1/encoder/av1_fwd_txfm1d_cfg.h"
+#include "av1/encoder/x86/av1_fwd_txfm_avx2.h"
+#include "av1/encoder/x86/av1_fwd_txfm_avx512.h"
+#include "av1/encoder/x86/av1_fwd_txfm_sse2.h"
+#include "av1/encoder/x86/av1_txfm1d_sse4.h"
+
+#if !CONFIG_HIGHWAY
+
+static inline void fdct32x16_new_avx512(const __m512i *input, __m512i *output,
+ int8_t cos_bit) {
+ const int32_t *cospi = cospi_arr(cos_bit);
+ const __m512i _r = _mm512_set1_epi32(1 << (cos_bit - 1));
+
+ const __m512i cospi_m32_p32 = pair_set_w32_epi16(-cospi[32], cospi[32]);
+ const __m512i cospi_p32_p32 = pair_set_w32_epi16(cospi[32], cospi[32]);
+ const __m512i cospi_p32_m32 = pair_set_w32_epi16(cospi[32], -cospi[32]);
+ const __m512i cospi_p48_p16 = pair_set_w32_epi16(cospi[48], cospi[16]);
+ const __m512i cospi_m16_p48 = pair_set_w32_epi16(-cospi[16], cospi[48]);
+ const __m512i cospi_m48_m16 = pair_set_w32_epi16(-cospi[48], -cospi[16]);
+ const __m512i cospi_p56_p08 = pair_set_w32_epi16(cospi[56], cospi[8]);
+ const __m512i cospi_m08_p56 = pair_set_w32_epi16(-cospi[8], cospi[56]);
+ const __m512i cospi_p24_p40 = pair_set_w32_epi16(cospi[24], cospi[40]);
+ const __m512i cospi_m40_p24 = pair_set_w32_epi16(-cospi[40], cospi[24]);
+ const __m512i cospi_p60_p04 = pair_set_w32_epi16(cospi[60], cospi[4]);
+ const __m512i cospi_m04_p60 = pair_set_w32_epi16(-cospi[4], cospi[60]);
+ const __m512i cospi_p28_p36 = pair_set_w32_epi16(cospi[28], cospi[36]);
+ const __m512i cospi_m36_p28 = pair_set_w32_epi16(-cospi[36], cospi[28]);
+ const __m512i cospi_p44_p20 = pair_set_w32_epi16(cospi[44], cospi[20]);
+ const __m512i cospi_m20_p44 = pair_set_w32_epi16(-cospi[20], cospi[44]);
+ const __m512i cospi_p12_p52 = pair_set_w32_epi16(cospi[12], cospi[52]);
+ const __m512i cospi_m52_p12 = pair_set_w32_epi16(-cospi[52], cospi[12]);
+
+ __m512i x1[16];
+ for (int i = 0; i < 8; ++i) {
+ btf_16_adds_subs_out_avx512(&x1[i], &x1[15 - i], input[i], input[15 - i]);
+ }
+
+ for (int i = 0; i < 4; ++i) btf_16_adds_subs_avx512(&x1[i], &x1[7 - i]);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[10], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[11], &x1[12], _r,
+ cos_bit);
+
+ btf_16_adds_subs_avx512(&x1[0], &x1[3]);
+ btf_16_adds_subs_avx512(&x1[1], &x1[2]);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[5], &x1[6], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[8], &x1[11]);
+ btf_16_adds_subs_avx512(&x1[9], &x1[10]);
+ btf_16_adds_subs_avx512(&x1[15], &x1[12]);
+ btf_16_adds_subs_avx512(&x1[14], &x1[13]);
+
+ btf_16_w32_avx512(cospi_p32_p32, cospi_p32_m32, &x1[0], &x1[1], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p48_p16, cospi_m16_p48, &x1[2], &x1[3], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[4], &x1[5]);
+ btf_16_adds_subs_avx512(&x1[7], &x1[6]);
+ btf_16_w32_avx512(cospi_m16_p48, cospi_p48_p16, &x1[9], &x1[14], _r, cos_bit);
+ btf_16_w32_avx512(cospi_m48_m16, cospi_m16_p48, &x1[10], &x1[13], _r,
+ cos_bit);
+
+ btf_16_w32_avx512(cospi_p56_p08, cospi_m08_p56, &x1[4], &x1[7], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p24_p40, cospi_m40_p24, &x1[5], &x1[6], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[8], &x1[9]);
+ btf_16_adds_subs_avx512(&x1[11], &x1[10]);
+ btf_16_adds_subs_avx512(&x1[12], &x1[13]);
+ btf_16_adds_subs_avx512(&x1[15], &x1[14]);
+
+ btf_16_w32_avx512(cospi_p60_p04, cospi_m04_p60, &x1[8], &x1[15], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p28_p36, cospi_m36_p28, &x1[9], &x1[14], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p44_p20, cospi_m20_p44, &x1[10], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p12_p52, cospi_m52_p12, &x1[11], &x1[12], _r,
+ cos_bit);
+
+ output[0] = x1[0];
+ output[1] = x1[8];
+ output[2] = x1[4];
+ output[3] = x1[12];
+ output[4] = x1[2];
+ output[5] = x1[10];
+ output[6] = x1[6];
+ output[7] = x1[14];
+ output[8] = x1[1];
+ output[9] = x1[9];
+ output[10] = x1[5];
+ output[11] = x1[13];
+ output[12] = x1[3];
+ output[13] = x1[11];
+ output[14] = x1[7];
+ output[15] = x1[15];
+}
+
+static inline void fadst32x16_new_avx512(const __m512i *input, __m512i *output,
+ int8_t cos_bit) {
+ const int32_t *cospi = cospi_arr(cos_bit);
+ const __m512i __zero = _mm512_setzero_si512();
+ const __m512i _r = _mm512_set1_epi32(1 << (cos_bit - 1));
+
+ const __m512i cospi_p32_p32 = pair_set_w32_epi16(cospi[32], cospi[32]);
+ const __m512i cospi_p32_m32 = pair_set_w32_epi16(cospi[32], -cospi[32]);
+ const __m512i cospi_p16_p48 = pair_set_w32_epi16(cospi[16], cospi[48]);
+ const __m512i cospi_p48_m16 = pair_set_w32_epi16(cospi[48], -cospi[16]);
+ const __m512i cospi_m48_p16 = pair_set_w32_epi16(-cospi[48], cospi[16]);
+ const __m512i cospi_p08_p56 = pair_set_w32_epi16(cospi[8], cospi[56]);
+ const __m512i cospi_p56_m08 = pair_set_w32_epi16(cospi[56], -cospi[8]);
+ const __m512i cospi_p40_p24 = pair_set_w32_epi16(cospi[40], cospi[24]);
+ const __m512i cospi_p24_m40 = pair_set_w32_epi16(cospi[24], -cospi[40]);
+ const __m512i cospi_m56_p08 = pair_set_w32_epi16(-cospi[56], cospi[8]);
+ const __m512i cospi_m24_p40 = pair_set_w32_epi16(-cospi[24], cospi[40]);
+ const __m512i cospi_p02_p62 = pair_set_w32_epi16(cospi[2], cospi[62]);
+ const __m512i cospi_p62_m02 = pair_set_w32_epi16(cospi[62], -cospi[2]);
+ const __m512i cospi_p10_p54 = pair_set_w32_epi16(cospi[10], cospi[54]);
+ const __m512i cospi_p54_m10 = pair_set_w32_epi16(cospi[54], -cospi[10]);
+ const __m512i cospi_p18_p46 = pair_set_w32_epi16(cospi[18], cospi[46]);
+ const __m512i cospi_p46_m18 = pair_set_w32_epi16(cospi[46], -cospi[18]);
+ const __m512i cospi_p26_p38 = pair_set_w32_epi16(cospi[26], cospi[38]);
+ const __m512i cospi_p38_m26 = pair_set_w32_epi16(cospi[38], -cospi[26]);
+ const __m512i cospi_p34_p30 = pair_set_w32_epi16(cospi[34], cospi[30]);
+ const __m512i cospi_p30_m34 = pair_set_w32_epi16(cospi[30], -cospi[34]);
+ const __m512i cospi_p42_p22 = pair_set_w32_epi16(cospi[42], cospi[22]);
+ const __m512i cospi_p22_m42 = pair_set_w32_epi16(cospi[22], -cospi[42]);
+ const __m512i cospi_p50_p14 = pair_set_w32_epi16(cospi[50], cospi[14]);
+ const __m512i cospi_p14_m50 = pair_set_w32_epi16(cospi[14], -cospi[50]);
+ const __m512i cospi_p58_p06 = pair_set_w32_epi16(cospi[58], cospi[6]);
+ const __m512i cospi_p06_m58 = pair_set_w32_epi16(cospi[6], -cospi[58]);
+
+ __m512i x1[16];
+ x1[0] = input[0];
+ x1[1] = _mm512_subs_epi16(__zero, input[15]);
+ x1[2] = _mm512_subs_epi16(__zero, input[7]);
+ x1[3] = input[8];
+ x1[4] = _mm512_subs_epi16(__zero, input[3]);
+ x1[5] = input[12];
+ x1[6] = input[4];
+ x1[7] = _mm512_subs_epi16(__zero, input[11]);
+ x1[8] = _mm512_subs_epi16(__zero, input[1]);
+ x1[9] = input[14];
+ x1[10] = input[6];
+ x1[11] = _mm512_subs_epi16(__zero, input[9]);
+ x1[12] = input[2];
+ x1[13] = _mm512_subs_epi16(__zero, input[13]);
+ x1[14] = _mm512_subs_epi16(__zero, input[5]);
+ x1[15] = input[10];
+
+ btf_16_w32_avx512(cospi_p32_p32, cospi_p32_m32, &x1[2], &x1[3], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p32_p32, cospi_p32_m32, &x1[6], &x1[7], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p32_p32, cospi_p32_m32, &x1[10], &x1[11], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p32_p32, cospi_p32_m32, &x1[14], &x1[15], _r,
+ cos_bit);
+
+ for (int i = 0; i < 16; i += 4) {
+ btf_16_adds_subs_avx512(&x1[i], &x1[i + 2]);
+ btf_16_adds_subs_avx512(&x1[i + 1], &x1[i + 3]);
+ }
+
+ btf_16_w32_avx512(cospi_p16_p48, cospi_p48_m16, &x1[4], &x1[5], _r, cos_bit);
+ btf_16_w32_avx512(cospi_m48_p16, cospi_p16_p48, &x1[6], &x1[7], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p16_p48, cospi_p48_m16, &x1[12], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m48_p16, cospi_p16_p48, &x1[14], &x1[15], _r,
+ cos_bit);
+
+ for (int i = 0; i < 4; ++i) {
+ btf_16_adds_subs_avx512(&x1[i], &x1[i + 4]);
+ btf_16_adds_subs_avx512(&x1[i + 8], &x1[i + 12]);
+ }
+
+ btf_16_w32_avx512(cospi_p08_p56, cospi_p56_m08, &x1[8], &x1[9], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p40_p24, cospi_p24_m40, &x1[10], &x1[11], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m56_p08, cospi_p08_p56, &x1[12], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m24_p40, cospi_p40_p24, &x1[14], &x1[15], _r,
+ cos_bit);
+
+ for (int i = 0; i < 8; ++i) btf_16_adds_subs_avx512(&x1[i], &x1[i + 8]);
+
+ btf_16_w32_avx512(cospi_p02_p62, cospi_p62_m02, &x1[0], &x1[1], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p10_p54, cospi_p54_m10, &x1[2], &x1[3], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p18_p46, cospi_p46_m18, &x1[4], &x1[5], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p26_p38, cospi_p38_m26, &x1[6], &x1[7], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p34_p30, cospi_p30_m34, &x1[8], &x1[9], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p42_p22, cospi_p22_m42, &x1[10], &x1[11], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p50_p14, cospi_p14_m50, &x1[12], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p58_p06, cospi_p06_m58, &x1[14], &x1[15], _r,
+ cos_bit);
+
+ output[0] = x1[1];
+ output[1] = x1[14];
+ output[2] = x1[3];
+ output[3] = x1[12];
+ output[4] = x1[5];
+ output[5] = x1[10];
+ output[6] = x1[7];
+ output[7] = x1[8];
+ output[8] = x1[9];
+ output[9] = x1[6];
+ output[10] = x1[11];
+ output[11] = x1[4];
+ output[12] = x1[13];
+ output[13] = x1[2];
+ output[14] = x1[15];
+ output[15] = x1[0];
+}
+
+static inline void fidentity32x16_new_avx512(const __m512i *input,
+ __m512i *output, int8_t cos_bit) {
+ (void)cos_bit;
+ const __m512i one = _mm512_set1_epi16(1);
+ for (int i = 0; i < 16; ++i) {
+ const __m512i a_lo = _mm512_unpacklo_epi16(input[i], one);
+ const __m512i a_hi = _mm512_unpackhi_epi16(input[i], one);
+ const __m512i b_lo = scale_round_avx512(a_lo, 2 * NewSqrt2);
+ const __m512i b_hi = scale_round_avx512(a_hi, 2 * NewSqrt2);
+ output[i] = _mm512_packs_epi32(b_lo, b_hi);
+ }
+}
+
+static inline void fdct32x32_avx512(const __m512i *input, __m512i *output,
+ int8_t cos_bit) {
+ const int32_t *cospi = cospi_arr(cos_bit);
+ const __m512i _r = _mm512_set1_epi32(1 << (cos_bit - 1));
+
+ const __m512i cospi_m32_p32 = pair_set_w32_epi16(-cospi[32], cospi[32]);
+ const __m512i cospi_p32_p32 = pair_set_w32_epi16(cospi[32], cospi[32]);
+ const __m512i cospi_m16_p48 = pair_set_w32_epi16(-cospi[16], cospi[48]);
+ const __m512i cospi_p48_p16 = pair_set_w32_epi16(cospi[48], cospi[16]);
+ const __m512i cospi_m48_m16 = pair_set_w32_epi16(-cospi[48], -cospi[16]);
+ const __m512i cospi_p32_m32 = pair_set_w32_epi16(cospi[32], -cospi[32]);
+ const __m512i cospi_p56_p08 = pair_set_w32_epi16(cospi[56], cospi[8]);
+ const __m512i cospi_m08_p56 = pair_set_w32_epi16(-cospi[8], cospi[56]);
+ const __m512i cospi_p24_p40 = pair_set_w32_epi16(cospi[24], cospi[40]);
+ const __m512i cospi_m40_p24 = pair_set_w32_epi16(-cospi[40], cospi[24]);
+ const __m512i cospi_m56_m08 = pair_set_w32_epi16(-cospi[56], -cospi[8]);
+ const __m512i cospi_m24_m40 = pair_set_w32_epi16(-cospi[24], -cospi[40]);
+ const __m512i cospi_p60_p04 = pair_set_w32_epi16(cospi[60], cospi[4]);
+ const __m512i cospi_m04_p60 = pair_set_w32_epi16(-cospi[4], cospi[60]);
+ const __m512i cospi_p28_p36 = pair_set_w32_epi16(cospi[28], cospi[36]);
+ const __m512i cospi_m36_p28 = pair_set_w32_epi16(-cospi[36], cospi[28]);
+ const __m512i cospi_p44_p20 = pair_set_w32_epi16(cospi[44], cospi[20]);
+ const __m512i cospi_m20_p44 = pair_set_w32_epi16(-cospi[20], cospi[44]);
+ const __m512i cospi_p12_p52 = pair_set_w32_epi16(cospi[12], cospi[52]);
+ const __m512i cospi_m52_p12 = pair_set_w32_epi16(-cospi[52], cospi[12]);
+ const __m512i cospi_p62_p02 = pair_set_w32_epi16(cospi[62], cospi[2]);
+ const __m512i cospi_m02_p62 = pair_set_w32_epi16(-cospi[2], cospi[62]);
+ const __m512i cospi_p30_p34 = pair_set_w32_epi16(cospi[30], cospi[34]);
+ const __m512i cospi_m34_p30 = pair_set_w32_epi16(-cospi[34], cospi[30]);
+ const __m512i cospi_p46_p18 = pair_set_w32_epi16(cospi[46], cospi[18]);
+ const __m512i cospi_m18_p46 = pair_set_w32_epi16(-cospi[18], cospi[46]);
+ const __m512i cospi_p14_p50 = pair_set_w32_epi16(cospi[14], cospi[50]);
+ const __m512i cospi_m50_p14 = pair_set_w32_epi16(-cospi[50], cospi[14]);
+ const __m512i cospi_p54_p10 = pair_set_w32_epi16(cospi[54], cospi[10]);
+ const __m512i cospi_m10_p54 = pair_set_w32_epi16(-cospi[10], cospi[54]);
+ const __m512i cospi_p22_p42 = pair_set_w32_epi16(cospi[22], cospi[42]);
+ const __m512i cospi_m42_p22 = pair_set_w32_epi16(-cospi[42], cospi[22]);
+ const __m512i cospi_p38_p26 = pair_set_w32_epi16(cospi[38], cospi[26]);
+ const __m512i cospi_m26_p38 = pair_set_w32_epi16(-cospi[26], cospi[38]);
+ const __m512i cospi_p06_p58 = pair_set_w32_epi16(cospi[6], cospi[58]);
+ const __m512i cospi_m58_p06 = pair_set_w32_epi16(-cospi[58], cospi[6]);
+
+ __m512i x1[32];
+ for (int i = 0; i < 16; ++i) {
+ btf_16_adds_subs_out_avx512(&x1[i], &x1[31 - i], input[i], input[31 - i]);
+ }
+
+ for (int i = 0; i < 8; ++i) btf_16_adds_subs_avx512(&x1[i], &x1[15 - i]);
+ for (int i = 0; i < 4; ++i) {
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[20 + i], &x1[27 - i],
+ _r, cos_bit);
+ }
+
+ for (int i = 0; i < 4; ++i) btf_16_adds_subs_avx512(&x1[i], &x1[7 - i]);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[10], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[11], &x1[12], _r,
+ cos_bit);
+ for (int i = 0; i < 4; ++i) {
+ btf_16_adds_subs_avx512(&x1[16 + i], &x1[23 - i]);
+ btf_16_adds_subs_avx512(&x1[31 - i], &x1[24 + i]);
+ }
+
+ btf_16_adds_subs_avx512(&x1[0], &x1[3]);
+ btf_16_adds_subs_avx512(&x1[1], &x1[2]);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[5], &x1[6], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[8], &x1[11]);
+ btf_16_adds_subs_avx512(&x1[9], &x1[10]);
+ btf_16_adds_subs_avx512(&x1[15], &x1[12]);
+ btf_16_adds_subs_avx512(&x1[14], &x1[13]);
+ btf_16_w32_avx512(cospi_m16_p48, cospi_p48_p16, &x1[18], &x1[29], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m16_p48, cospi_p48_p16, &x1[19], &x1[28], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m48_m16, cospi_m16_p48, &x1[20], &x1[27], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m48_m16, cospi_m16_p48, &x1[21], &x1[26], _r,
+ cos_bit);
+
+ btf_16_w32_avx512(cospi_p32_p32, cospi_p32_m32, &x1[0], &x1[1], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p48_p16, cospi_m16_p48, &x1[2], &x1[3], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[4], &x1[5]);
+ btf_16_adds_subs_avx512(&x1[7], &x1[6]);
+ btf_16_w32_avx512(cospi_m16_p48, cospi_p48_p16, &x1[9], &x1[14], _r, cos_bit);
+ btf_16_w32_avx512(cospi_m48_m16, cospi_m16_p48, &x1[10], &x1[13], _r,
+ cos_bit);
+ btf_16_adds_subs_avx512(&x1[16], &x1[19]);
+ btf_16_adds_subs_avx512(&x1[17], &x1[18]);
+ btf_16_adds_subs_avx512(&x1[23], &x1[20]);
+ btf_16_adds_subs_avx512(&x1[22], &x1[21]);
+ btf_16_adds_subs_avx512(&x1[24], &x1[27]);
+ btf_16_adds_subs_avx512(&x1[25], &x1[26]);
+ btf_16_adds_subs_avx512(&x1[31], &x1[28]);
+ btf_16_adds_subs_avx512(&x1[30], &x1[29]);
+
+ btf_16_w32_avx512(cospi_p56_p08, cospi_m08_p56, &x1[4], &x1[7], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p24_p40, cospi_m40_p24, &x1[5], &x1[6], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[8], &x1[9]);
+ btf_16_adds_subs_avx512(&x1[11], &x1[10]);
+ btf_16_adds_subs_avx512(&x1[12], &x1[13]);
+ btf_16_adds_subs_avx512(&x1[15], &x1[14]);
+ btf_16_w32_avx512(cospi_m08_p56, cospi_p56_p08, &x1[17], &x1[30], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m56_m08, cospi_m08_p56, &x1[18], &x1[29], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m40_p24, cospi_p24_p40, &x1[21], &x1[26], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m24_m40, cospi_m40_p24, &x1[22], &x1[25], _r,
+ cos_bit);
+
+ btf_16_w32_avx512(cospi_p60_p04, cospi_m04_p60, &x1[8], &x1[15], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p28_p36, cospi_m36_p28, &x1[9], &x1[14], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p44_p20, cospi_m20_p44, &x1[10], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p12_p52, cospi_m52_p12, &x1[11], &x1[12], _r,
+ cos_bit);
+ for (int i = 16; i < 32; i += 4) {
+ btf_16_adds_subs_avx512(&x1[i], &x1[i + 1]);
+ btf_16_adds_subs_avx512(&x1[i + 3], &x1[i + 2]);
+ }
+
+ btf_16_w32_avx512(cospi_p62_p02, cospi_m02_p62, &x1[16], &x1[31], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p30_p34, cospi_m34_p30, &x1[17], &x1[30], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p46_p18, cospi_m18_p46, &x1[18], &x1[29], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p14_p50, cospi_m50_p14, &x1[19], &x1[28], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p54_p10, cospi_m10_p54, &x1[20], &x1[27], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p22_p42, cospi_m42_p22, &x1[21], &x1[26], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p38_p26, cospi_m26_p38, &x1[22], &x1[25], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p06_p58, cospi_m58_p06, &x1[23], &x1[24], _r,
+ cos_bit);
+
+ output[0] = x1[0];
+ output[1] = x1[16];
+ output[2] = x1[8];
+ output[3] = x1[24];
+ output[4] = x1[4];
+ output[5] = x1[20];
+ output[6] = x1[12];
+ output[7] = x1[28];
+ output[8] = x1[2];
+ output[9] = x1[18];
+ output[10] = x1[10];
+ output[11] = x1[26];
+ output[12] = x1[6];
+ output[13] = x1[22];
+ output[14] = x1[14];
+ output[15] = x1[30];
+ output[16] = x1[1];
+ output[17] = x1[17];
+ output[18] = x1[9];
+ output[19] = x1[25];
+ output[20] = x1[5];
+ output[21] = x1[21];
+ output[22] = x1[13];
+ output[23] = x1[29];
+ output[24] = x1[3];
+ output[25] = x1[19];
+ output[26] = x1[11];
+ output[27] = x1[27];
+ output[28] = x1[7];
+ output[29] = x1[23];
+ output[30] = x1[15];
+ output[31] = x1[31];
+}
+
+static inline void fidentity32x32_avx512(const __m512i *input, __m512i *output,
+ int8_t cos_bit) {
+ (void)cos_bit;
+ for (int i = 0; i < 32; ++i) {
+ output[i] = _mm512_slli_epi16(input[i], 2);
+ }
+}
+
+static inline void fdct32x64_new_avx512(const __m512i *input, __m512i *output,
+ int8_t cos_bit) {
+ const int32_t *cospi = cospi_arr(cos_bit);
+ const __m512i _r = _mm512_set1_epi32(1 << (cos_bit - 1));
+
+ const __m512i cospi_m32_p32 = pair_set_w32_epi16(-cospi[32], cospi[32]);
+ const __m512i cospi_p32_p32 = pair_set_w32_epi16(cospi[32], cospi[32]);
+ const __m512i cospi_m16_p48 = pair_set_w32_epi16(-cospi[16], cospi[48]);
+ const __m512i cospi_p48_p16 = pair_set_w32_epi16(cospi[48], cospi[16]);
+ const __m512i cospi_m48_m16 = pair_set_w32_epi16(-cospi[48], -cospi[16]);
+ const __m512i cospi_p32_m32 = pair_set_w32_epi16(cospi[32], -cospi[32]);
+ const __m512i cospi_m08_p56 = pair_set_w32_epi16(-cospi[8], cospi[56]);
+ const __m512i cospi_p56_p08 = pair_set_w32_epi16(cospi[56], cospi[8]);
+ const __m512i cospi_m56_m08 = pair_set_w32_epi16(-cospi[56], -cospi[8]);
+ const __m512i cospi_m40_p24 = pair_set_w32_epi16(-cospi[40], cospi[24]);
+ const __m512i cospi_p24_p40 = pair_set_w32_epi16(cospi[24], cospi[40]);
+ const __m512i cospi_m24_m40 = pair_set_w32_epi16(-cospi[24], -cospi[40]);
+ const __m512i cospi_p60_p04 = pair_set_w32_epi16(cospi[60], cospi[4]);
+ const __m512i cospi_m04_p60 = pair_set_w32_epi16(-cospi[4], cospi[60]);
+ const __m512i cospi_p28_p36 = pair_set_w32_epi16(cospi[28], cospi[36]);
+ const __m512i cospi_m36_p28 = pair_set_w32_epi16(-cospi[36], cospi[28]);
+ const __m512i cospi_p44_p20 = pair_set_w32_epi16(cospi[44], cospi[20]);
+ const __m512i cospi_m20_p44 = pair_set_w32_epi16(-cospi[20], cospi[44]);
+ const __m512i cospi_p12_p52 = pair_set_w32_epi16(cospi[12], cospi[52]);
+ const __m512i cospi_m52_p12 = pair_set_w32_epi16(-cospi[52], cospi[12]);
+ const __m512i cospi_m60_m04 = pair_set_w32_epi16(-cospi[60], -cospi[4]);
+ const __m512i cospi_m28_m36 = pair_set_w32_epi16(-cospi[28], -cospi[36]);
+ const __m512i cospi_m44_m20 = pair_set_w32_epi16(-cospi[44], -cospi[20]);
+ const __m512i cospi_m12_m52 = pair_set_w32_epi16(-cospi[12], -cospi[52]);
+ const __m512i cospi_p62_p02 = pair_set_w32_epi16(cospi[62], cospi[2]);
+ const __m512i cospi_m02_p62 = pair_set_w32_epi16(-cospi[2], cospi[62]);
+ const __m512i cospi_p30_p34 = pair_set_w32_epi16(cospi[30], cospi[34]);
+ const __m512i cospi_m34_p30 = pair_set_w32_epi16(-cospi[34], cospi[30]);
+ const __m512i cospi_p46_p18 = pair_set_w32_epi16(cospi[46], cospi[18]);
+ const __m512i cospi_m18_p46 = pair_set_w32_epi16(-cospi[18], cospi[46]);
+ const __m512i cospi_p14_p50 = pair_set_w32_epi16(cospi[14], cospi[50]);
+ const __m512i cospi_m50_p14 = pair_set_w32_epi16(-cospi[50], cospi[14]);
+ const __m512i cospi_p54_p10 = pair_set_w32_epi16(cospi[54], cospi[10]);
+ const __m512i cospi_m10_p54 = pair_set_w32_epi16(-cospi[10], cospi[54]);
+ const __m512i cospi_p22_p42 = pair_set_w32_epi16(cospi[22], cospi[42]);
+ const __m512i cospi_m42_p22 = pair_set_w32_epi16(-cospi[42], cospi[22]);
+ const __m512i cospi_p38_p26 = pair_set_w32_epi16(cospi[38], cospi[26]);
+ const __m512i cospi_m26_p38 = pair_set_w32_epi16(-cospi[26], cospi[38]);
+ const __m512i cospi_p06_p58 = pair_set_w32_epi16(cospi[6], cospi[58]);
+ const __m512i cospi_m58_p06 = pair_set_w32_epi16(-cospi[58], cospi[6]);
+ const __m512i cospi_p63_p01 = pair_set_w32_epi16(cospi[63], cospi[1]);
+ const __m512i cospi_m01_p63 = pair_set_w32_epi16(-cospi[1], cospi[63]);
+ const __m512i cospi_p31_p33 = pair_set_w32_epi16(cospi[31], cospi[33]);
+ const __m512i cospi_m33_p31 = pair_set_w32_epi16(-cospi[33], cospi[31]);
+ const __m512i cospi_p47_p17 = pair_set_w32_epi16(cospi[47], cospi[17]);
+ const __m512i cospi_m17_p47 = pair_set_w32_epi16(-cospi[17], cospi[47]);
+ const __m512i cospi_p15_p49 = pair_set_w32_epi16(cospi[15], cospi[49]);
+ const __m512i cospi_m49_p15 = pair_set_w32_epi16(-cospi[49], cospi[15]);
+ const __m512i cospi_p55_p09 = pair_set_w32_epi16(cospi[55], cospi[9]);
+ const __m512i cospi_m09_p55 = pair_set_w32_epi16(-cospi[9], cospi[55]);
+ const __m512i cospi_p23_p41 = pair_set_w32_epi16(cospi[23], cospi[41]);
+ const __m512i cospi_m41_p23 = pair_set_w32_epi16(-cospi[41], cospi[23]);
+ const __m512i cospi_p39_p25 = pair_set_w32_epi16(cospi[39], cospi[25]);
+ const __m512i cospi_m25_p39 = pair_set_w32_epi16(-cospi[25], cospi[39]);
+ const __m512i cospi_p07_p57 = pair_set_w32_epi16(cospi[7], cospi[57]);
+ const __m512i cospi_m57_p07 = pair_set_w32_epi16(-cospi[57], cospi[7]);
+ const __m512i cospi_p59_p05 = pair_set_w32_epi16(cospi[59], cospi[5]);
+ const __m512i cospi_m05_p59 = pair_set_w32_epi16(-cospi[5], cospi[59]);
+ const __m512i cospi_p27_p37 = pair_set_w32_epi16(cospi[27], cospi[37]);
+ const __m512i cospi_m37_p27 = pair_set_w32_epi16(-cospi[37], cospi[27]);
+ const __m512i cospi_p43_p21 = pair_set_w32_epi16(cospi[43], cospi[21]);
+ const __m512i cospi_m21_p43 = pair_set_w32_epi16(-cospi[21], cospi[43]);
+ const __m512i cospi_p11_p53 = pair_set_w32_epi16(cospi[11], cospi[53]);
+ const __m512i cospi_m53_p11 = pair_set_w32_epi16(-cospi[53], cospi[11]);
+ const __m512i cospi_p51_p13 = pair_set_w32_epi16(cospi[51], cospi[13]);
+ const __m512i cospi_m13_p51 = pair_set_w32_epi16(-cospi[13], cospi[51]);
+ const __m512i cospi_p19_p45 = pair_set_w32_epi16(cospi[19], cospi[45]);
+ const __m512i cospi_m45_p19 = pair_set_w32_epi16(-cospi[45], cospi[19]);
+ const __m512i cospi_p35_p29 = pair_set_w32_epi16(cospi[35], cospi[29]);
+ const __m512i cospi_m29_p35 = pair_set_w32_epi16(-cospi[29], cospi[35]);
+ const __m512i cospi_p03_p61 = pair_set_w32_epi16(cospi[3], cospi[61]);
+ const __m512i cospi_m61_p03 = pair_set_w32_epi16(-cospi[61], cospi[3]);
+
+ __m512i x1[64];
+ for (int i = 0; i < 32; ++i) {
+ btf_16_adds_subs_out_avx512(&x1[i], &x1[63 - i], input[i], input[63 - i]);
+ }
+ for (int i = 0; i < 16; ++i) btf_16_adds_subs_avx512(&x1[i], &x1[31 - i]);
+ for (int i = 0; i < 8; ++i) {
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[40 + i], &x1[55 - i],
+ _r, cos_bit);
+ }
+ for (int i = 0; i < 8; ++i) btf_16_adds_subs_avx512(&x1[i], &x1[15 - i]);
+ for (int i = 0; i < 4; ++i) {
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[20 + i], &x1[27 - i],
+ _r, cos_bit);
+ }
+ for (int i = 0; i < 8; ++i) {
+ btf_16_adds_subs_avx512(&x1[32 + i], &x1[47 - i]);
+ btf_16_adds_subs_avx512(&x1[63 - i], &x1[48 + i]);
+ }
+ for (int i = 0; i < 4; ++i) btf_16_adds_subs_avx512(&x1[i], &x1[7 - i]);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[10], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[11], &x1[12], _r,
+ cos_bit);
+ for (int i = 0; i < 4; ++i) {
+ btf_16_adds_subs_avx512(&x1[16 + i], &x1[23 - i]);
+ btf_16_adds_subs_avx512(&x1[31 - i], &x1[24 + i]);
+ btf_16_w32_avx512(cospi_m16_p48, cospi_p48_p16, &x1[36 + i], &x1[59 - i],
+ _r, cos_bit);
+ btf_16_w32_avx512(cospi_m48_m16, cospi_m16_p48, &x1[40 + i], &x1[55 - i],
+ _r, cos_bit);
+ }
+ btf_16_adds_subs_avx512(&x1[0], &x1[3]);
+ btf_16_adds_subs_avx512(&x1[1], &x1[2]);
+ btf_16_w32_avx512(cospi_m32_p32, cospi_p32_p32, &x1[5], &x1[6], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[8], &x1[11]);
+ btf_16_adds_subs_avx512(&x1[9], &x1[10]);
+ btf_16_adds_subs_avx512(&x1[15], &x1[12]);
+ btf_16_adds_subs_avx512(&x1[14], &x1[13]);
+ btf_16_w32_avx512(cospi_m16_p48, cospi_p48_p16, &x1[18], &x1[29], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m16_p48, cospi_p48_p16, &x1[19], &x1[28], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m48_m16, cospi_m16_p48, &x1[20], &x1[27], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m48_m16, cospi_m16_p48, &x1[21], &x1[26], _r,
+ cos_bit);
+ for (int i = 0; i < 4; ++i) {
+ btf_16_adds_subs_avx512(&x1[32 + i], &x1[39 - i]);
+ btf_16_adds_subs_avx512(&x1[47 - i], &x1[40 + i]);
+ btf_16_adds_subs_avx512(&x1[48 + i], &x1[55 - i]);
+ btf_16_adds_subs_avx512(&x1[63 - i], &x1[56 + i]);
+ }
+ btf_16_w32_avx512(cospi_p32_p32, cospi_p32_m32, &x1[0], &x1[1], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p48_p16, cospi_m16_p48, &x1[2], &x1[3], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[4], &x1[5]);
+ btf_16_adds_subs_avx512(&x1[7], &x1[6]);
+ btf_16_w32_avx512(cospi_m16_p48, cospi_p48_p16, &x1[9], &x1[14], _r, cos_bit);
+ btf_16_w32_avx512(cospi_m48_m16, cospi_m16_p48, &x1[10], &x1[13], _r,
+ cos_bit);
+ for (int i = 0; i < 2; ++i) {
+ btf_16_adds_subs_avx512(&x1[16 + i], &x1[19 - i]);
+ btf_16_adds_subs_avx512(&x1[23 - i], &x1[20 + i]);
+ btf_16_adds_subs_avx512(&x1[24 + i], &x1[27 - i]);
+ btf_16_adds_subs_avx512(&x1[31 - i], &x1[28 + i]);
+ btf_16_w32_avx512(cospi_m08_p56, cospi_p56_p08, &x1[34 + i], &x1[61 - i],
+ _r, cos_bit);
+ btf_16_w32_avx512(cospi_m56_m08, cospi_m08_p56, &x1[36 + i], &x1[59 - i],
+ _r, cos_bit);
+ btf_16_w32_avx512(cospi_m40_p24, cospi_p24_p40, &x1[42 + i], &x1[53 - i],
+ _r, cos_bit);
+ btf_16_w32_avx512(cospi_m24_m40, cospi_m40_p24, &x1[44 + i], &x1[51 - i],
+ _r, cos_bit);
+ }
+ btf_16_w32_avx512(cospi_p56_p08, cospi_m08_p56, &x1[4], &x1[7], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p24_p40, cospi_m40_p24, &x1[5], &x1[6], _r, cos_bit);
+ btf_16_adds_subs_avx512(&x1[8], &x1[9]);
+ btf_16_adds_subs_avx512(&x1[11], &x1[10]);
+ btf_16_adds_subs_avx512(&x1[12], &x1[13]);
+ btf_16_adds_subs_avx512(&x1[15], &x1[14]);
+ btf_16_w32_avx512(cospi_m08_p56, cospi_p56_p08, &x1[17], &x1[30], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m56_m08, cospi_m08_p56, &x1[18], &x1[29], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m40_p24, cospi_p24_p40, &x1[21], &x1[26], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m24_m40, cospi_m40_p24, &x1[22], &x1[25], _r,
+ cos_bit);
+ for (int k = 32; k < 64; k += 8) {
+ btf_16_adds_subs_avx512(&x1[k + 0], &x1[k + 3]);
+ btf_16_adds_subs_avx512(&x1[k + 1], &x1[k + 2]);
+ btf_16_adds_subs_avx512(&x1[k + 7], &x1[k + 4]);
+ btf_16_adds_subs_avx512(&x1[k + 6], &x1[k + 5]);
+ }
+ btf_16_w32_avx512(cospi_p60_p04, cospi_m04_p60, &x1[8], &x1[15], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p28_p36, cospi_m36_p28, &x1[9], &x1[14], _r, cos_bit);
+ btf_16_w32_avx512(cospi_p44_p20, cospi_m20_p44, &x1[10], &x1[13], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p12_p52, cospi_m52_p12, &x1[11], &x1[12], _r,
+ cos_bit);
+ for (int k = 16; k < 32; k += 4) {
+ btf_16_adds_subs_avx512(&x1[k + 0], &x1[k + 1]);
+ btf_16_adds_subs_avx512(&x1[k + 3], &x1[k + 2]);
+ }
+ btf_16_w32_avx512(cospi_m04_p60, cospi_p60_p04, &x1[33], &x1[62], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m60_m04, cospi_m04_p60, &x1[34], &x1[61], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m36_p28, cospi_p28_p36, &x1[37], &x1[58], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m28_m36, cospi_m36_p28, &x1[38], &x1[57], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m20_p44, cospi_p44_p20, &x1[41], &x1[54], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m44_m20, cospi_m20_p44, &x1[42], &x1[53], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m52_p12, cospi_p12_p52, &x1[45], &x1[50], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_m12_m52, cospi_m52_p12, &x1[46], &x1[49], _r,
+ cos_bit);
+
+ btf_16_w32_avx512(cospi_p62_p02, cospi_m02_p62, &x1[16], &x1[31], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p30_p34, cospi_m34_p30, &x1[17], &x1[30], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p46_p18, cospi_m18_p46, &x1[18], &x1[29], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p14_p50, cospi_m50_p14, &x1[19], &x1[28], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p54_p10, cospi_m10_p54, &x1[20], &x1[27], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p22_p42, cospi_m42_p22, &x1[21], &x1[26], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p38_p26, cospi_m26_p38, &x1[22], &x1[25], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p06_p58, cospi_m58_p06, &x1[23], &x1[24], _r,
+ cos_bit);
+ for (int k = 32; k < 64; k += 4) {
+ btf_16_adds_subs_avx512(&x1[k + 0], &x1[k + 1]);
+ btf_16_adds_subs_avx512(&x1[k + 3], &x1[k + 2]);
+ }
+ btf_16_w32_avx512(cospi_p63_p01, cospi_m01_p63, &x1[32], &x1[63], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p31_p33, cospi_m33_p31, &x1[33], &x1[62], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p47_p17, cospi_m17_p47, &x1[34], &x1[61], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p15_p49, cospi_m49_p15, &x1[35], &x1[60], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p55_p09, cospi_m09_p55, &x1[36], &x1[59], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p23_p41, cospi_m41_p23, &x1[37], &x1[58], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p39_p25, cospi_m25_p39, &x1[38], &x1[57], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p07_p57, cospi_m57_p07, &x1[39], &x1[56], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p59_p05, cospi_m05_p59, &x1[40], &x1[55], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p27_p37, cospi_m37_p27, &x1[41], &x1[54], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p43_p21, cospi_m21_p43, &x1[42], &x1[53], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p11_p53, cospi_m53_p11, &x1[43], &x1[52], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p51_p13, cospi_m13_p51, &x1[44], &x1[51], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p19_p45, cospi_m45_p19, &x1[45], &x1[50], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p35_p29, cospi_m29_p35, &x1[46], &x1[49], _r,
+ cos_bit);
+ btf_16_w32_avx512(cospi_p03_p61, cospi_m61_p03, &x1[47], &x1[48], _r,
+ cos_bit);
+
+ static const uint8_t kBitRev64[64] = {
+ 0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60,
+ 2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62,
+ 1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61,
+ 3, 35, 19, 51, 11, 43, 27, 59, 7, 39, 23, 55, 15, 47, 31, 63
+ };
+ for (int i = 0; i < 64; ++i) {
+ output[i] = x1[kBitRev64[i]];
+ }
+}
+
+static inline void fdct32_avx512(const __m512i *input, __m512i *output,
+ int8_t cos_bit) {
+ __m512i x1[32];
+ const int32_t *cospi = cospi_arr(cos_bit);
+ const __m512i _r = _mm512_set1_epi32(1 << (cos_bit - 1));
+
+ for (int i = 0; i < 16; ++i) {
+ btf_32_add_sub_out_avx512(&x1[i], &x1[31 - i], input[i], input[31 - i]);
+ }
+ for (int i = 0; i < 8; ++i) btf_32_add_sub_avx512(&x1[i], &x1[15 - i]);
+ for (int i = 0; i < 4; ++i) {
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[20 + i], &x1[27 - i], _r,
+ cos_bit);
+ }
+ for (int i = 0; i < 4; ++i) btf_32_add_sub_avx512(&x1[i], &x1[7 - i]);
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[10], &x1[13], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[11], &x1[12], _r, cos_bit);
+ for (int i = 0; i < 4; ++i) {
+ btf_32_add_sub_avx512(&x1[16 + i], &x1[23 - i]);
+ btf_32_add_sub_avx512(&x1[31 - i], &x1[24 + i]);
+ }
+ btf_32_add_sub_avx512(&x1[0], &x1[3]);
+ btf_32_add_sub_avx512(&x1[1], &x1[2]);
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[5], &x1[6], _r, cos_bit);
+ btf_32_add_sub_avx512(&x1[8], &x1[11]);
+ btf_32_add_sub_avx512(&x1[9], &x1[10]);
+ btf_32_add_sub_avx512(&x1[15], &x1[12]);
+ btf_32_add_sub_avx512(&x1[14], &x1[13]);
+ btf_32_avx512_type0(-cospi[16], cospi[48], &x1[18], &x1[29], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[16], cospi[48], &x1[19], &x1[28], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[48], -cospi[16], &x1[20], &x1[27], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[48], -cospi[16], &x1[21], &x1[26], _r, cos_bit);
+
+ btf_32_avx512_type0(cospi[32], cospi[32], &x1[0], &x1[1], _r, cos_bit);
+ btf_32_avx512_type1(cospi[48], cospi[16], &x1[2], &x1[3], _r, cos_bit);
+ btf_32_add_sub_avx512(&x1[4], &x1[5]);
+ btf_32_add_sub_avx512(&x1[7], &x1[6]);
+ btf_32_avx512_type0(-cospi[16], cospi[48], &x1[9], &x1[14], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[48], -cospi[16], &x1[10], &x1[13], _r, cos_bit);
+ for (int i = 0; i < 2; ++i) {
+ btf_32_add_sub_avx512(&x1[16 + i], &x1[19 - i]);
+ btf_32_add_sub_avx512(&x1[23 - i], &x1[20 + i]);
+ btf_32_add_sub_avx512(&x1[24 + i], &x1[27 - i]);
+ btf_32_add_sub_avx512(&x1[31 - i], &x1[28 + i]);
+ }
+ btf_32_avx512_type1(cospi[56], cospi[8], &x1[4], &x1[7], _r, cos_bit);
+ btf_32_avx512_type1(cospi[24], cospi[40], &x1[5], &x1[6], _r, cos_bit);
+ btf_32_add_sub_avx512(&x1[8], &x1[9]);
+ btf_32_add_sub_avx512(&x1[11], &x1[10]);
+ btf_32_add_sub_avx512(&x1[12], &x1[13]);
+ btf_32_add_sub_avx512(&x1[15], &x1[14]);
+ btf_32_avx512_type0(-cospi[8], cospi[56], &x1[17], &x1[30], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[56], -cospi[8], &x1[18], &x1[29], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[40], cospi[24], &x1[21], &x1[26], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[24], -cospi[40], &x1[22], &x1[25], _r, cos_bit);
+
+ btf_32_avx512_type1(cospi[60], cospi[4], &x1[8], &x1[15], _r, cos_bit);
+ btf_32_avx512_type1(cospi[28], cospi[36], &x1[9], &x1[14], _r, cos_bit);
+ btf_32_avx512_type1(cospi[44], cospi[20], &x1[10], &x1[13], _r, cos_bit);
+ btf_32_avx512_type1(cospi[12], cospi[52], &x1[11], &x1[12], _r, cos_bit);
+ for (int k = 16; k < 32; k += 4) {
+ btf_32_add_sub_avx512(&x1[k + 0], &x1[k + 1]);
+ btf_32_add_sub_avx512(&x1[k + 3], &x1[k + 2]);
+ }
+ btf_32_avx512_type1(cospi[62], cospi[2], &x1[16], &x1[31], _r, cos_bit);
+ btf_32_avx512_type1(cospi[30], cospi[34], &x1[17], &x1[30], _r, cos_bit);
+ btf_32_avx512_type1(cospi[46], cospi[18], &x1[18], &x1[29], _r, cos_bit);
+ btf_32_avx512_type1(cospi[14], cospi[50], &x1[19], &x1[28], _r, cos_bit);
+ btf_32_avx512_type1(cospi[54], cospi[10], &x1[20], &x1[27], _r, cos_bit);
+ btf_32_avx512_type1(cospi[22], cospi[42], &x1[21], &x1[26], _r, cos_bit);
+ btf_32_avx512_type1(cospi[38], cospi[26], &x1[22], &x1[25], _r, cos_bit);
+ btf_32_avx512_type1(cospi[6], cospi[58], &x1[23], &x1[24], _r, cos_bit);
+
+ static const uint8_t kBitRev32[32] = { 0, 16, 8, 24, 4, 20, 12, 28,
+ 2, 18, 10, 26, 6, 22, 14, 30,
+ 1, 17, 9, 25, 5, 21, 13, 29,
+ 3, 19, 11, 27, 7, 23, 15, 31 };
+ for (int i = 0; i < 32; ++i) {
+ output[i] = x1[kBitRev32[i]];
+ }
+}
+
+static inline void fdct64_new_avx512(const __m512i *input, __m512i *output,
+ int8_t cos_bit) {
+ const int32_t *cospi = cospi_arr(cos_bit);
+ const __m512i _r = _mm512_set1_epi32(1 << (cos_bit - 1));
+
+ __m512i x1[64];
+ for (int i = 0; i < 32; ++i) {
+ btf_32_add_sub_out_avx512(&x1[i], &x1[63 - i], input[i], input[63 - i]);
+ }
+ for (int i = 0; i < 16; ++i) btf_32_add_sub_avx512(&x1[i], &x1[31 - i]);
+ for (int i = 0; i < 8; ++i) {
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[40 + i], &x1[55 - i], _r,
+ cos_bit);
+ }
+ for (int i = 0; i < 8; ++i) btf_32_add_sub_avx512(&x1[i], &x1[15 - i]);
+ for (int i = 0; i < 4; ++i) {
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[20 + i], &x1[27 - i], _r,
+ cos_bit);
+ }
+ for (int i = 0; i < 8; ++i) {
+ btf_32_add_sub_avx512(&x1[32 + i], &x1[47 - i]);
+ btf_32_add_sub_avx512(&x1[63 - i], &x1[48 + i]);
+ }
+ for (int i = 0; i < 4; ++i) btf_32_add_sub_avx512(&x1[i], &x1[7 - i]);
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[10], &x1[13], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[11], &x1[12], _r, cos_bit);
+ for (int i = 0; i < 4; ++i) {
+ btf_32_add_sub_avx512(&x1[16 + i], &x1[23 - i]);
+ btf_32_add_sub_avx512(&x1[31 - i], &x1[24 + i]);
+ btf_32_avx512_type0(-cospi[16], cospi[48], &x1[36 + i], &x1[59 - i], _r,
+ cos_bit);
+ btf_32_avx512_type0(-cospi[48], -cospi[16], &x1[40 + i], &x1[55 - i], _r,
+ cos_bit);
+ }
+ btf_32_add_sub_avx512(&x1[0], &x1[3]);
+ btf_32_add_sub_avx512(&x1[1], &x1[2]);
+ btf_32_avx512_type0(-cospi[32], cospi[32], &x1[5], &x1[6], _r, cos_bit);
+ btf_32_add_sub_avx512(&x1[8], &x1[11]);
+ btf_32_add_sub_avx512(&x1[9], &x1[10]);
+ btf_32_add_sub_avx512(&x1[15], &x1[12]);
+ btf_32_add_sub_avx512(&x1[14], &x1[13]);
+ btf_32_avx512_type0(-cospi[16], cospi[48], &x1[18], &x1[29], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[16], cospi[48], &x1[19], &x1[28], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[48], -cospi[16], &x1[20], &x1[27], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[48], -cospi[16], &x1[21], &x1[26], _r, cos_bit);
+ for (int i = 0; i < 4; ++i) {
+ btf_32_add_sub_avx512(&x1[32 + i], &x1[39 - i]);
+ btf_32_add_sub_avx512(&x1[47 - i], &x1[40 + i]);
+ btf_32_add_sub_avx512(&x1[48 + i], &x1[55 - i]);
+ btf_32_add_sub_avx512(&x1[63 - i], &x1[56 + i]);
+ }
+ btf_32_avx512_type0(cospi[32], cospi[32], &x1[0], &x1[1], _r, cos_bit);
+ btf_32_avx512_type1(cospi[48], cospi[16], &x1[2], &x1[3], _r, cos_bit);
+ btf_32_add_sub_avx512(&x1[4], &x1[5]);
+ btf_32_add_sub_avx512(&x1[7], &x1[6]);
+ btf_32_avx512_type0(-cospi[16], cospi[48], &x1[9], &x1[14], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[48], -cospi[16], &x1[10], &x1[13], _r, cos_bit);
+ for (int i = 0; i < 2; ++i) {
+ btf_32_add_sub_avx512(&x1[16 + i], &x1[19 - i]);
+ btf_32_add_sub_avx512(&x1[23 - i], &x1[20 + i]);
+ btf_32_add_sub_avx512(&x1[24 + i], &x1[27 - i]);
+ btf_32_add_sub_avx512(&x1[31 - i], &x1[28 + i]);
+ btf_32_avx512_type0(-cospi[8], cospi[56], &x1[34 + i], &x1[61 - i], _r,
+ cos_bit);
+ btf_32_avx512_type0(-cospi[56], -cospi[8], &x1[36 + i], &x1[59 - i], _r,
+ cos_bit);
+ btf_32_avx512_type0(-cospi[40], cospi[24], &x1[42 + i], &x1[53 - i], _r,
+ cos_bit);
+ btf_32_avx512_type0(-cospi[24], -cospi[40], &x1[44 + i], &x1[51 - i], _r,
+ cos_bit);
+ }
+ btf_32_avx512_type1(cospi[56], cospi[8], &x1[4], &x1[7], _r, cos_bit);
+ btf_32_avx512_type1(cospi[24], cospi[40], &x1[5], &x1[6], _r, cos_bit);
+ btf_32_add_sub_avx512(&x1[8], &x1[9]);
+ btf_32_add_sub_avx512(&x1[11], &x1[10]);
+ btf_32_add_sub_avx512(&x1[12], &x1[13]);
+ btf_32_add_sub_avx512(&x1[15], &x1[14]);
+ btf_32_avx512_type0(-cospi[8], cospi[56], &x1[17], &x1[30], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[56], -cospi[8], &x1[18], &x1[29], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[40], cospi[24], &x1[21], &x1[26], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[24], -cospi[40], &x1[22], &x1[25], _r, cos_bit);
+ for (int k = 32; k < 64; k += 8) {
+ btf_32_add_sub_avx512(&x1[k + 0], &x1[k + 3]);
+ btf_32_add_sub_avx512(&x1[k + 1], &x1[k + 2]);
+ btf_32_add_sub_avx512(&x1[k + 7], &x1[k + 4]);
+ btf_32_add_sub_avx512(&x1[k + 6], &x1[k + 5]);
+ }
+ btf_32_avx512_type1(cospi[60], cospi[4], &x1[8], &x1[15], _r, cos_bit);
+ btf_32_avx512_type1(cospi[28], cospi[36], &x1[9], &x1[14], _r, cos_bit);
+ btf_32_avx512_type1(cospi[44], cospi[20], &x1[10], &x1[13], _r, cos_bit);
+ btf_32_avx512_type1(cospi[12], cospi[52], &x1[11], &x1[12], _r, cos_bit);
+ for (int k = 16; k < 32; k += 4) {
+ btf_32_add_sub_avx512(&x1[k + 0], &x1[k + 1]);
+ btf_32_add_sub_avx512(&x1[k + 3], &x1[k + 2]);
+ }
+ btf_32_avx512_type0(-cospi[4], cospi[60], &x1[33], &x1[62], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[60], -cospi[4], &x1[34], &x1[61], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[36], cospi[28], &x1[37], &x1[58], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[28], -cospi[36], &x1[38], &x1[57], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[20], cospi[44], &x1[41], &x1[54], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[44], -cospi[20], &x1[42], &x1[53], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[52], cospi[12], &x1[45], &x1[50], _r, cos_bit);
+ btf_32_avx512_type0(-cospi[12], -cospi[52], &x1[46], &x1[49], _r, cos_bit);
+
+ btf_32_avx512_type1(cospi[62], cospi[2], &x1[16], &x1[31], _r, cos_bit);
+ btf_32_avx512_type1(cospi[30], cospi[34], &x1[17], &x1[30], _r, cos_bit);
+ btf_32_avx512_type1(cospi[46], cospi[18], &x1[18], &x1[29], _r, cos_bit);
+ btf_32_avx512_type1(cospi[14], cospi[50], &x1[19], &x1[28], _r, cos_bit);
+ btf_32_avx512_type1(cospi[54], cospi[10], &x1[20], &x1[27], _r, cos_bit);
+ btf_32_avx512_type1(cospi[22], cospi[42], &x1[21], &x1[26], _r, cos_bit);
+ btf_32_avx512_type1(cospi[38], cospi[26], &x1[22], &x1[25], _r, cos_bit);
+ btf_32_avx512_type1(cospi[6], cospi[58], &x1[23], &x1[24], _r, cos_bit);
+ for (int k = 32; k < 64; k += 4) {
+ btf_32_add_sub_avx512(&x1[k + 0], &x1[k + 1]);
+ btf_32_add_sub_avx512(&x1[k + 3], &x1[k + 2]);
+ }
+ btf_32_avx512_type1(cospi[63], cospi[1], &x1[32], &x1[63], _r, cos_bit);
+ btf_32_avx512_type1(cospi[31], cospi[33], &x1[33], &x1[62], _r, cos_bit);
+ btf_32_avx512_type1(cospi[47], cospi[17], &x1[34], &x1[61], _r, cos_bit);
+ btf_32_avx512_type1(cospi[15], cospi[49], &x1[35], &x1[60], _r, cos_bit);
+ btf_32_avx512_type1(cospi[55], cospi[9], &x1[36], &x1[59], _r, cos_bit);
+ btf_32_avx512_type1(cospi[23], cospi[41], &x1[37], &x1[58], _r, cos_bit);
+ btf_32_avx512_type1(cospi[39], cospi[25], &x1[38], &x1[57], _r, cos_bit);
+ btf_32_avx512_type1(cospi[7], cospi[57], &x1[39], &x1[56], _r, cos_bit);
+ btf_32_avx512_type1(cospi[59], cospi[5], &x1[40], &x1[55], _r, cos_bit);
+ btf_32_avx512_type1(cospi[27], cospi[37], &x1[41], &x1[54], _r, cos_bit);
+ btf_32_avx512_type1(cospi[43], cospi[21], &x1[42], &x1[53], _r, cos_bit);
+ btf_32_avx512_type1(cospi[11], cospi[53], &x1[43], &x1[52], _r, cos_bit);
+ btf_32_avx512_type1(cospi[51], cospi[13], &x1[44], &x1[51], _r, cos_bit);
+ btf_32_avx512_type1(cospi[19], cospi[45], &x1[45], &x1[50], _r, cos_bit);
+ btf_32_avx512_type1(cospi[35], cospi[29], &x1[46], &x1[49], _r, cos_bit);
+ btf_32_avx512_type1(cospi[3], cospi[61], &x1[47], &x1[48], _r, cos_bit);
+
+ static const uint8_t kBitRev64[64] = {
+ 0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60,
+ 2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62,
+ 1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61,
+ 3, 35, 19, 51, 11, 43, 27, 59, 7, 39, 23, 55, 15, 47, 31, 63
+ };
+ for (int i = 0; i < 64; ++i) {
+ output[i] = x1[kBitRev64[i]];
+ }
+}
+
+typedef void (*transform_1d_avx512)(const __m512i *input, __m512i *output,
+ int8_t cos_bit);
+
+static const transform_1d_avx512 col_txfm32x32_arr[TX_TYPES] = {
+ fdct32x32_avx512, // DCT_DCT
+ NULL, // ADST_DCT
+ NULL, // DCT_ADST
+ NULL, // ADST_ADST
+ NULL, // FLIPADST_DCT
+ NULL, // DCT_FLIPADST
+ NULL, // FLIPADST_FLIPADST
+ NULL, // ADST_FLIPADST
+ NULL, // FLIPADST_ADST
+ fidentity32x32_avx512, // IDTX
+ fdct32x32_avx512, // V_DCT
+ fidentity32x32_avx512, // H_DCT
+ NULL, // V_ADST
+ NULL, // H_ADST
+ NULL, // V_FLIPADST
+ NULL // H_FLIPADST
+};
+
+static const transform_1d_avx512 row_txfm32x32_arr[TX_TYPES] = {
+ fdct32x32_avx512, // DCT_DCT
+ NULL, // ADST_DCT
+ NULL, // DCT_ADST
+ NULL, // ADST_ADST
+ NULL, // FLIPADST_DCT
+ NULL, // DCT_FLIPADST
+ NULL, // FLIPADST_FLIPADST
+ NULL, // ADST_FLIPADST
+ NULL, // FLIPADST_ADST
+ fidentity32x32_avx512, // IDTX
+ fidentity32x32_avx512, // V_DCT
+ fdct32x32_avx512, // H_DCT
+ NULL, // V_ADST
+ NULL, // H_ADST
+ NULL, // V_FLIPADST
+ NULL // H_FLIPADST
+};
+
+static const transform_1d_avx512 col_txfm32x16_arr[TX_TYPES] = {
+ fdct32x16_new_avx512, // DCT_DCT
+ fadst32x16_new_avx512, // ADST_DCT
+ fdct32x16_new_avx512, // DCT_ADST
+ fadst32x16_new_avx512, // ADST_ADST
+ fadst32x16_new_avx512, // FLIPADST_DCT
+ fdct32x16_new_avx512, // DCT_FLIPADST
+ fadst32x16_new_avx512, // FLIPADST_FLIPADST
+ fadst32x16_new_avx512, // ADST_FLIPADST
+ fadst32x16_new_avx512, // FLIPADST_ADST
+ fidentity32x16_new_avx512, // IDTX
+ fdct32x16_new_avx512, // V_DCT
+ fidentity32x16_new_avx512, // H_DCT
+ fadst32x16_new_avx512, // V_ADST
+ fidentity32x16_new_avx512, // H_ADST
+ fadst32x16_new_avx512, // V_FLIPADST
+ fidentity32x16_new_avx512 // H_FLIPADST
+};
+
+static const transform_1d_avx512 row_txfm32x16_arr[TX_TYPES] = {
+ fdct32x16_new_avx512, // DCT_DCT
+ fdct32x16_new_avx512, // ADST_DCT
+ fadst32x16_new_avx512, // DCT_ADST
+ fadst32x16_new_avx512, // ADST_ADST
+ fdct32x16_new_avx512, // FLIPADST_DCT
+ fadst32x16_new_avx512, // DCT_FLIPADST
+ fadst32x16_new_avx512, // FLIPADST_FLIPADST
+ fadst32x16_new_avx512, // ADST_FLIPADST
+ fadst32x16_new_avx512, // FLIPADST_ADST
+ fidentity32x16_new_avx512, // IDTX
+ fidentity32x16_new_avx512, // V_DCT
+ fdct32x16_new_avx512, // H_DCT
+ fidentity32x16_new_avx512, // V_ADST
+ fadst32x16_new_avx512, // H_ADST
+ fidentity32x16_new_avx512, // V_FLIPADST
+ fadst32x16_new_avx512 // H_FLIPADST
+};
+
+static void lowbd_fwd_txfm2d_16x16_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ const TX_SIZE tx_size = TX_16X16;
+ __m512i buf512[16];
+ __m256i buf0[16], buf1[16];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[tx_size];
+ const int txw_idx = get_txw_idx(tx_size);
+ const int txh_idx = get_txh_idx(tx_size);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+ const transform_1d_avx512 col_txfm = col_txfm32x16_arr[tx_type];
+ const transform_1d_avx512 row_txfm = row_txfm32x16_arr[tx_type];
+ int ud_flip, lr_flip;
+ get_flip_cfg(tx_type, &ud_flip, &lr_flip);
+
+ for (int i = 0; i < 16; ++i) {
+ const int r = ud_flip ? (15 - i) : i;
+ buf512[i] = _mm512_castsi256_si512(
+ _mm256_loadu_si256((const __m256i *)(input + r * stride)));
+ }
+ round_shift_16bit_w32_avx512(buf512, 16, shift[0]);
+ col_txfm(buf512, buf512, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf512, 16, shift[1]);
+ for (int i = 0; i < 16; ++i) buf0[i] = _mm512_castsi512_si256(buf512[i]);
+ transpose_16bit_16x16_avx2(buf0, buf1);
+
+ for (int i = 0; i < 16; ++i) {
+ const int r = lr_flip ? (15 - i) : i;
+ buf512[i] = _mm512_castsi256_si512(buf1[r]);
+ }
+ row_txfm(buf512, buf512, cos_bit_row);
+ round_shift_16bit_w32_avx512(buf512, 16, shift[2]);
+ for (int i = 0; i < 16; ++i) buf0[i] = _mm512_castsi512_si256(buf512[i]);
+ store_buffer_16bit_to_32bit_w16_avx512(buf0, output, 16, 16);
+}
+
+static void lowbd_fwd_txfm2d_32x32_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ const TX_SIZE tx_size = TX_32X32;
+ __m512i buf0[32], buf_row[32];
+ __m256i buf1[64];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[tx_size];
+ const int txw_idx = get_txw_idx(tx_size);
+ const int txh_idx = get_txh_idx(tx_size);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+ const transform_1d_avx512 col_txfm = col_txfm32x32_arr[tx_type];
+ const transform_1d_avx512 row_txfm = row_txfm32x32_arr[tx_type];
+ int ud_flip, lr_flip;
+ get_flip_cfg(tx_type, &ud_flip, &lr_flip);
+
+ if (ud_flip) {
+ load_buffer_16bit_to_16bit_w32_flip_avx512(input, stride, buf0, 32);
+ } else {
+ load_buffer_16bit_to_16bit_w32_avx512(input, stride, buf0, 32);
+ }
+ round_shift_16bit_w32_avx512(buf0, 32, shift[0]);
+ col_txfm(buf0, buf0, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf0, 32, shift[1]);
+ transpose_two_16bit_16x16_avx512(buf0 + 0, buf1 + 0, buf1 + 16);
+ transpose_two_16bit_16x16_avx512(buf0 + 16, buf1 + 32, buf1 + 48);
+
+ for (int i = 0; i < 32; ++i) {
+ const int idx = lr_flip ? (31 - i) : i;
+ buf_row[i] = _mm512_inserti64x4(_mm512_castsi256_si512(buf1[idx]),
+ buf1[32 + idx], 1);
+ }
+ row_txfm(buf_row, buf_row, cos_bit_row);
+ round_shift_16bit_w32_avx512(buf_row, 32, shift[2]);
+ store_two_buffers_16bit_to_32bit_w16_avx512(buf_row, output, output + 16, 32,
+ 32);
+}
+
+static void lowbd_fwd_txfm2d_64x64_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ (void)tx_type;
+ assert(tx_type == DCT_DCT);
+ const TX_SIZE tx_size = TX_64X64;
+ __m512i buf0[64];
+ __m256i buf1[128];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[tx_size];
+ const int txw_idx = get_txw_idx(tx_size);
+ const int txh_idx = get_txh_idx(tx_size);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+
+ for (int i = 0; i < 2; ++i) {
+ load_buffer_16bit_to_16bit_w32_avx512(input + 32 * i, stride, buf0, 64);
+ round_shift_16bit_w32_avx512(buf0, 64, shift[0]);
+ fdct32x64_new_avx512(buf0, buf0, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf0, 64, shift[1]);
+ for (int j = 0; j < 2; ++j) {
+ transpose_two_16bit_16x16_avx512(buf0 + j * 16, buf1 + j * 64 + 32 * i,
+ buf1 + j * 64 + 32 * i + 16);
+ }
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ __m512i buf_row[64];
+ const __m256i *src = buf1 + 64 * i;
+ for (int j = 0; j < 64; ++j) {
+ buf_row[j] = _mm512_cvtepi16_epi32(src[j]);
+ }
+ fdct64_new_avx512(buf_row, buf_row, cos_bit_row);
+ round_shift_array_32_avx512(buf_row, buf_row, 32, -shift[2]);
+ store_output_32bit_w16_avx512(output + i * 16, buf_row, 32, 32);
+ }
+}
+
+static void lowbd_fwd_txfm2d_16x32_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ const TX_SIZE tx_size = TX_16X32;
+ __m512i buf512[32], buf_row[16];
+ __m256i buf0[32], buf1[32];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[tx_size];
+ const int txw_idx = get_txw_idx(tx_size);
+ const int txh_idx = get_txh_idx(tx_size);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+ const transform_1d_avx512 col_txfm = col_txfm32x32_arr[tx_type];
+ const transform_1d_avx512 row_txfm = row_txfm32x16_arr[tx_type];
+ int ud_flip, lr_flip;
+ get_flip_cfg(tx_type, &ud_flip, &lr_flip);
+
+ for (int i = 0; i < 32; ++i) {
+ const int r = ud_flip ? (31 - i) : i;
+ buf512[i] = _mm512_castsi256_si512(
+ _mm256_loadu_si256((const __m256i *)(input + r * stride)));
+ }
+ round_shift_16bit_w32_avx512(buf512, 32, shift[0]);
+ col_txfm(buf512, buf512, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf512, 32, shift[1]);
+ for (int i = 0; i < 32; ++i) buf0[i] = _mm512_castsi512_si256(buf512[i]);
+ transpose_16bit_16x16_avx2(buf0, buf1);
+ transpose_16bit_16x16_avx2(buf0 + 16, buf1 + 16);
+
+ for (int i = 0; i < 16; ++i) {
+ const int idx = lr_flip ? (15 - i) : i;
+ buf_row[i] = _mm512_inserti64x4(_mm512_castsi256_si512(buf1[idx]),
+ buf1[16 + idx], 1);
+ }
+ row_txfm(buf_row, buf_row, cos_bit_row);
+ round_shift_16bit_w32_avx512(buf_row, 16, shift[2]);
+ store_two_rect_buffers_16bit_to_32bit_w16_avx512(buf_row, output, output + 16,
+ 32, 16);
+}
+
+static void lowbd_fwd_txfm2d_32x16_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ __m512i buf0[32];
+ __m256i buf1[32];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[TX_32X16];
+ const int txw_idx = get_txw_idx(TX_32X16);
+ const int txh_idx = get_txh_idx(TX_32X16);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+ const transform_1d_avx512 col_txfm = col_txfm32x16_arr[tx_type];
+ const transform_1d_avx512 row_txfm = row_txfm32x32_arr[tx_type];
+ int ud_flip, lr_flip;
+ get_flip_cfg(tx_type, &ud_flip, &lr_flip);
+
+ if (ud_flip) {
+ load_buffer_16bit_to_16bit_w32_flip_avx512(input, stride, buf0, 16);
+ } else {
+ load_buffer_16bit_to_16bit_w32_avx512(input, stride, buf0, 16);
+ }
+ round_shift_16bit_w32_avx512(buf0, 16, shift[0]);
+ col_txfm(buf0, buf0, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf0, 16, shift[1]);
+ transpose_two_16bit_16x16_avx512(buf0, buf1, buf1 + 16);
+
+ for (int i = 0; i < 32; ++i) {
+ const int idx = lr_flip ? (31 - i) : i;
+ buf0[i] = _mm512_castsi256_si512(buf1[idx]);
+ }
+ row_txfm(buf0, buf0, cos_bit_row);
+ round_shift_16bit_w32_avx512(buf0, 32, shift[2]);
+ for (int i = 0; i < 32; ++i) buf1[i] = _mm512_castsi512_si256(buf0[i]);
+ store_rect_buffer_16bit_to_32bit_w16_avx512(buf1, output, 16, 32);
+}
+
+static void lowbd_fwd_txfm2d_64x32_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ assert(tx_type == DCT_DCT);
+ const TX_SIZE tx_size = TX_64X32;
+ __m512i buf0[32];
+ __m256i buf1[128];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[tx_size];
+ const int txw_idx = get_txw_idx(tx_size);
+ const int txh_idx = get_txh_idx(tx_size);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+ const transform_1d_avx512 col_txfm = col_txfm32x32_arr[tx_type];
+
+ for (int i = 0; i < 2; ++i) {
+ load_buffer_16bit_to_16bit_w32_avx512(input + 32 * i, stride, buf0, 32);
+ round_shift_16bit_w32_avx512(buf0, 32, shift[0]);
+ col_txfm(buf0, buf0, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf0, 32, shift[1]);
+ for (int j = 0; j < 2; ++j) {
+ transpose_two_16bit_16x16_avx512(buf0 + j * 16, buf1 + j * 64 + 32 * i,
+ buf1 + j * 64 + 32 * i + 16);
+ }
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ __m512i buf_row[64];
+ const __m256i *src = buf1 + 64 * i;
+ for (int j = 0; j < 64; ++j) {
+ buf_row[j] = _mm512_cvtepi16_epi32(src[j]);
+ }
+ fdct64_new_avx512(buf_row, buf_row, cos_bit_row);
+ round_shift_rect_array_32_avx512(buf_row, buf_row, 32, -shift[2], NewSqrt2);
+ store_output_32bit_w16_avx512(output + i * 16, buf_row, 32, 32);
+ }
+}
+
+static void lowbd_fwd_txfm2d_32x64_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ (void)tx_type;
+ assert(tx_type == DCT_DCT);
+ const TX_SIZE tx_size = TX_32X64;
+ __m512i buf0[64];
+ __m256i buf1[64];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[tx_size];
+ const int txw_idx = get_txw_idx(tx_size);
+ const int txh_idx = get_txh_idx(tx_size);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+
+ load_buffer_16bit_to_16bit_w32_avx512(input, stride, buf0, 64);
+ round_shift_16bit_w32_avx512(buf0, 64, shift[0]);
+ fdct32x64_new_avx512(buf0, buf0, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf0, 64, shift[1]);
+ for (int j = 0; j < 2; ++j) {
+ transpose_two_16bit_16x16_avx512(buf0 + j * 16, buf1 + j * 32,
+ buf1 + j * 32 + 16);
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ __m512i buf_row[32];
+ const __m256i *src = buf1 + 32 * i;
+ for (int j = 0; j < 32; ++j) {
+ buf_row[j] = _mm512_cvtepi16_epi32(src[j]);
+ }
+ fdct32_avx512(buf_row, buf_row, cos_bit_row);
+ round_shift_rect_array_32_avx512(buf_row, buf_row, 32, -shift[2], NewSqrt2);
+ store_output_32bit_w16_avx512(output + i * 16, buf_row, 32, 32);
+ }
+}
+
+static void lowbd_fwd_txfm2d_16x64_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ (void)tx_type;
+ assert(tx_type == DCT_DCT);
+ const TX_SIZE tx_size = TX_16X64;
+ __m512i buf512[64], buf_row[16];
+ __m256i buf0[32], buf1[32];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[tx_size];
+ const int txw_idx = get_txw_idx(tx_size);
+ const int txh_idx = get_txh_idx(tx_size);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+
+ for (int i = 0; i < 64; ++i) {
+ buf512[i] = _mm512_castsi256_si512(
+ _mm256_loadu_si256((const __m256i *)(input + i * stride)));
+ }
+ round_shift_16bit_w32_avx512(buf512, 64, shift[0]);
+ fdct32x64_new_avx512(buf512, buf512, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf512, 64, shift[1]);
+ for (int i = 0; i < 32; ++i) buf0[i] = _mm512_castsi512_si256(buf512[i]);
+ transpose_16bit_16x16_avx2(buf0, buf1);
+ transpose_16bit_16x16_avx2(buf0 + 16, buf1 + 16);
+
+ for (int i = 0; i < 16; ++i) {
+ buf_row[i] =
+ _mm512_inserti64x4(_mm512_castsi256_si512(buf1[i]), buf1[16 + i], 1);
+ }
+ fdct32x16_new_avx512(buf_row, buf_row, cos_bit_row);
+ round_shift_16bit_w32_avx512(buf_row, 16, shift[2]);
+ store_two_buffers_16bit_to_32bit_w16_avx512(buf_row, output, output + 16, 32,
+ 16);
+}
+
+static void lowbd_fwd_txfm2d_64x16_avx512(const int16_t *input, int32_t *output,
+ int stride, TX_TYPE tx_type, int bd) {
+ (void)bd;
+ (void)tx_type;
+ assert(tx_type == DCT_DCT);
+ const TX_SIZE tx_size = TX_64X16;
+ __m512i buf0[64];
+ __m256i buf1[64];
+ const int8_t *shift = av1_fwd_txfm_shift_ls[tx_size];
+ const int txw_idx = get_txw_idx(tx_size);
+ const int txh_idx = get_txh_idx(tx_size);
+ const int cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx];
+ const int cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx];
+
+ for (int i = 0; i < 2; ++i) {
+ load_buffer_16bit_to_16bit_w32_avx512(input + 32 * i, stride, buf0, 16);
+ round_shift_16bit_w32_avx512(buf0, 16, shift[0]);
+ fdct32x16_new_avx512(buf0, buf0, cos_bit_col);
+ round_shift_16bit_w32_avx512(buf0, 16, shift[1]);
+ transpose_two_16bit_16x16_avx512(buf0, buf1 + 32 * i, buf1 + 32 * i + 16);
+ }
+
+ for (int i = 0; i < 64; ++i) {
+ buf0[i] = _mm512_castsi256_si512(buf1[i]);
+ }
+ fdct32x64_new_avx512(buf0, buf0, cos_bit_row);
+ round_shift_16bit_w32_avx512(buf0, 64, shift[2]);
+ for (int i = 0; i < 32; ++i) buf1[i] = _mm512_castsi512_si256(buf0[i]);
+ store_buffer_16bit_to_32bit_w16_avx512(buf1, output, 16, 32);
+ memset(output + 16 * 32, 0, 16 * 32 * sizeof(*output));
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+__attribute__((force_align_arg_pointer))
+#endif
+void av1_lowbd_fwd_txfm_avx512(const int16_t *src_diff, tran_low_t *coeff,
+ int diff_stride, TxfmParam *txfm_param) {
+ volatile __m512i stack_align_guard = _mm512_setzero_si512();
+ (void)stack_align_guard;
+ if (txfm_param->lossless && txfm_param->tx_size == TX_4X4) {
+ av1_lowbd_fwd_txfm_c(src_diff, coeff, diff_stride, txfm_param);
+ return;
+ }
+ switch (txfm_param->tx_size) {
+ case TX_16X16:
+ lowbd_fwd_txfm2d_16x16_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ case TX_32X32:
+ lowbd_fwd_txfm2d_32x32_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ case TX_64X64:
+ lowbd_fwd_txfm2d_64x64_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ case TX_16X32:
+ lowbd_fwd_txfm2d_16x32_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ case TX_32X16:
+ lowbd_fwd_txfm2d_32x16_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ case TX_32X64:
+ lowbd_fwd_txfm2d_32x64_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ case TX_64X32:
+ lowbd_fwd_txfm2d_64x32_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ case TX_16X64:
+ lowbd_fwd_txfm2d_16x64_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ case TX_64X16:
+ lowbd_fwd_txfm2d_64x16_avx512(src_diff, coeff, diff_stride,
+ txfm_param->tx_type, txfm_param->bd);
+ break;
+ default:
+ av1_lowbd_fwd_txfm_avx2(src_diff, coeff, diff_stride, txfm_param);
+ break;
+ }
+}
+
+#endif // !CONFIG_HIGHWAY
diff --git a/av1/encoder/x86/av1_fwd_txfm_avx512.h b/av1/encoder/x86/av1_fwd_txfm_avx512.h
new file mode 100644
index 0000000000..a6fd6f82b0
--- /dev/null
+++ b/av1/encoder/x86/av1_fwd_txfm_avx512.h
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#ifndef AOM_AV1_ENCODER_X86_AV1_FWD_TXFM_AVX512_H_
+#define AOM_AV1_ENCODER_X86_AV1_FWD_TXFM_AVX512_H_
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <immintrin.h>
+
+#include "aom/aom_integer.h"
+#include "aom_dsp/x86/txfm_common_avx2.h"
+#include "av1/common/av1_txfm.h"
+#include "av1/encoder/av1_fwd_txfm1d_cfg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline __m512i pair_set_w32_epi16(int16_t a, int16_t b) {
+ return _mm512_set1_epi32(
+ (int32_t)(((uint16_t)(a)) | (((uint32_t)(uint16_t)(b)) << 16)));
+}
+
+static inline void btf_16_w32_avx512(const __m512i w0, const __m512i w1,
+ __m512i *in0, __m512i *in1,
+ const __m512i _r, const int32_t cos_bit) {
+ const __m512i t0 = _mm512_unpacklo_epi16(*in0, *in1);
+ const __m512i t1 = _mm512_unpackhi_epi16(*in0, *in1);
+ const __m512i u0 = _mm512_madd_epi16(t0, w0);
+ const __m512i u1 = _mm512_madd_epi16(t1, w0);
+ const __m512i v0 = _mm512_madd_epi16(t0, w1);
+ const __m512i v1 = _mm512_madd_epi16(t1, w1);
+
+ const __m512i a0 = _mm512_add_epi32(u0, _r);
+ const __m512i a1 = _mm512_add_epi32(u1, _r);
+ const __m512i b0 = _mm512_add_epi32(v0, _r);
+ const __m512i b1 = _mm512_add_epi32(v1, _r);
+
+ const __m512i c0 = _mm512_srai_epi32(a0, (unsigned int)cos_bit);
+ const __m512i c1 = _mm512_srai_epi32(a1, (unsigned int)cos_bit);
+ const __m512i d0 = _mm512_srai_epi32(b0, (unsigned int)cos_bit);
+ const __m512i d1 = _mm512_srai_epi32(b1, (unsigned int)cos_bit);
+
+ *in0 = _mm512_packs_epi32(c0, c1);
+ *in1 = _mm512_packs_epi32(d0, d1);
+}
+
+static inline void btf_16_adds_subs_avx512(__m512i *in0, __m512i *in1) {
+ const __m512i _in0 = *in0;
+ const __m512i _in1 = *in1;
+ *in0 = _mm512_adds_epi16(_in0, _in1);
+ *in1 = _mm512_subs_epi16(_in0, _in1);
+}
+
+static inline void btf_32_add_sub_avx512(__m512i *in0, __m512i *in1) {
+ const __m512i _in0 = *in0;
+ const __m512i _in1 = *in1;
+ *in0 = _mm512_add_epi32(_in0, _in1);
+ *in1 = _mm512_sub_epi32(_in0, _in1);
+}
+
+static inline void btf_16_adds_subs_out_avx512(__m512i *out0, __m512i *out1,
+ __m512i in0, __m512i in1) {
+ *out0 = _mm512_adds_epi16(in0, in1);
+ *out1 = _mm512_subs_epi16(in0, in1);
+}
+
+static inline void btf_32_add_sub_out_avx512(__m512i *out0, __m512i *out1,
+ __m512i in0, __m512i in1) {
+ *out0 = _mm512_add_epi32(in0, in1);
+ *out1 = _mm512_sub_epi32(in0, in1);
+}
+
+// out0 = in0*w0 + in1*w1
+// out1 = -in1*w0 + in0*w1
+static inline void btf_32_avx512_type0(const int32_t w0, const int32_t w1,
+ __m512i *in0, __m512i *in1,
+ const __m512i _r,
+ const int32_t cos_bit) {
+ const __m512i _in0 = *in0;
+ const __m512i _in1 = *in1;
+ const __m512i ww0 = _mm512_set1_epi32(w0);
+ const __m512i ww1 = _mm512_set1_epi32(w1);
+ const __m512i in0_w0 = _mm512_mullo_epi32(_in0, ww0);
+ const __m512i in1_w1 = _mm512_mullo_epi32(_in1, ww1);
+ __m512i temp0 = _mm512_add_epi32(in0_w0, in1_w1);
+ temp0 = _mm512_add_epi32(temp0, _r);
+ *in0 = _mm512_srai_epi32(temp0, (unsigned int)cos_bit);
+ const __m512i in0_w1 = _mm512_mullo_epi32(_in0, ww1);
+ const __m512i in1_w0 = _mm512_mullo_epi32(_in1, ww0);
+ __m512i temp1 = _mm512_sub_epi32(in0_w1, in1_w0);
+ temp1 = _mm512_add_epi32(temp1, _r);
+ *in1 = _mm512_srai_epi32(temp1, (unsigned int)cos_bit);
+}
+
+// out0 = in0*w0 + in1*w1
+// out1 = in1*w0 - in0*w1
+static inline void btf_32_avx512_type1(const int32_t w0, const int32_t w1,
+ __m512i *in0, __m512i *in1,
+ const __m512i _r,
+ const int32_t cos_bit) {
+ const __m512i _in0 = *in0;
+ const __m512i _in1 = *in1;
+ const __m512i ww0 = _mm512_set1_epi32(w0);
+ const __m512i ww1 = _mm512_set1_epi32(w1);
+ const __m512i in0_w0 = _mm512_mullo_epi32(_in0, ww0);
+ const __m512i in1_w1 = _mm512_mullo_epi32(_in1, ww1);
+ __m512i temp0 = _mm512_add_epi32(in0_w0, in1_w1);
+ temp0 = _mm512_add_epi32(temp0, _r);
+ *in0 = _mm512_srai_epi32(temp0, (unsigned int)cos_bit);
+ const __m512i in0_w1 = _mm512_mullo_epi32(_in0, ww1);
+ const __m512i in1_w0 = _mm512_mullo_epi32(_in1, ww0);
+ __m512i temp1 = _mm512_sub_epi32(in1_w0, in0_w1);
+ temp1 = _mm512_add_epi32(temp1, _r);
+ *in1 = _mm512_srai_epi32(temp1, (unsigned int)cos_bit);
+}
+
+static inline void btf_32_avx512_type0_new(const __m512i ww0, const __m512i ww1,
+ __m512i *in0, __m512i *in1,
+ const __m512i _r,
+ const int32_t cos_bit) {
+ const __m512i _in0 = *in0;
+ const __m512i _in1 = *in1;
+ const __m512i in0_w0 = _mm512_mullo_epi32(_in0, ww0);
+ const __m512i in1_w1 = _mm512_mullo_epi32(_in1, ww1);
+ __m512i temp0 = _mm512_add_epi32(in0_w0, in1_w1);
+ temp0 = _mm512_add_epi32(temp0, _r);
+ *in0 = _mm512_srai_epi32(temp0, (unsigned int)cos_bit);
+ const __m512i in0_w1 = _mm512_mullo_epi32(_in0, ww1);
+ const __m512i in1_w0 = _mm512_mullo_epi32(_in1, ww0);
+ __m512i temp1 = _mm512_sub_epi32(in0_w1, in1_w0);
+ temp1 = _mm512_add_epi32(temp1, _r);
+ *in1 = _mm512_srai_epi32(temp1, (unsigned int)cos_bit);
+}
+
+static inline void btf_32_avx512_type1_new(const __m512i ww0, const __m512i ww1,
+ __m512i *in0, __m512i *in1,
+ const __m512i _r,
+ const int32_t cos_bit) {
+ const __m512i _in0 = *in0;
+ const __m512i _in1 = *in1;
+ const __m512i in0_w0 = _mm512_mullo_epi32(_in0, ww0);
+ const __m512i in1_w1 = _mm512_mullo_epi32(_in1, ww1);
+ __m512i temp0 = _mm512_add_epi32(in0_w0, in1_w1);
+ temp0 = _mm512_add_epi32(temp0, _r);
+ *in0 = _mm512_srai_epi32(temp0, (unsigned int)cos_bit);
+ const __m512i in0_w1 = _mm512_mullo_epi32(_in0, ww1);
+ const __m512i in1_w0 = _mm512_mullo_epi32(_in1, ww0);
+ __m512i temp1 = _mm512_sub_epi32(in1_w0, in0_w1);
+ temp1 = _mm512_add_epi32(temp1, _r);
+ *in1 = _mm512_srai_epi32(temp1, (unsigned int)cos_bit);
+}
+
+static inline __m512i scale_round_avx512(const __m512i a, const int scale) {
+ const __m512i scale_rounding =
+ pair_set_w32_epi16(scale, 1 << (NewSqrt2Bits - 1));
+ const __m512i b = _mm512_madd_epi16(a, scale_rounding);
+ return _mm512_srai_epi32(b, NewSqrt2Bits);
+}
+
+static inline void load_buffer_16bit_to_16bit_w32_avx512(const int16_t *in,
+ int stride,
+ __m512i *out,
+ int out_size) {
+ for (int i = 0; i < out_size; ++i) {
+ out[i] = _mm512_loadu_si512((const __m512i *)(in + i * stride));
+ }
+}
+
+static inline void load_buffer_16bit_to_16bit_w32_flip_avx512(const int16_t *in,
+ int stride,
+ __m512i *out,
+ int out_size) {
+ for (int i = 0; i < out_size; ++i) {
+ out[out_size - i - 1] =
+ _mm512_loadu_si512((const __m512i *)(in + i * stride));
+ }
+}
+
+// Pack two 16-wide strips separated by `strip_stride` int16_t elements into
+// a single 32-wide __m512i array.
+static inline void load_two_buffers_16bit_to_16bit_w32_avx512(
+ const int16_t *in0, const int16_t *in1, int stride, __m512i *out,
+ int out_size) {
+ for (int i = 0; i < out_size; ++i) {
+ const __m256i v0 = _mm256_loadu_si256((const __m256i *)(in0 + i * stride));
+ const __m256i v1 = _mm256_loadu_si256((const __m256i *)(in1 + i * stride));
+ out[i] = _mm512_inserti64x4(_mm512_castsi256_si512(v0), v1, 1);
+ }
+}
+
+static inline void load_two_buffers_16bit_to_16bit_w32_flip_avx512(
+ const int16_t *in0, const int16_t *in1, int stride, __m512i *out,
+ int out_size) {
+ for (int i = 0; i < out_size; ++i) {
+ const __m256i v0 = _mm256_loadu_si256((const __m256i *)(in0 + i * stride));
+ const __m256i v1 = _mm256_loadu_si256((const __m256i *)(in1 + i * stride));
+ out[out_size - i - 1] =
+ _mm512_inserti64x4(_mm512_castsi256_si512(v0), v1, 1);
+ }
+}
+
+static inline void round_shift_16bit_w32_avx512(__m512i *in, int size,
+ int bit) {
+ if (bit < 0) {
+ bit = -bit;
+ const __m512i round = _mm512_set1_epi16(1 << (bit - 1));
+ for (int i = 0; i < size; ++i) {
+ in[i] = _mm512_adds_epi16(in[i], round);
+ in[i] = _mm512_srai_epi16(in[i], (unsigned int)bit);
+ }
+ } else if (bit > 0) {
+ for (int i = 0; i < size; ++i) {
+ in[i] = _mm512_slli_epi16(in[i], (unsigned int)bit);
+ }
+ }
+}
+
+static inline __m512i round_shift_32_avx512(__m512i vec, int bit) {
+ const __m512i round = _mm512_set1_epi32(1 << (bit - 1));
+ const __m512i tmp = _mm512_add_epi32(vec, round);
+ return _mm512_srai_epi32(tmp, (unsigned int)bit);
+}
+
+static inline void round_shift_array_32_avx512(__m512i *input, __m512i *output,
+ const int size, const int bit) {
+ if (bit > 0) {
+ for (int i = 0; i < size; i++) {
+ output[i] = round_shift_32_avx512(input[i], bit);
+ }
+ } else {
+ for (int i = 0; i < size; i++) {
+ output[i] = _mm512_slli_epi32(input[i], (unsigned int)(-bit));
+ }
+ }
+}
+
+static inline void round_shift_rect_array_32_avx512(__m512i *input,
+ __m512i *output,
+ const int size,
+ const int bit,
+ const int val) {
+ const __m512i sqrt2 = _mm512_set1_epi32(val);
+ if (bit > 0) {
+ for (int i = 0; i < size; i++) {
+ const __m512i r0 = round_shift_32_avx512(input[i], bit);
+ const __m512i r1 = _mm512_mullo_epi32(sqrt2, r0);
+ output[i] = round_shift_32_avx512(r1, NewSqrt2Bits);
+ }
+ } else {
+ for (int i = 0; i < size; i++) {
+ const __m512i r0 = _mm512_slli_epi32(input[i], (unsigned int)(-bit));
+ const __m512i r1 = _mm512_mullo_epi32(sqrt2, r0);
+ output[i] = round_shift_32_avx512(r1, NewSqrt2Bits);
+ }
+ }
+}
+
+static inline void store_output_32bit_w16_avx512(int32_t *const out,
+ const __m512i *const in,
+ const int stride,
+ const int out_size) {
+ for (int i = 0; i < out_size; ++i) {
+ _mm512_storeu_si512((__m512i *)(out + stride * i),
+ _mm512_loadu_si512((const __m512i *)&in[i]));
+ }
+}
+
+static inline void store_buffer_16bit_to_32bit_w16_avx512(
+ const __m256i *const in, int32_t *out, const int stride,
+ const int out_size) {
+ for (int i = 0; i < out_size; ++i) {
+ _mm512_storeu_si512((__m512i *)out, _mm512_cvtepi16_epi32(in[i]));
+ out += stride;
+ }
+}
+
+// Store 32-wide __m512i (two 16-wide strips in low 256-bit and high 256-bit)
+// into `out0` and `out1`.
+static inline void store_two_buffers_16bit_to_32bit_w16_avx512(
+ const __m512i *const in, int32_t *out0, int32_t *out1, const int stride,
+ const int out_size) {
+ for (int i = 0; i < out_size; ++i) {
+ const __m256i lo = _mm512_castsi512_si256(in[i]);
+ const __m256i hi = _mm512_extracti64x4_epi64(in[i], 1);
+ _mm512_storeu_si512((__m512i *)(out0 + i * stride),
+ _mm512_cvtepi16_epi32(lo));
+ _mm512_storeu_si512((__m512i *)(out1 + i * stride),
+ _mm512_cvtepi16_epi32(hi));
+ }
+}
+
+static inline void store_rect_16bit_to_32bit_w16_avx512(const __m256i a,
+ int32_t *const b) {
+ const __m512i a_32 = _mm512_cvtepi16_epi32(a);
+ const __m512i sqrt2 = _mm512_set1_epi32(NewSqrt2);
+ const __m512i prod = _mm512_mullo_epi32(a_32, sqrt2);
+ const __m512i res = round_shift_32_avx512(prod, NewSqrt2Bits);
+ _mm512_storeu_si512((__m512i *)b, res);
+}
+
+static inline void store_rect_buffer_16bit_to_32bit_w16_avx512(
+ const __m256i *const in, int32_t *const out, const int stride,
+ const int out_size) {
+ for (int i = 0; i < out_size; ++i) {
+ store_rect_16bit_to_32bit_w16_avx512(in[i], out + i * stride);
+ }
+}
+
+static inline void store_two_rect_buffers_16bit_to_32bit_w16_avx512(
+ const __m512i *const in, int32_t *const out0, int32_t *const out1,
+ const int stride, const int out_size) {
+ const __m512i sqrt2 = _mm512_set1_epi32(NewSqrt2);
+ for (int i = 0; i < out_size; ++i) {
+ const __m256i lo = _mm512_castsi512_si256(in[i]);
+ const __m256i hi = _mm512_extracti64x4_epi64(in[i], 1);
+ const __m512i lo_32 = _mm512_cvtepi16_epi32(lo);
+ const __m512i hi_32 = _mm512_cvtepi16_epi32(hi);
+ const __m512i res0 =
+ round_shift_32_avx512(_mm512_mullo_epi32(lo_32, sqrt2), NewSqrt2Bits);
+ const __m512i res1 =
+ round_shift_32_avx512(_mm512_mullo_epi32(hi_32, sqrt2), NewSqrt2Bits);
+ _mm512_storeu_si512((__m512i *)(out0 + i * stride), res0);
+ _mm512_storeu_si512((__m512i *)(out1 + i * stride), res1);
+ }
+}
+
+// Transpose two 16x16 blocks held in the low 256-bit and high 256-bit halves
+// of `in[0..15]` into `out0[0..15]` and `out1[0..15]` (each 256-bit).
+static inline void transpose_two_16bit_16x16_avx512(const __m512i *const in,
+ __m256i *const out0,
+ __m256i *const out1) {
+ __m256i in_lo[16], in_hi[16];
+ for (int i = 0; i < 16; ++i) {
+ in_lo[i] = _mm512_castsi512_si256(in[i]);
+ in_hi[i] = _mm512_extracti64x4_epi64(in[i], 1);
+ }
+ transpose_16bit_16x16_avx2(in_lo, out0);
+ transpose_16bit_16x16_avx2(in_hi, out1);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // AOM_AV1_ENCODER_X86_AV1_FWD_TXFM_AVX512_H_
diff --git a/av1/encoder/x86/av1_quantize_avx512.c b/av1/encoder/x86/av1_quantize_avx512.c
new file mode 100644
index 0000000000..c4d64c8c65
--- /dev/null
+++ b/av1/encoder/x86/av1_quantize_avx512.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <assert.h>
+#include <immintrin.h>
+
+#include "config/av1_rtcd.h"
+
+#include "aom/aom_integer.h"
+#include "aom_dsp/aom_dsp_common.h"
+
+static inline __m512i mm512_sign_epi16(__m512i a, __m512i b) {
+ const __m512i zero = _mm512_setzero_si512();
+ const __mmask32 nz_mask = _mm512_cmpneq_epi16_mask(b, zero);
+ const __mmask32 neg_mask = _mm512_cmpgt_epi16_mask(zero, b);
+ const __m512i a_nz = _mm512_maskz_mov_epi16(nz_mask, a);
+ return _mm512_mask_sub_epi16(a_nz, neg_mask, zero, a_nz);
+}
+
+static inline void write_zero_32_avx512(tran_low_t *qcoeff) {
+ const __m512i zero = _mm512_setzero_si512();
+ _mm512_storeu_si512((__m512i *)qcoeff, zero);
+ _mm512_storeu_si512((__m512i *)(qcoeff + 16), zero);
+}
+
+static inline void init_one_qp_avx512(const __m128i *p, __m512i *qp) {
+ const __m128i ac = _mm_unpackhi_epi64(*p, *p);
+ const __m256i dc_ac =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(*p), ac, 1);
+ const __m256i ac256 = _mm256_broadcastq_epi64(ac);
+ *qp = _mm512_inserti64x4(_mm512_castsi256_si512(dc_ac), ac256, 1);
+}
+
+static inline void init_qp_avx512(const int16_t *round_ptr,
+ const int16_t *quant_ptr,
+ const int16_t *dequant_ptr, int log_scale,
+ __m512i *thr, __m512i *qp) {
+ __m128i round = _mm_loadu_si128((const __m128i *)round_ptr);
+ const __m128i quant = _mm_loadu_si128((const __m128i *)quant_ptr);
+ const __m128i dequant = _mm_loadu_si128((const __m128i *)dequant_ptr);
+
+ if (log_scale > 0) {
+ const __m128i rnd = _mm_set1_epi16((int16_t)1 << (log_scale - 1));
+ round = _mm_add_epi16(round, rnd);
+ round = _mm_srai_epi16(round, log_scale);
+ }
+
+ init_one_qp_avx512(&round, &qp[0]);
+ init_one_qp_avx512(&quant, &qp[1]);
+
+ if (log_scale == 1) {
+ qp[1] = _mm512_slli_epi16(qp[1], (unsigned int)log_scale);
+ }
+
+ init_one_qp_avx512(&dequant, &qp[2]);
+ *thr = _mm512_srai_epi16(qp[2], (unsigned int)(1 + log_scale));
+ *thr = _mm512_sub_epi16(*thr, _mm512_set1_epi16(1));
+}
+
+static inline void update_qp_avx512(__m512i *thr, __m512i *qp) {
+ qp[0] = _mm512_shuffle_i64x2(qp[0], qp[0], 0xFF);
+ qp[1] = _mm512_shuffle_i64x2(qp[1], qp[1], 0xFF);
+ qp[2] = _mm512_shuffle_i64x2(qp[2], qp[2], 0xFF);
+ *thr = _mm512_shuffle_i64x2(*thr, *thr, 0xFF);
+}
+
+static inline __m512i load_coefficients_avx512(const tran_low_t *coeff_ptr) {
+ const __m512i coeff1 = _mm512_loadu_si512((const __m512i *)coeff_ptr);
+ const __m512i coeff2 = _mm512_loadu_si512((const __m512i *)(coeff_ptr + 16));
+ return _mm512_packs_epi32(coeff1, coeff2);
+}
+
+static inline void store_coefficients_avx512(__m512i coeff_vals,
+ tran_low_t *coeff_ptr) {
+ const __m512i coeff_sign = _mm512_srai_epi16(coeff_vals, 15);
+ const __m512i coeff_vals_lo = _mm512_unpacklo_epi16(coeff_vals, coeff_sign);
+ const __m512i coeff_vals_hi = _mm512_unpackhi_epi16(coeff_vals, coeff_sign);
+ _mm512_storeu_si512((__m512i *)coeff_ptr, coeff_vals_lo);
+ _mm512_storeu_si512((__m512i *)(coeff_ptr + 16), coeff_vals_hi);
+}
+
+static inline uint16_t quant_gather_eob_avx512(__m512i eob512) {
+ const __m256i eob256 = _mm256_max_epi16(_mm512_castsi512_si256(eob512),
+ _mm512_extracti64x4_epi64(eob512, 1));
+ const __m128i eob_lo = _mm256_castsi256_si128(eob256);
+ const __m128i eob_hi = _mm256_extracti128_si256(eob256, 1);
+ __m128i eob_s = _mm_max_epi16(eob_lo, eob_hi);
+ eob_s = _mm_subs_epu16(_mm_set1_epi16(INT16_MAX), eob_s);
+ eob_s = _mm_minpos_epu16(eob_s);
+ return (uint16_t)(INT16_MAX - _mm_extract_epi16(eob_s, 0));
+}
+
+static AOM_FORCE_INLINE void quantize_lp_32_avx512(
+ const int16_t *coeff_ptr, const int16_t *iscan_ptr, int16_t *qcoeff_ptr,
+ int16_t *dqcoeff_ptr, const __m512i *round512, const __m512i *quant512,
+ const __m512i *dequant512, __m512i *eob) {
+ const __m512i coeff = _mm512_loadu_si512((const __m512i *)coeff_ptr);
+ const __m512i abs_coeff = _mm512_abs_epi16(coeff);
+ const __m512i tmp_rnd = _mm512_adds_epi16(abs_coeff, *round512);
+ const __m512i abs_qcoeff = _mm512_mulhi_epi16(tmp_rnd, *quant512);
+ const __m512i qcoeff = mm512_sign_epi16(abs_qcoeff, coeff);
+ const __m512i dqcoeff = _mm512_mullo_epi16(qcoeff, *dequant512);
+ const __mmask32 nz_mask =
+ _mm512_cmpgt_epi16_mask(abs_qcoeff, _mm512_setzero_si512());
+
+ _mm512_storeu_si512((__m512i *)qcoeff_ptr, qcoeff);
+ _mm512_storeu_si512((__m512i *)dqcoeff_ptr, dqcoeff);
+
+ if (nz_mask) {
+ const __m512i iscan = _mm512_loadu_si512((const __m512i *)iscan_ptr);
+ const __m512i nz_iscan =
+ _mm512_maskz_add_epi16(nz_mask, iscan, _mm512_set1_epi16(1));
+ *eob = _mm512_max_epi16(*eob, nz_iscan);
+ }
+}
+
+void av1_quantize_lp_avx512(const int16_t *coeff_ptr, intptr_t n_coeffs,
+ const int16_t *round_ptr, const int16_t *quant_ptr,
+ int16_t *qcoeff_ptr, int16_t *dqcoeff_ptr,
+ const int16_t *dequant_ptr, uint16_t *eob_ptr,
+ const int16_t *scan, const int16_t *iscan) {
+ if (n_coeffs < 32) {
+ av1_quantize_lp_avx2(coeff_ptr, n_coeffs, round_ptr, quant_ptr, qcoeff_ptr,
+ dqcoeff_ptr, dequant_ptr, eob_ptr, scan, iscan);
+ return;
+ }
+ (void)scan;
+ __m512i eob512 = _mm512_setzero_si512();
+ __m512i round512, quant512, dequant512;
+
+ const __m128i round128 = _mm_loadu_si128((const __m128i *)round_ptr);
+ const __m128i quant128 = _mm_loadu_si128((const __m128i *)quant_ptr);
+ const __m128i dequant128 = _mm_loadu_si128((const __m128i *)dequant_ptr);
+
+ init_one_qp_avx512(&round128, &round512);
+ init_one_qp_avx512(&quant128, &quant512);
+ init_one_qp_avx512(&dequant128, &dequant512);
+
+ quantize_lp_32_avx512(coeff_ptr, iscan, qcoeff_ptr, dqcoeff_ptr, &round512,
+ &quant512, &dequant512, &eob512);
+
+ if (n_coeffs > 32) {
+ round512 = _mm512_shuffle_i64x2(round512, round512, 0xFF);
+ quant512 = _mm512_shuffle_i64x2(quant512, quant512, 0xFF);
+ dequant512 = _mm512_shuffle_i64x2(dequant512, dequant512, 0xFF);
+
+ for (intptr_t idx = 32; idx < n_coeffs; idx += 32) {
+ quantize_lp_32_avx512(coeff_ptr + idx, iscan + idx, qcoeff_ptr + idx,
+ dqcoeff_ptr + idx, &round512, &quant512,
+ &dequant512, &eob512);
+ }
+ }
+
+ *eob_ptr = quant_gather_eob_avx512(eob512);
+}
+
+static AOM_FORCE_INLINE __m512i get_max_lane_eob_avx512(const int16_t *iscan,
+ __m512i v_eobmax,
+ __mmask32 nz_mask) {
+ const __m512i v_iscan = _mm512_loadu_si512((const __m512i *)iscan);
+ const __m512i perm_idx = _mm512_setr_epi64(0, 4, 1, 5, 2, 6, 3, 7);
+ const __m512i v_iscan_perm = _mm512_permutexvar_epi64(perm_idx, v_iscan);
+ const __m512i v_nz_iscan =
+ _mm512_maskz_add_epi16(nz_mask, v_iscan_perm, _mm512_set1_epi16(1));
+ return _mm512_max_epi16(v_eobmax, v_nz_iscan);
+}
+
+static AOM_FORCE_INLINE void quantize_fp_32_avx512(
+ const __m512i *thr, const __m512i *qp, const tran_low_t *coeff_ptr,
+ const int16_t *iscan_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
+ __m512i *eob) {
+ const __m512i coeff = load_coefficients_avx512(coeff_ptr);
+ const __m512i abs_coeff = _mm512_abs_epi16(coeff);
+ const __mmask32 mask = _mm512_cmpgt_epi16_mask(abs_coeff, *thr);
+
+ if (mask) {
+ const __m512i tmp_rnd = _mm512_adds_epi16(abs_coeff, qp[0]);
+ const __m512i abs_q = _mm512_mulhi_epi16(tmp_rnd, qp[1]);
+ const __m512i q = mm512_sign_epi16(abs_q, coeff);
+ const __m512i dq = _mm512_mullo_epi16(q, qp[2]);
+ const __mmask32 nz_mask =
+ _mm512_cmpgt_epi16_mask(abs_q, _mm512_setzero_si512());
+
+ store_coefficients_avx512(q, qcoeff_ptr);
+ store_coefficients_avx512(dq, dqcoeff_ptr);
+
+ *eob = get_max_lane_eob_avx512(iscan_ptr, *eob, nz_mask);
+ } else {
+ write_zero_32_avx512(qcoeff_ptr);
+ write_zero_32_avx512(dqcoeff_ptr);
+ }
+}
+
+void av1_quantize_fp_avx512(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
+ const int16_t *zbin_ptr, const int16_t *round_ptr,
+ const int16_t *quant_ptr,
+ const int16_t *quant_shift_ptr,
+ tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
+ const int16_t *dequant_ptr, uint16_t *eob_ptr,
+ const int16_t *scan_ptr, const int16_t *iscan_ptr) {
+ if (n_coeffs < 32) {
+ av1_quantize_fp_avx2(coeff_ptr, n_coeffs, zbin_ptr, round_ptr, quant_ptr,
+ quant_shift_ptr, qcoeff_ptr, dqcoeff_ptr, dequant_ptr,
+ eob_ptr, scan_ptr, iscan_ptr);
+ return;
+ }
+ (void)scan_ptr;
+ (void)zbin_ptr;
+ (void)quant_shift_ptr;
+
+ const int log_scale = 0;
+ const int step = 32;
+ __m512i qp[3], thr;
+ __m512i eob = _mm512_setzero_si512();
+
+ init_qp_avx512(round_ptr, quant_ptr, dequant_ptr, log_scale, &thr, qp);
+
+ quantize_fp_32_avx512(&thr, qp, coeff_ptr, iscan_ptr, qcoeff_ptr, dqcoeff_ptr,
+ &eob);
+
+ coeff_ptr += step;
+ qcoeff_ptr += step;
+ dqcoeff_ptr += step;
+ iscan_ptr += step;
+ n_coeffs -= step;
+
+ update_qp_avx512(&thr, qp);
+
+ while (n_coeffs > 0) {
+ quantize_fp_32_avx512(&thr, qp, coeff_ptr, iscan_ptr, qcoeff_ptr,
+ dqcoeff_ptr, &eob);
+
+ coeff_ptr += step;
+ qcoeff_ptr += step;
+ dqcoeff_ptr += step;
+ iscan_ptr += step;
+ n_coeffs -= step;
+ }
+ *eob_ptr = quant_gather_eob_avx512(eob);
+}
+
+static AOM_FORCE_INLINE void quantize_fp_32x32_avx512(
+ const __m512i *thr, const __m512i *qp, const tran_low_t *coeff_ptr,
+ const int16_t *iscan_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
+ __m512i *eob) {
+ const __m512i coeff = load_coefficients_avx512(coeff_ptr);
+ const __m512i abs_coeff = _mm512_abs_epi16(coeff);
+ const __mmask32 mask = _mm512_cmpgt_epi16_mask(abs_coeff, *thr);
+
+ if (mask) {
+ const __m512i tmp_rnd = _mm512_adds_epi16(abs_coeff, qp[0]);
+ const __m512i abs_q = _mm512_mulhi_epu16(tmp_rnd, qp[1]);
+ const __m512i q = mm512_sign_epi16(abs_q, coeff);
+ const __m512i abs_dq =
+ _mm512_srli_epi16(_mm512_mullo_epi16(abs_q, qp[2]), 1);
+ const __mmask32 nz_mask =
+ _mm512_cmpgt_epi16_mask(abs_q, _mm512_setzero_si512());
+ const __m512i dq = mm512_sign_epi16(abs_dq, coeff);
+
+ store_coefficients_avx512(q, qcoeff_ptr);
+ store_coefficients_avx512(dq, dqcoeff_ptr);
+
+ *eob = get_max_lane_eob_avx512(iscan_ptr, *eob, nz_mask);
+ } else {
+ write_zero_32_avx512(qcoeff_ptr);
+ write_zero_32_avx512(dqcoeff_ptr);
+ }
+}
+
+void av1_quantize_fp_32x32_avx512(
+ const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
+ const int16_t *round_ptr, const int16_t *quant_ptr,
+ const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
+ tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
+ const int16_t *scan_ptr, const int16_t *iscan_ptr) {
+ (void)scan_ptr;
+ (void)zbin_ptr;
+ (void)quant_shift_ptr;
+
+ const int log_scale = 1;
+ const unsigned int step = 32;
+ __m512i qp[3], thr;
+ __m512i eob = _mm512_setzero_si512();
+
+ init_qp_avx512(round_ptr, quant_ptr, dequant_ptr, log_scale, &thr, qp);
+
+ quantize_fp_32x32_avx512(&thr, qp, coeff_ptr, iscan_ptr, qcoeff_ptr,
+ dqcoeff_ptr, &eob);
+
+ coeff_ptr += step;
+ qcoeff_ptr += step;
+ dqcoeff_ptr += step;
+ iscan_ptr += step;
+ n_coeffs -= step;
+
+ update_qp_avx512(&thr, qp);
+
+ while (n_coeffs > 0) {
+ quantize_fp_32x32_avx512(&thr, qp, coeff_ptr, iscan_ptr, qcoeff_ptr,
+ dqcoeff_ptr, &eob);
+
+ coeff_ptr += step;
+ qcoeff_ptr += step;
+ dqcoeff_ptr += step;
+ iscan_ptr += step;
+ n_coeffs -= step;
+ }
+ *eob_ptr = quant_gather_eob_avx512(eob);
+}
+
+static inline void quantize_fp_64x64_avx512(
+ const __m512i *thr, const __m512i *qp, const tran_low_t *coeff_ptr,
+ const int16_t *iscan_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
+ __m512i *eob) {
+ const __m512i coeff = load_coefficients_avx512(coeff_ptr);
+ const __m512i abs_coeff = _mm512_abs_epi16(coeff);
+ const __mmask32 mask = _mm512_cmpgt_epi16_mask(abs_coeff, *thr);
+
+ if (mask) {
+ const __m512i tmp_rnd = _mm512_maskz_adds_epi16(mask, abs_coeff, qp[0]);
+ const __m512i qh = _mm512_slli_epi16(_mm512_mulhi_epi16(tmp_rnd, qp[1]), 2);
+ const __m512i ql =
+ _mm512_srli_epi16(_mm512_mullo_epi16(tmp_rnd, qp[1]), 14);
+ const __m512i abs_q = _mm512_or_si512(qh, ql);
+ const __m512i dqh = _mm512_slli_epi16(_mm512_mulhi_epi16(abs_q, qp[2]), 14);
+ const __m512i dql = _mm512_srli_epi16(_mm512_mullo_epi16(abs_q, qp[2]), 2);
+ const __m512i abs_dq = _mm512_or_si512(dqh, dql);
+ const __m512i q = mm512_sign_epi16(abs_q, coeff);
+ const __m512i dq = mm512_sign_epi16(abs_dq, coeff);
+ const __mmask32 nz_mask =
+ _mm512_cmpneq_epi16_mask(dq, _mm512_setzero_si512());
+
+ store_coefficients_avx512(q, qcoeff_ptr);
+ store_coefficients_avx512(dq, dqcoeff_ptr);
+
+ *eob = get_max_lane_eob_avx512(iscan_ptr, *eob, nz_mask);
+ } else {
+ write_zero_32_avx512(qcoeff_ptr);
+ write_zero_32_avx512(dqcoeff_ptr);
+ }
+}
+
+void av1_quantize_fp_64x64_avx512(
+ const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
+ const int16_t *round_ptr, const int16_t *quant_ptr,
+ const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
+ tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
+ const int16_t *scan_ptr, const int16_t *iscan_ptr) {
+ (void)scan_ptr;
+ (void)zbin_ptr;
+ (void)quant_shift_ptr;
+
+ const int log_scale = 2;
+ const unsigned int step = 32;
+ __m512i qp[3], thr;
+ __m512i eob = _mm512_setzero_si512();
+
+ init_qp_avx512(round_ptr, quant_ptr, dequant_ptr, log_scale, &thr, qp);
+
+ quantize_fp_64x64_avx512(&thr, qp, coeff_ptr, iscan_ptr, qcoeff_ptr,
+ dqcoeff_ptr, &eob);
+
+ coeff_ptr += step;
+ qcoeff_ptr += step;
+ dqcoeff_ptr += step;
+ iscan_ptr += step;
+ n_coeffs -= step;
+
+ update_qp_avx512(&thr, qp);
+
+ while (n_coeffs > 0) {
+ quantize_fp_64x64_avx512(&thr, qp, coeff_ptr, iscan_ptr, qcoeff_ptr,
+ dqcoeff_ptr, &eob);
+
+ coeff_ptr += step;
+ qcoeff_ptr += step;
+ dqcoeff_ptr += step;
+ iscan_ptr += step;
+ n_coeffs -= step;
+ }
+ *eob_ptr = quant_gather_eob_avx512(eob);
+}
+
+int64_t av1_block_error_lp_avx512(const int16_t *coeff, const int16_t *dqcoeff,
+ intptr_t block_size) {
+ assert(block_size % 16 == 0);
+ if (block_size == 16) {
+ return av1_block_error_lp_avx2(coeff, dqcoeff, block_size);
+ }
+ const __m512i zero = _mm512_setzero_si512();
+ __m512i sse_512 = zero;
+ intptr_t i = 0;
+
+ for (; i + 64 <= block_size; i += 64) {
+ const __m512i c0 = _mm512_loadu_si512((const __m512i *)(coeff + i));
+ const __m512i d0 = _mm512_loadu_si512((const __m512i *)(dqcoeff + i));
+ const __m512i c1 = _mm512_loadu_si512((const __m512i *)(coeff + i + 32));
+ const __m512i d1 = _mm512_loadu_si512((const __m512i *)(dqcoeff + i + 32));
+
+ const __m512i diff0 = _mm512_sub_epi16(d0, c0);
+ const __m512i diff1 = _mm512_sub_epi16(d1, c1);
+ const __m512i err0 = _mm512_madd_epi16(diff0, diff0);
+ const __m512i err1 = _mm512_madd_epi16(diff1, diff1);
+
+ const __m512i exp0_lo = _mm512_unpacklo_epi32(err0, zero);
+ const __m512i exp0_hi = _mm512_unpackhi_epi32(err0, zero);
+ const __m512i exp1_lo = _mm512_unpacklo_epi32(err1, zero);
+ const __m512i exp1_hi = _mm512_unpackhi_epi32(err1, zero);
+
+ const __m512i sum0 = _mm512_add_epi64(exp0_lo, exp0_hi);
+ const __m512i sum1 = _mm512_add_epi64(exp1_lo, exp1_hi);
+ sse_512 = _mm512_add_epi64(sse_512, _mm512_add_epi64(sum0, sum1));
+ }
+
+ for (; i < block_size; i += 32) {
+ const __m512i c0 = _mm512_loadu_si512((const __m512i *)(coeff + i));
+ const __m512i d0 = _mm512_loadu_si512((const __m512i *)(dqcoeff + i));
+ const __m512i diff0 = _mm512_sub_epi16(d0, c0);
+ const __m512i err0 = _mm512_madd_epi16(diff0, diff0);
+ const __m512i exp0_lo = _mm512_unpacklo_epi32(err0, zero);
+ const __m512i exp0_hi = _mm512_unpackhi_epi32(err0, zero);
+ sse_512 = _mm512_add_epi64(sse_512, _mm512_add_epi64(exp0_lo, exp0_hi));
+ }
+
+ return _mm512_reduce_add_epi64(sse_512);
+}
+
+int64_t av1_block_error_avx512(const tran_low_t *coeff,
+ const tran_low_t *dqcoeff, intptr_t block_size,
+ int64_t *ssz) {
+ if (block_size < 32) {
+ return av1_block_error_avx2(coeff, dqcoeff, block_size, ssz);
+ }
+ const __m512i zero = _mm512_setzero_si512();
+ __m512i sse_reg = zero;
+ __m512i ssz_reg = zero;
+
+ for (intptr_t i = 0; i < block_size; i += 32) {
+ const __m512i c0 = _mm512_loadu_si512((const __m512i *)(coeff + i));
+ const __m512i c1 = _mm512_loadu_si512((const __m512i *)(coeff + i + 16));
+ const __m512i coeff_reg = _mm512_packs_epi32(c0, c1);
+
+ const __m512i d0 = _mm512_loadu_si512((const __m512i *)(dqcoeff + i));
+ const __m512i d1 = _mm512_loadu_si512((const __m512i *)(dqcoeff + i + 16));
+ const __m512i dqcoeff_reg = _mm512_packs_epi32(d0, d1);
+
+ const __m512i diff = _mm512_sub_epi16(dqcoeff_reg, coeff_reg);
+ const __m512i err = _mm512_madd_epi16(diff, diff);
+ const __m512i sq_coeff = _mm512_madd_epi16(coeff_reg, coeff_reg);
+
+ const __m512i exp_err_lo = _mm512_unpacklo_epi32(err, zero);
+ const __m512i exp_err_hi = _mm512_unpackhi_epi32(err, zero);
+ const __m512i exp_coeff_lo = _mm512_unpacklo_epi32(sq_coeff, zero);
+ const __m512i exp_coeff_hi = _mm512_unpackhi_epi32(sq_coeff, zero);
+
+ sse_reg =
+ _mm512_add_epi64(sse_reg, _mm512_add_epi64(exp_err_lo, exp_err_hi));
+ ssz_reg =
+ _mm512_add_epi64(ssz_reg, _mm512_add_epi64(exp_coeff_lo, exp_coeff_hi));
+ }
+
+ *ssz = _mm512_reduce_add_epi64(ssz_reg);
+ return _mm512_reduce_add_epi64(sse_reg);
+}
diff --git a/av1/encoder/x86/encodetxb_avx512.c b/av1/encoder/x86/encodetxb_avx512.c
new file mode 100644
index 0000000000..de164d26c3
--- /dev/null
+++ b/av1/encoder/x86/encodetxb_avx512.c
@@ -0,0 +1,721 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <assert.h>
+#include <immintrin.h>
+#include <string.h>
+
+#include "config/av1_rtcd.h"
+
+#include "aom/aom_integer.h"
+#include "aom_dsp/x86/mem_sse2.h"
+#include "av1/common/av1_common_int.h"
+#include "av1/common/reconinter.h"
+#include "av1/common/txb_common.h"
+#include "av1/encoder/encodetxb.h"
+
+// Packs 64 tran_low_t values into 64 uint8_t levels in sequential order in a
+// single 512-bit ZMM register.
+static inline __m512i pack_64_levels_avx512(const tran_low_t *coeff) {
+ const __m512i c0 =
+ _mm512_abs_epi32(_mm512_loadu_si512((const __m512i *)coeff));
+ const __m512i c1 =
+ _mm512_abs_epi32(_mm512_loadu_si512((const __m512i *)(coeff + 16)));
+ const __m512i c2 =
+ _mm512_abs_epi32(_mm512_loadu_si512((const __m512i *)(coeff + 32)));
+ const __m512i c3 =
+ _mm512_abs_epi32(_mm512_loadu_si512((const __m512i *)(coeff + 48)));
+
+ const __m512i p01 = _mm512_packs_epi32(c0, c1);
+ const __m512i p23 = _mm512_packs_epi32(c2, c3);
+ const __m512i p0123 = _mm512_packs_epi16(p01, p23);
+ const __m512i perm_idx =
+ _mm512_setr_epi32(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15);
+ return _mm512_permutexvar_epi32(perm_idx, p0123);
+}
+
+void av1_txb_init_levels_avx512(const tran_low_t *const coeff, const int width,
+ const int height, uint8_t *const levels) {
+ const int stride = height + TX_PAD_HOR;
+ if (width * height < 64 || height == 4) {
+ av1_txb_init_levels_avx2(coeff, width, height, levels);
+ return;
+ }
+
+ const __m256i y_zeros = _mm256_setzero_si256();
+ const int32_t bottom_len = sizeof(*levels) * (TX_PAD_BOTTOM * stride);
+ uint8_t *bottom_buf_end = levels + (width + TX_PAD_BOTTOM) * stride;
+ uint8_t *bottom_buf = bottom_buf_end - ((bottom_len + 31) & (~31));
+ do {
+ _mm256_storeu_si256((__m256i *)bottom_buf, y_zeros);
+ bottom_buf += 32;
+ } while (bottom_buf < bottom_buf_end);
+
+ uint8_t *ls = levels;
+ const tran_low_t *cf = coeff;
+
+ if (height == 32) {
+ for (int i = 0; i < width; i += 2) {
+ const __m512i lv = pack_64_levels_avx512(cf);
+ _mm256_storeu_si256((__m256i *)ls, _mm512_castsi512_si256(lv));
+ *(int32_t *)(ls + 32) = 0;
+ ls += stride;
+ _mm256_storeu_si256((__m256i *)ls, _mm512_extracti64x4_epi64(lv, 1));
+ *(int32_t *)(ls + 32) = 0;
+ ls += stride;
+ cf += 64;
+ }
+ } else if (height == 16) {
+ for (int i = 0; i < width; i += 4) {
+ const __m512i lv = pack_64_levels_avx512(cf);
+ const __m256i lv_lo = _mm512_castsi512_si256(lv);
+ const __m256i lv_hi = _mm512_extracti64x4_epi64(lv, 1);
+ _mm_storeu_si128((__m128i *)ls, _mm256_castsi256_si128(lv_lo));
+ *(int32_t *)(ls + 16) = 0;
+ ls += stride;
+ _mm_storeu_si128((__m128i *)ls, _mm256_extracti128_si256(lv_lo, 1));
+ *(int32_t *)(ls + 16) = 0;
+ ls += stride;
+ _mm_storeu_si128((__m128i *)ls, _mm256_castsi256_si128(lv_hi));
+ *(int32_t *)(ls + 16) = 0;
+ ls += stride;
+ _mm_storeu_si128((__m128i *)ls, _mm256_extracti128_si256(lv_hi, 1));
+ *(int32_t *)(ls + 16) = 0;
+ ls += stride;
+ cf += 64;
+ }
+ } else if (height == 8) {
+ for (int i = 0; i < width; i += 8) {
+ const __m512i lv = pack_64_levels_avx512(cf);
+ const __m256i lv_lo = _mm512_castsi512_si256(lv);
+ const __m256i lv_hi = _mm512_extracti64x4_epi64(lv, 1);
+ const __m128i r01 = _mm256_castsi256_si128(lv_lo);
+ const __m128i r23 = _mm256_extracti128_si256(lv_lo, 1);
+ const __m128i r45 = _mm256_castsi256_si128(lv_hi);
+ const __m128i r67 = _mm256_extracti128_si256(lv_hi, 1);
+ _mm_storel_epi64((__m128i *)(ls + 0 * stride), r01);
+ *(int32_t *)(ls + 0 * stride + 8) = 0;
+ _mm_storeh_pi((__m64 *)(ls + 1 * stride), _mm_castsi128_ps(r01));
+ *(int32_t *)(ls + 1 * stride + 8) = 0;
+ _mm_storel_epi64((__m128i *)(ls + 2 * stride), r23);
+ *(int32_t *)(ls + 2 * stride + 8) = 0;
+ _mm_storeh_pi((__m64 *)(ls + 3 * stride), _mm_castsi128_ps(r23));
+ *(int32_t *)(ls + 3 * stride + 8) = 0;
+ _mm_storel_epi64((__m128i *)(ls + 4 * stride), r45);
+ *(int32_t *)(ls + 4 * stride + 8) = 0;
+ _mm_storeh_pi((__m64 *)(ls + 5 * stride), _mm_castsi128_ps(r45));
+ *(int32_t *)(ls + 5 * stride + 8) = 0;
+ _mm_storel_epi64((__m128i *)(ls + 6 * stride), r67);
+ *(int32_t *)(ls + 6 * stride + 8) = 0;
+ _mm_storeh_pi((__m64 *)(ls + 7 * stride), _mm_castsi128_ps(r67));
+ *(int32_t *)(ls + 7 * stride + 8) = 0;
+ ls += 8 * stride;
+ cf += 64;
+ }
+ } else {
+ av1_txb_init_levels_avx2(coeff, width, height, levels);
+ }
+}
+
+static inline __m512i load_8bit_16x4_to_1_reg_avx512(const uint8_t *const src,
+ const int stride) {
+ const __m128i r0 = _mm_loadu_si128((const __m128i *)(src + 0 * stride));
+ const __m128i r1 = _mm_loadu_si128((const __m128i *)(src + 1 * stride));
+ const __m128i r2 = _mm_loadu_si128((const __m128i *)(src + 2 * stride));
+ const __m128i r3 = _mm_loadu_si128((const __m128i *)(src + 3 * stride));
+ const __m256i r01 =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(r0), r1, 1);
+ const __m256i r23 =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(r2), r3, 1);
+ return _mm512_inserti64x4(_mm512_castsi256_si512(r01), r23, 1);
+}
+
+static inline __m512i load_8bit_32x2_to_1_reg_avx512(const uint8_t *const src,
+ const int stride) {
+ const __m256i r0 = _mm256_loadu_si256((const __m256i *)(src + 0 * stride));
+ const __m256i r1 = _mm256_loadu_si256((const __m256i *)(src + 1 * stride));
+ return _mm512_inserti64x4(_mm512_castsi256_si512(r0), r1, 1);
+}
+
+static inline __m512i load_8bit_8x8_to_1_reg_avx512(const uint8_t *const src,
+ const int stride) {
+ const __m128i r01 = load_8bit_8x2_to_1_reg_sse2(src + 0 * stride, stride);
+ const __m128i r23 = load_8bit_8x2_to_1_reg_sse2(src + 2 * stride, stride);
+ const __m128i r45 = load_8bit_8x2_to_1_reg_sse2(src + 4 * stride, stride);
+ const __m128i r67 = load_8bit_8x2_to_1_reg_sse2(src + 6 * stride, stride);
+ const __m256i r0123 =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(r01), r23, 1);
+ const __m256i r4567 =
+ _mm256_inserti128_si256(_mm256_castsi128_si256(r45), r67, 1);
+ return _mm512_inserti64x4(_mm512_castsi256_si512(r0123), r4567, 1);
+}
+
+static inline void load_levels_16x4x5_avx512(const uint8_t *const src,
+ const int stride,
+ const ptrdiff_t *const offsets,
+ __m512i *const level) {
+ level[0] = load_8bit_16x4_to_1_reg_avx512(src + 1, stride);
+ level[1] = load_8bit_16x4_to_1_reg_avx512(src + stride, stride);
+ level[2] = load_8bit_16x4_to_1_reg_avx512(src + offsets[0], stride);
+ level[3] = load_8bit_16x4_to_1_reg_avx512(src + offsets[1], stride);
+ level[4] = load_8bit_16x4_to_1_reg_avx512(src + offsets[2], stride);
+}
+
+static inline void load_levels_32x2x5_avx512(const uint8_t *const src,
+ const int stride,
+ const ptrdiff_t *const offsets,
+ __m512i *const level) {
+ level[0] = load_8bit_32x2_to_1_reg_avx512(src + 1, stride);
+ level[1] = load_8bit_32x2_to_1_reg_avx512(src + stride, stride);
+ level[2] = load_8bit_32x2_to_1_reg_avx512(src + offsets[0], stride);
+ level[3] = load_8bit_32x2_to_1_reg_avx512(src + offsets[1], stride);
+ level[4] = load_8bit_32x2_to_1_reg_avx512(src + offsets[2], stride);
+}
+
+static inline void load_levels_8x8x5_avx512(const uint8_t *const src,
+ const int stride,
+ const ptrdiff_t *const offsets,
+ __m512i *const level) {
+ level[0] = load_8bit_8x8_to_1_reg_avx512(src + 1, stride);
+ level[1] = load_8bit_8x8_to_1_reg_avx512(src + stride, stride);
+ level[2] = load_8bit_8x8_to_1_reg_avx512(src + offsets[0], stride);
+ level[3] = load_8bit_8x8_to_1_reg_avx512(src + offsets[1], stride);
+ level[4] = load_8bit_8x8_to_1_reg_avx512(src + offsets[2], stride);
+}
+
+static inline __m512i get_coeff_contexts_kernel_avx512(__m512i *const level) {
+ const __m512i const_3 = _mm512_set1_epi8(3);
+ const __m512i const_4 = _mm512_set1_epi8(4);
+ __m512i count = _mm512_min_epu8(level[0], const_3);
+ level[1] = _mm512_min_epu8(level[1], const_3);
+ level[2] = _mm512_min_epu8(level[2], const_3);
+ level[3] = _mm512_min_epu8(level[3], const_3);
+ level[4] = _mm512_min_epu8(level[4], const_3);
+ count = _mm512_add_epi8(count, level[1]);
+ count = _mm512_add_epi8(count, level[2]);
+ count = _mm512_add_epi8(count, level[3]);
+ count = _mm512_add_epi8(count, level[4]);
+ count = _mm512_avg_epu8(count, _mm512_setzero_si512());
+ count = _mm512_min_epu8(count, const_4);
+ return count;
+}
+
+static inline __m512i pack_4x128_to_512(__m128i a, __m128i b, __m128i c,
+ __m128i d) {
+ const __m256i ab = _mm256_inserti128_si256(_mm256_castsi128_si256(a), b, 1);
+ const __m256i cd = _mm256_inserti128_si256(_mm256_castsi128_si256(c), d, 1);
+ return _mm512_inserti64x4(_mm512_castsi256_si512(ab), cd, 1);
+}
+
+static inline void get_8_coeff_contexts_2d_avx512(
+ const uint8_t *levels, const int width, const ptrdiff_t *const offsets,
+ int8_t *coeff_contexts) {
+ const int stride = 8 + TX_PAD_HOR;
+ int8_t *cc = coeff_contexts;
+ int col = width;
+ __m512i level[5];
+ __m128i p0, p1;
+ const __m128i p2 = _mm_set1_epi8(21);
+
+ if (width == 8) {
+ p0 = _mm_setr_epi8(0, 1, 6, 6, 21, 21, 21, 21, 1, 6, 6, 21, 21, 21, 21, 21);
+ p1 = _mm_setr_epi8(6, 6, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21,
+ 21);
+ } else {
+ p0 = _mm_setr_epi8(0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16);
+ p1 = _mm_setr_epi8(6, 6, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21,
+ 21);
+ }
+
+ __m512i pos_to_offset = pack_4x128_to_512(p0, p1, p2, p2);
+ const __m512i pos_to_offset_large = _mm512_set1_epi8(21);
+
+ do {
+ load_levels_8x8x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset);
+ _mm512_storeu_si512((__m512i *)cc, count);
+ pos_to_offset = pos_to_offset_large;
+ levels += 8 * stride;
+ cc += 64;
+ col -= 8;
+ } while (col > 0);
+
+ coeff_contexts[0] = 0;
+}
+
+static inline void get_8_coeff_contexts_ver_avx512(
+ const uint8_t *levels, const int width, const ptrdiff_t *const offsets,
+ int8_t *coeff_contexts) {
+ const int stride = 8 + TX_PAD_HOR;
+ const __m128i p0 =
+ _mm_setr_epi8(SIG_COEF_CONTEXTS_2D + 0, SIG_COEF_CONTEXTS_2D + 5,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 0, SIG_COEF_CONTEXTS_2D + 5,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10);
+ const __m512i pos_to_offset = _mm512_broadcast_i32x4(p0);
+ int col = width;
+ __m512i level[5];
+
+ do {
+ load_levels_8x8x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset);
+ _mm512_storeu_si512((__m512i *)coeff_contexts, count);
+ levels += 8 * stride;
+ coeff_contexts += 64;
+ col -= 8;
+ } while (col > 0);
+}
+
+static inline void get_8_coeff_contexts_hor_avx512(
+ const uint8_t *levels, const int width, const ptrdiff_t *const offsets,
+ int8_t *coeff_contexts) {
+ const int stride = 8 + TX_PAD_HOR;
+ const __m128i p0 =
+ _mm_setr_epi8(SIG_COEF_CONTEXTS_2D + 0, SIG_COEF_CONTEXTS_2D + 0,
+ SIG_COEF_CONTEXTS_2D + 0, SIG_COEF_CONTEXTS_2D + 0,
+ SIG_COEF_CONTEXTS_2D + 0, SIG_COEF_CONTEXTS_2D + 0,
+ SIG_COEF_CONTEXTS_2D + 0, SIG_COEF_CONTEXTS_2D + 0,
+ SIG_COEF_CONTEXTS_2D + 5, SIG_COEF_CONTEXTS_2D + 5,
+ SIG_COEF_CONTEXTS_2D + 5, SIG_COEF_CONTEXTS_2D + 5,
+ SIG_COEF_CONTEXTS_2D + 5, SIG_COEF_CONTEXTS_2D + 5,
+ SIG_COEF_CONTEXTS_2D + 5, SIG_COEF_CONTEXTS_2D + 5);
+ const __m128i p_large = _mm_set1_epi8(SIG_COEF_CONTEXTS_2D + 10);
+ __m512i pos_to_offset = pack_4x128_to_512(p0, p_large, p_large, p_large);
+ const __m512i pos_to_offset_large =
+ _mm512_set1_epi8(SIG_COEF_CONTEXTS_2D + 10);
+ int col = width;
+ __m512i level[5];
+
+ do {
+ load_levels_8x8x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset);
+ _mm512_storeu_si512((__m512i *)coeff_contexts, count);
+ pos_to_offset = pos_to_offset_large;
+ levels += 8 * stride;
+ coeff_contexts += 64;
+ col -= 8;
+ } while (col > 0);
+}
+
+static inline void get_16_coeff_contexts_2d_avx512(
+ const uint8_t *levels, const int real_width, const int real_height,
+ const int width, const ptrdiff_t *const offsets, int8_t *coeff_contexts) {
+ const int stride = 16 + TX_PAD_HOR;
+ int8_t *cc = coeff_contexts;
+ int col = width;
+ __m512i level[5];
+ __m512i pos_to_offset;
+ __m512i pos_to_offset_large;
+
+ if (real_width == real_height) {
+ const __m128i p0 = _mm_setr_epi8(0, 1, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21);
+ const __m128i p1 = _mm_setr_epi8(1, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p2 = _mm_setr_epi8(6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p3 = _mm_setr_epi8(6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ pos_to_offset = pack_4x128_to_512(p0, p1, p2, p3);
+ pos_to_offset_large = _mm512_set1_epi8(21);
+ } else if (real_width < real_height) {
+ const __m128i p0 = _mm_setr_epi8(0, 11, 6, 6, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p1 = _mm_setr_epi8(11, 11, 6, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p2 = _mm_setr_epi8(11, 11, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ pos_to_offset = pack_4x128_to_512(p0, p1, p2, p2);
+ pos_to_offset_large = _mm512_broadcast_i32x4(p2);
+ } else {
+ const __m128i p0 = _mm_set1_epi8(16);
+ const __m128i p2 = _mm_setr_epi8(6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p3 = _mm_setr_epi8(6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ pos_to_offset = pack_4x128_to_512(p0, p0, p2, p3);
+ pos_to_offset_large = _mm512_set1_epi8(21);
+ }
+
+ do {
+ load_levels_16x4x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset);
+ _mm512_storeu_si512((__m512i *)cc, count);
+ pos_to_offset = pos_to_offset_large;
+ levels += 4 * stride;
+ cc += 64;
+ col -= 4;
+ } while (col > 0);
+
+ coeff_contexts[0] = 0;
+}
+
+static inline void get_16_coeff_contexts_ver_avx512(
+ const uint8_t *levels, const int width, const ptrdiff_t *const offsets,
+ int8_t *coeff_contexts) {
+ const int stride = 16 + TX_PAD_HOR;
+ const __m128i p0 =
+ _mm_setr_epi8(SIG_COEF_CONTEXTS_2D + 0, SIG_COEF_CONTEXTS_2D + 5,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10);
+ const __m512i pos_to_offset = _mm512_broadcast_i32x4(p0);
+ int col = width;
+ __m512i level[5];
+
+ do {
+ load_levels_16x4x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset);
+ _mm512_storeu_si512((__m512i *)coeff_contexts, count);
+ levels += 4 * stride;
+ coeff_contexts += 64;
+ col -= 4;
+ } while (col > 0);
+}
+
+static inline void get_16_coeff_contexts_hor_avx512(
+ const uint8_t *levels, const int width, const ptrdiff_t *const offsets,
+ int8_t *coeff_contexts) {
+ const int stride = 16 + TX_PAD_HOR;
+ const __m128i p0 = _mm_set1_epi8(SIG_COEF_CONTEXTS_2D + 0);
+ const __m128i p1 = _mm_set1_epi8(SIG_COEF_CONTEXTS_2D + 5);
+ const __m128i p2 = _mm_set1_epi8(SIG_COEF_CONTEXTS_2D + 10);
+ __m512i pos_to_offset = pack_4x128_to_512(p0, p1, p2, p2);
+ const __m512i pos_to_offset_large =
+ _mm512_set1_epi8(SIG_COEF_CONTEXTS_2D + 10);
+ int col = width;
+ __m512i level[5];
+
+ do {
+ load_levels_16x4x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset);
+ _mm512_storeu_si512((__m512i *)coeff_contexts, count);
+ pos_to_offset = pos_to_offset_large;
+ levels += 4 * stride;
+ coeff_contexts += 64;
+ col -= 4;
+ } while (col > 0);
+}
+
+static inline void get_32_coeff_contexts_2d_avx512(
+ const uint8_t *levels, const int real_width, const int real_height,
+ const int width, const ptrdiff_t *const offsets, int8_t *coeff_contexts) {
+ const int stride = 32 + TX_PAD_HOR;
+ int8_t *cc = coeff_contexts;
+ int col = width;
+ __m512i level[5];
+ __m512i pos_to_offset[3];
+ const __m128i p_21 = _mm_set1_epi8(21);
+
+ if (real_width == real_height) {
+ const __m128i p0 = _mm_setr_epi8(0, 1, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21);
+ const __m128i p1 = _mm_setr_epi8(1, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p2 = _mm_setr_epi8(6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p3 = _mm_setr_epi8(6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ pos_to_offset[0] = pack_4x128_to_512(p0, p_21, p1, p_21);
+ pos_to_offset[1] = pack_4x128_to_512(p2, p_21, p3, p_21);
+ pos_to_offset[2] = _mm512_set1_epi8(21);
+ } else if (real_width < real_height) {
+ const __m128i p0 = _mm_setr_epi8(0, 11, 6, 6, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p1 = _mm_setr_epi8(11, 11, 6, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p2 = _mm_setr_epi8(11, 11, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ pos_to_offset[0] = pack_4x128_to_512(p0, p_21, p1, p_21);
+ pos_to_offset[1] = pos_to_offset[2] = pack_4x128_to_512(p2, p_21, p2, p_21);
+ } else {
+ const __m128i p_16 = _mm_set1_epi8(16);
+ const __m128i p2 = _mm_setr_epi8(6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ const __m128i p3 = _mm_setr_epi8(6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21);
+ pos_to_offset[0] = pack_4x128_to_512(p_16, p_16, p_16, p_16);
+ pos_to_offset[1] = pack_4x128_to_512(p2, p_21, p3, p_21);
+ pos_to_offset[2] = _mm512_set1_epi8(21);
+ }
+
+ do {
+ load_levels_32x2x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset[0]);
+ _mm512_storeu_si512((__m512i *)cc, count);
+ pos_to_offset[0] = pos_to_offset[1];
+ pos_to_offset[1] = pos_to_offset[2];
+ levels += 2 * stride;
+ cc += 64;
+ col -= 2;
+ } while (col > 0);
+
+ coeff_contexts[0] = 0;
+}
+
+static inline void get_32_coeff_contexts_ver_avx512(
+ const uint8_t *levels, const int width, const ptrdiff_t *const offsets,
+ int8_t *coeff_contexts) {
+ const int stride = 32 + TX_PAD_HOR;
+ const __m128i p0 =
+ _mm_setr_epi8(SIG_COEF_CONTEXTS_2D + 0, SIG_COEF_CONTEXTS_2D + 5,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10,
+ SIG_COEF_CONTEXTS_2D + 10, SIG_COEF_CONTEXTS_2D + 10);
+ const __m128i p1 = _mm_set1_epi8(SIG_COEF_CONTEXTS_2D + 10);
+ const __m512i pos_to_offset = pack_4x128_to_512(p0, p1, p0, p1);
+ int col = width;
+ __m512i level[5];
+
+ do {
+ load_levels_32x2x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset);
+ _mm512_storeu_si512((__m512i *)coeff_contexts, count);
+ levels += 2 * stride;
+ coeff_contexts += 64;
+ col -= 2;
+ } while (col > 0);
+}
+
+static inline void get_32_coeff_contexts_hor_avx512(
+ const uint8_t *levels, const int width, const ptrdiff_t *const offsets,
+ int8_t *coeff_contexts) {
+ const int stride = 32 + TX_PAD_HOR;
+ const __m128i p0 = _mm_set1_epi8(SIG_COEF_CONTEXTS_2D + 0);
+ const __m128i p1 = _mm_set1_epi8(SIG_COEF_CONTEXTS_2D + 5);
+ __m512i pos_to_offset = pack_4x128_to_512(p0, p0, p1, p1);
+ const __m512i pos_to_offset_large =
+ _mm512_set1_epi8(SIG_COEF_CONTEXTS_2D + 10);
+ int col = width;
+ __m512i level[5];
+
+ do {
+ load_levels_32x2x5_avx512(levels, stride, offsets, level);
+ __m512i count = get_coeff_contexts_kernel_avx512(level);
+ count = _mm512_add_epi8(count, pos_to_offset);
+ _mm512_storeu_si512((__m512i *)coeff_contexts, count);
+ pos_to_offset = pos_to_offset_large;
+ levels += 2 * stride;
+ coeff_contexts += 64;
+ col -= 2;
+ } while (col > 0);
+}
+
+void av1_get_nz_map_contexts_avx512(const uint8_t *const levels,
+ const int16_t *const scan, const int eob,
+ const TX_SIZE tx_size,
+ const TX_CLASS tx_class,
+ int8_t *const coeff_contexts) {
+ const int last_idx = eob - 1;
+ if (!last_idx) {
+ coeff_contexts[0] = 0;
+ return;
+ }
+
+ const int real_width = tx_size_wide[tx_size];
+ const int real_height = tx_size_high[tx_size];
+ const int width = get_txb_wide(tx_size);
+ const int height = get_txb_high(tx_size);
+ const int stride = height + TX_PAD_HOR;
+ ptrdiff_t offsets[3];
+
+ /* coeff_contexts must be 16 byte aligned. */
+ assert(!((intptr_t)coeff_contexts & 0xf));
+
+ if (tx_class == TX_CLASS_2D) {
+ offsets[0] = 0 * stride + 2;
+ offsets[1] = 1 * stride + 1;
+ offsets[2] = 2 * stride + 0;
+
+ if (height == 8 && width >= 8) {
+ get_8_coeff_contexts_2d_avx512(levels, width, offsets, coeff_contexts);
+ } else if (height == 16) {
+ get_16_coeff_contexts_2d_avx512(levels, real_width, real_height, width,
+ offsets, coeff_contexts);
+ } else if (height == 32) {
+ get_32_coeff_contexts_2d_avx512(levels, real_width, real_height, width,
+ offsets, coeff_contexts);
+ } else {
+ av1_get_nz_map_contexts_sse2(levels, scan, eob, tx_size, tx_class,
+ coeff_contexts);
+ return;
+ }
+ } else if (tx_class == TX_CLASS_HORIZ) {
+ offsets[0] = 2 * stride;
+ offsets[1] = 3 * stride;
+ offsets[2] = 4 * stride;
+
+ if (height == 8 && width >= 8) {
+ get_8_coeff_contexts_hor_avx512(levels, width, offsets, coeff_contexts);
+ } else if (height == 16) {
+ get_16_coeff_contexts_hor_avx512(levels, width, offsets, coeff_contexts);
+ } else if (height == 32) {
+ get_32_coeff_contexts_hor_avx512(levels, width, offsets, coeff_contexts);
+ } else {
+ av1_get_nz_map_contexts_sse2(levels, scan, eob, tx_size, tx_class,
+ coeff_contexts);
+ return;
+ }
+ } else {
+ offsets[0] = 2;
+ offsets[1] = 3;
+ offsets[2] = 4;
+
+ if (height == 8 && width >= 8) {
+ get_8_coeff_contexts_ver_avx512(levels, width, offsets, coeff_contexts);
+ } else if (height == 16) {
+ get_16_coeff_contexts_ver_avx512(levels, width, offsets, coeff_contexts);
+ } else if (height == 32) {
+ get_32_coeff_contexts_ver_avx512(levels, width, offsets, coeff_contexts);
+ } else {
+ av1_get_nz_map_contexts_sse2(levels, scan, eob, tx_size, tx_class,
+ coeff_contexts);
+ return;
+ }
+ }
+
+ const int bhl = get_txb_bhl(tx_size);
+ const int pos = scan[last_idx];
+ if (last_idx <= (width << bhl) / 8)
+ coeff_contexts[pos] = 1;
+ else if (last_idx <= (width << bhl) / 4)
+ coeff_contexts[pos] = 2;
+ else
+ coeff_contexts[pos] = 3;
+}
+
+uint64_t av1_wedge_sse_from_residuals_avx512(const int16_t *r1,
+ const int16_t *d, const uint8_t *m,
+ int N) {
+ assert(N % 64 == 0);
+ const __m512i v_max_mask = _mm512_set1_epi16(1 << WEDGE_WEIGHT_BITS);
+ __m512i v_acc0 = _mm512_setzero_si512();
+ __m512i v_acc1 = _mm512_setzero_si512();
+
+ for (int i = 0; i < N; i += 64) {
+ const __m512i r1_l = _mm512_loadu_si512((const __m512i *)(r1 + i));
+ const __m512i r1_h = _mm512_loadu_si512((const __m512i *)(r1 + i + 32));
+ const __m512i d_l = _mm512_loadu_si512((const __m512i *)(d + i));
+ const __m512i d_h = _mm512_loadu_si512((const __m512i *)(d + i + 32));
+ const __m512i m_l =
+ _mm512_cvtepu8_epi16(_mm256_loadu_si256((const __m256i *)(m + i)));
+ const __m512i m_h =
+ _mm512_cvtepu8_epi16(_mm256_loadu_si256((const __m256i *)(m + i + 32)));
+
+ const __m512i rd_ll = _mm512_unpacklo_epi16(d_l, r1_l);
+ const __m512i rd_lh = _mm512_unpackhi_epi16(d_l, r1_l);
+ const __m512i m_ll = _mm512_unpacklo_epi16(m_l, v_max_mask);
+ const __m512i m_lh = _mm512_unpackhi_epi16(m_l, v_max_mask);
+ const __m512i t_l = _mm512_packs_epi32(_mm512_madd_epi16(rd_ll, m_ll),
+ _mm512_madd_epi16(rd_lh, m_lh));
+
+ const __m512i rd_hl = _mm512_unpacklo_epi16(d_h, r1_h);
+ const __m512i rd_hh = _mm512_unpackhi_epi16(d_h, r1_h);
+ const __m512i m_hl = _mm512_unpacklo_epi16(m_h, v_max_mask);
+ const __m512i m_hh = _mm512_unpackhi_epi16(m_h, v_max_mask);
+ const __m512i t_h = _mm512_packs_epi32(_mm512_madd_epi16(rd_hl, m_hl),
+ _mm512_madd_epi16(rd_hh, m_hh));
+
+ const __m512i sq_l = _mm512_madd_epi16(t_l, t_l);
+ const __m512i sq_h = _mm512_madd_epi16(t_h, t_h);
+
+ v_acc0 = _mm512_add_epi64(
+ v_acc0, _mm512_cvtepu32_epi64(_mm512_castsi512_si256(sq_l)));
+ v_acc1 = _mm512_add_epi64(
+ v_acc1, _mm512_cvtepu32_epi64(_mm512_extracti64x4_epi64(sq_l, 1)));
+ v_acc0 = _mm512_add_epi64(
+ v_acc0, _mm512_cvtepu32_epi64(_mm512_castsi512_si256(sq_h)));
+ v_acc1 = _mm512_add_epi64(
+ v_acc1, _mm512_cvtepu32_epi64(_mm512_extracti64x4_epi64(sq_h, 1)));
+ }
+
+ const uint64_t csse =
+ (uint64_t)_mm512_reduce_add_epi64(_mm512_add_epi64(v_acc0, v_acc1));
+ return ROUND_POWER_OF_TWO(csse, 2 * WEDGE_WEIGHT_BITS);
+}
+
+int8_t av1_wedge_sign_from_residuals_avx512(const int16_t *ds, const uint8_t *m,
+ int N, int64_t limit) {
+ assert(N % 64 == 0);
+ __m512i acc0 = _mm512_setzero_si512();
+ __m512i acc1 = _mm512_setzero_si512();
+
+ for (int i = 0; i < N; i += 64) {
+ const __m512i ds_l = _mm512_loadu_si512((const __m512i *)(ds + i));
+ const __m512i ds_h = _mm512_loadu_si512((const __m512i *)(ds + i + 32));
+ const __m512i m_l =
+ _mm512_cvtepu8_epi16(_mm256_loadu_si256((const __m256i *)(m + i)));
+ const __m512i m_h =
+ _mm512_cvtepu8_epi16(_mm256_loadu_si256((const __m256i *)(m + i + 32)));
+
+ acc0 = _mm512_add_epi32(acc0, _mm512_madd_epi16(ds_l, m_l));
+ acc1 = _mm512_add_epi32(acc1, _mm512_madd_epi16(ds_h, m_h));
+ }
+
+ const int64_t sign_sum =
+ (int64_t)_mm512_reduce_add_epi32(_mm512_add_epi32(acc0, acc1));
+ return sign_sum > limit;
+}
+
+void av1_wedge_compute_delta_squares_avx512(int16_t *d, const int16_t *a,
+ const int16_t *b, int N) {
+ assert(N % 64 == 0);
+ const __m512i zero = _mm512_setzero_si512();
+ for (int i = 0; i < N; i += 64) {
+ const __m512i a_l = _mm512_loadu_si512((const __m512i *)(a + i));
+ const __m512i a_h = _mm512_loadu_si512((const __m512i *)(a + i + 32));
+ const __m512i b_l = _mm512_loadu_si512((const __m512i *)(b + i));
+ const __m512i b_h = _mm512_loadu_si512((const __m512i *)(b + i + 32));
+
+ const __m512i nb_l = _mm512_subs_epi16(zero, b_l);
+ const __m512i nb_h = _mm512_subs_epi16(zero, b_h);
+
+ const __m512i r0 = _mm512_madd_epi16(_mm512_unpacklo_epi16(a_l, b_l),
+ _mm512_unpacklo_epi16(a_l, nb_l));
+ const __m512i r1 = _mm512_madd_epi16(_mm512_unpackhi_epi16(a_l, b_l),
+ _mm512_unpackhi_epi16(a_l, nb_l));
+ const __m512i r2 = _mm512_madd_epi16(_mm512_unpacklo_epi16(a_h, b_h),
+ _mm512_unpacklo_epi16(a_h, nb_h));
+ const __m512i r3 = _mm512_madd_epi16(_mm512_unpackhi_epi16(a_h, b_h),
+ _mm512_unpackhi_epi16(a_h, nb_h));
+
+ const __m512i res_l = _mm512_packs_epi32(r0, r1);
+ const __m512i res_h = _mm512_packs_epi32(r2, r3);
+
+ _mm512_storeu_si512((__m512i *)(d + i), res_l);
+ _mm512_storeu_si512((__m512i *)(d + i + 32), res_h);
+ }
+}
diff --git a/av1/encoder/x86/temporal_filter_avx512.c b/av1/encoder/x86/temporal_filter_avx512.c
new file mode 100644
index 0000000000..67e7c556f1
--- /dev/null
+++ b/av1/encoder/x86/temporal_filter_avx512.c
@@ -0,0 +1,878 @@
+/*
+ * Copyright (c) 2026, Alliance for Open Media. All rights reserved.
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#if !defined(AVX512_EMU_H_) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC target("avx2,avx512f,avx512cd,avx512bw,avx512dq,avx512vl")
+#endif
+
+#include <assert.h>
+#include <immintrin.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config/aom_config.h"
+#include "config/av1_rtcd.h"
+#include "aom_dsp/mathutils.h"
+#include "aom_ports/mem.h"
+#include "av1/encoder/encoder.h"
+#include "av1/encoder/temporal_filter.h"
+
+#define SSE_STRIDE_AVX512 (BW + 4)
+
+double av1_estimate_noise_from_single_plane_avx512(const uint8_t *src,
+ int height, int width,
+ int stride,
+ int edge_thresh) {
+ int count = 0;
+ int64_t accum = 0;
+ const int w32 = (width - 1) & ~0x1f;
+ const __m512i edge_threshold = _mm512_set1_epi16((int16_t)edge_thresh);
+ const __m512i one16 = _mm512_set1_epi16(1);
+ __m512i sum_accumulator = _mm512_setzero_si512();
+
+ for (int w = 1; w < w32; w += 32) {
+ int h = 1;
+ const int start_idx = h * stride + w;
+ const int stride_0 = start_idx - stride;
+
+ const __m512i A = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[stride_0 - 1])));
+ const __m512i C = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[stride_0 + 1])));
+ const __m512i D = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[start_idx - 1])));
+ const __m512i F = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[start_idx + 1])));
+ __m512i B = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[stride_0])));
+ __m512i E = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[start_idx])));
+
+ __m512i sub_AC = _mm512_sub_epi16(A, C);
+ __m512i sum_AC = _mm512_add_epi16(A, C);
+ __m512i sub_DF = _mm512_sub_epi16(D, F);
+ __m512i sum_DF = _mm512_add_epi16(D, F);
+
+ for (; h < height - 1; h++) {
+ const int k = h * stride + w;
+ const __m512i G = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[k + stride - 1])));
+ const __m512i H = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[k + stride])));
+ const __m512i I = _mm512_cvtepu8_epi16(
+ _mm256_loadu_si256((const __m256i *)(&src[k + stride + 1])));
+
+ const __m512i sub_GI = _mm512_sub_epi16(G, I);
+ const __m512i sum_GI = _mm512_add_epi16(G, I);
+ const __m512i sub_BH = _mm512_sub_epi16(B, H);
+
+ const __m512i gx = _mm512_abs_epi16(_mm512_add_epi16(
+ _mm512_add_epi16(sub_AC, sub_GI), _mm512_slli_epi16(sub_DF, 1)));
+ const __m512i gy = _mm512_abs_epi16(_mm512_add_epi16(
+ _mm512_sub_epi16(sum_AC, sum_GI), _mm512_slli_epi16(sub_BH, 1)));
+ const __m512i ga = _mm512_add_epi16(gx, gy);
+
+ const __mmask32 mask = _mm512_cmpgt_epi16_mask(edge_threshold, ga);
+ if (mask != 0) {
+ const __m512i sum_BH = _mm512_add_epi16(B, H);
+ const __m512i sum_DFBH =
+ _mm512_slli_epi16(_mm512_add_epi16(sum_DF, sum_BH), 1);
+ const __m512i sum_ACGI = _mm512_add_epi16(sum_AC, sum_GI);
+ const __m512i v = _mm512_add_epi16(
+ _mm512_sub_epi16(_mm512_slli_epi16(E, 2), sum_DFBH), sum_ACGI);
+ const __m512i var = _mm512_maskz_abs_epi16(mask, v);
+ sum_accumulator =
+ _mm512_add_epi32(sum_accumulator, _mm512_madd_epi16(var, one16));
+ count += __builtin_popcount((uint32_t)mask);
+ }
+
+ sub_AC = sub_DF;
+ sub_DF = sub_GI;
+ sum_AC = sum_DF;
+ sum_DF = sum_GI;
+ B = E;
+ E = H;
+ }
+ }
+
+ for (int h = 1; h < height - 1; ++h) {
+ for (int w = w32 + 1; w < width - 1; ++w) {
+ const int k = h * stride + w;
+ const int g_x = (src[k - stride - 1] - src[k - stride + 1]) +
+ (src[k + stride - 1] - src[k + stride + 1]) +
+ 2 * (src[k - 1] - src[k + 1]);
+ const int g_y = (src[k - stride - 1] - src[k + stride - 1]) +
+ (src[k - stride + 1] - src[k + stride + 1]) +
+ 2 * (src[k - stride] - src[k + stride]);
+ const int ga = abs(g_x) + abs(g_y);
+ if (ga < edge_thresh) {
+ const int v =
+ 4 * src[k] -
+ 2 * (src[k - 1] + src[k + 1] + src[k - stride] + src[k + stride]) +
+ (src[k - stride - 1] + src[k - stride + 1] + src[k + stride - 1] +
+ src[k + stride + 1]);
+ accum += abs(v);
+ ++count;
+ }
+ }
+ }
+
+ accum += _mm512_reduce_add_epi32(sum_accumulator);
+ return (count < 16) ? -1.0 : (double)accum / (6 * count) * SQRT_PI_BY_2;
+}
+
+#if CONFIG_AV1_HIGHBITDEPTH
+double av1_highbd_estimate_noise_from_single_plane_avx512(const uint16_t *src16,
+ int height, int width,
+ int stride,
+ int bit_depth,
+ int edge_thresh) {
+ int count = 0;
+ int64_t accum = 0;
+ const int w16 = (width - 2) & ~0x0f;
+ const int shift = bit_depth - 8;
+ const int round_val = shift > 0 ? (1 << (shift - 1)) : 0;
+ const __m512i v_round = _mm512_set1_epi32(round_val);
+ const __m512i v_edge_thresh = _mm512_set1_epi32(edge_thresh);
+ __m512i sum_accumulator = _mm512_setzero_si512();
+
+ for (int w = 1; w < w16; w += 16) {
+ int h = 1;
+ const int start_idx = h * stride + w;
+ const int stride_0 = start_idx - stride;
+
+ const __m512i A = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[stride_0 - 1])));
+ const __m512i C = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[stride_0 + 1])));
+ const __m512i D = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[start_idx - 1])));
+ const __m512i F = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[start_idx + 1])));
+ __m512i B = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[stride_0])));
+ __m512i E = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[start_idx])));
+
+ __m512i sub_AC = _mm512_sub_epi32(A, C);
+ __m512i sum_AC = _mm512_add_epi32(A, C);
+ __m512i sub_DF = _mm512_sub_epi32(D, F);
+ __m512i sum_DF = _mm512_add_epi32(D, F);
+
+ for (; h < height - 1; h++) {
+ const int k = h * stride + w;
+ const __m512i G = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[k + stride - 1])));
+ const __m512i H = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[k + stride])));
+ const __m512i I = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(&src16[k + stride + 1])));
+
+ const __m512i sub_GI = _mm512_sub_epi32(G, I);
+ const __m512i sum_GI = _mm512_add_epi32(G, I);
+ const __m512i sub_BH = _mm512_sub_epi32(B, H);
+
+ const __m512i gx = _mm512_abs_epi32(_mm512_add_epi32(
+ _mm512_add_epi32(sub_AC, sub_GI), _mm512_slli_epi32(sub_DF, 1)));
+ const __m512i gy = _mm512_abs_epi32(_mm512_add_epi32(
+ _mm512_sub_epi32(sum_AC, sum_GI), _mm512_slli_epi32(sub_BH, 1)));
+ const __m512i ga =
+ _mm512_srai_epi32(_mm512_add_epi32(_mm512_add_epi32(gx, gy), v_round),
+ (unsigned int)shift);
+
+ const __mmask16 mask = _mm512_cmpgt_epi32_mask(v_edge_thresh, ga);
+ if (mask != 0) {
+ const __m512i sum_BH = _mm512_add_epi32(B, H);
+ const __m512i sum_DFBH =
+ _mm512_slli_epi32(_mm512_add_epi32(sum_DF, sum_BH), 1);
+ const __m512i sum_ACGI = _mm512_add_epi32(sum_AC, sum_GI);
+ const __m512i v = _mm512_add_epi32(
+ _mm512_sub_epi32(_mm512_slli_epi32(E, 2), sum_DFBH), sum_ACGI);
+ const __m512i abs_v = _mm512_abs_epi32(v);
+ const __m512i scaled_v = _mm512_srai_epi32(
+ _mm512_add_epi32(abs_v, v_round), (unsigned int)shift);
+ sum_accumulator = _mm512_mask_add_epi32(sum_accumulator, mask,
+ sum_accumulator, scaled_v);
+ count += __builtin_popcount((uint32_t)mask);
+ }
+
+ sub_AC = sub_DF;
+ sub_DF = sub_GI;
+ sum_AC = sum_DF;
+ sum_DF = sum_GI;
+ B = E;
+ E = H;
+ }
+ }
+
+ for (int i = 1; i < height - 1; ++i) {
+ for (int j = w16 + 1; j < width - 1; ++j) {
+ const int k = i * stride + j;
+ const int Gx = (src16[k - stride - 1] - src16[k - stride + 1]) +
+ (src16[k + stride - 1] - src16[k + stride + 1]) +
+ 2 * (src16[k - 1] - src16[k + 1]);
+ const int Gy = (src16[k - stride - 1] - src16[k + stride - 1]) +
+ (src16[k - stride + 1] - src16[k + stride + 1]) +
+ 2 * (src16[k - stride] - src16[k + stride]);
+ const int Ga = ROUND_POWER_OF_TWO(abs(Gx) + abs(Gy), shift);
+ if (Ga < edge_thresh) {
+ const int v = 4 * src16[k] -
+ 2 * (src16[k - 1] + src16[k + 1] + src16[k - stride] +
+ src16[k + stride]) +
+ (src16[k - stride - 1] + src16[k - stride + 1] +
+ src16[k + stride - 1] + src16[k + stride + 1]);
+ accum += ROUND_POWER_OF_TWO(abs(v), shift);
+ ++count;
+ }
+ }
+ }
+
+ accum += _mm512_reduce_add_epi32(sum_accumulator);
+ return (count < 16) ? -1.0 : (double)accum / (6 * count) * SQRT_PI_BY_2;
+}
+#endif // CONFIG_AV1_HIGHBITDEPTH
+
+static AOM_FORCE_INLINE void get_squared_error_avx512(
+ const uint8_t *frame1, const unsigned int stride, const uint8_t *frame2,
+ const unsigned int stride2, const int block_width, const int block_height,
+ uint16_t *frame_sse, const unsigned int sse_stride) {
+ const uint8_t *src1 = frame1;
+ const uint8_t *src2 = frame2;
+ uint16_t *dst = frame_sse + 2;
+ for (int i = 0; i < block_height; i++) {
+ for (int j = 0; j < block_width; j += 32) {
+ const __m256i vsrc1 = _mm256_loadu_si256((const __m256i *)(src1 + j));
+ const __m256i vsrc2 = _mm256_loadu_si256((const __m256i *)(src2 + j));
+ const __m512i s1 = _mm512_cvtepu8_epi16(vsrc1);
+ const __m512i s2 = _mm512_cvtepu8_epi16(vsrc2);
+ const __m512i diff = _mm512_sub_epi16(s1, s2);
+ const __m512i res = _mm512_mullo_epi16(diff, diff);
+ _mm512_storeu_si512((__m512i *)(dst + j), res);
+ }
+ dst[-2] = dst[-1] = dst[0];
+ dst[block_width] = dst[block_width + 1] = dst[block_width - 1];
+ src1 += stride;
+ src2 += stride2;
+ dst += sse_stride;
+ }
+}
+
+static AOM_FORCE_INLINE __m512i load_and_sum5_row_avx512(const uint16_t *src) {
+ const __m512i c0 =
+ _mm512_cvtepu16_epi32(_mm256_loadu_si256((const __m256i *)(src - 2)));
+ const __m512i c1 =
+ _mm512_cvtepu16_epi32(_mm256_loadu_si256((const __m256i *)(src - 1)));
+ const __m512i c2 =
+ _mm512_cvtepu16_epi32(_mm256_loadu_si256((const __m256i *)(src)));
+ const __m512i c3 =
+ _mm512_cvtepu16_epi32(_mm256_loadu_si256((const __m256i *)(src + 1)));
+ const __m512i c4 =
+ _mm512_cvtepu16_epi32(_mm256_loadu_si256((const __m256i *)(src + 2)));
+ return _mm512_add_epi32(_mm512_add_epi32(c0, c1),
+ _mm512_add_epi32(_mm512_add_epi32(c2, c3), c4));
+}
+
+static inline __m256 approx_exp_avx512(__m256 y) {
+#define A ((1 << 23) / 0.69314718056f)
+#define B 127
+#define C 60801
+ const __m256 multiplier = _mm256_set1_ps(A);
+ const __m256i offset = _mm256_set1_epi32(B * (1 << 23) - C);
+
+ y = _mm256_mul_ps(y, multiplier);
+ y = _mm256_castsi256_ps(_mm256_add_epi32(_mm256_cvttps_epi32(y), offset));
+ return y;
+#undef A
+#undef B
+#undef C
+}
+
+// Bit-exact 512-bit AVX-512 double-precision implementation of exp(-x) for 8
+// lanes simultaneously on x in [0, 7].
+static inline __m512d exact_exp_neg_pd_avx512(__m512d x) {
+ x = _mm512_min_pd(x, _mm512_set1_pd(7.0));
+ const __m512d inv_ln2 = _mm512_set1_pd(1.44269504088896340736);
+ const __m512d ln2_hi = _mm512_set1_pd(0.6931471805596629565116);
+ const __m512d ln2_lo = _mm512_set1_pd(0.2823529056303157712259e-12);
+ const __m512d k = _mm512_roundscale_pd(
+ _mm512_mul_pd(x, inv_ln2), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
+ const __m512d r = _mm512_add_pd(_mm512_sub_pd(_mm512_mul_pd(k, ln2_hi), x),
+ _mm512_mul_pd(k, ln2_lo));
+ const __m512d c1 = _mm512_set1_pd(1.0);
+ const __m512d c2 = _mm512_set1_pd(0.5);
+ const __m512d c3 = _mm512_set1_pd(1.0 / 6.0);
+ const __m512d c4 = _mm512_set1_pd(1.0 / 24.0);
+ const __m512d c5 = _mm512_set1_pd(1.0 / 120.0);
+ const __m512d c6 = _mm512_set1_pd(1.0 / 720.0);
+ const __m512d c7 = _mm512_set1_pd(1.0 / 5040.0);
+ __m512d p = _mm512_add_pd(_mm512_mul_pd(c7, r), c6);
+ p = _mm512_add_pd(_mm512_mul_pd(p, r), c5);
+ p = _mm512_add_pd(_mm512_mul_pd(p, r), c4);
+ p = _mm512_add_pd(_mm512_mul_pd(p, r), c3);
+ p = _mm512_add_pd(_mm512_mul_pd(p, r), c2);
+ p = _mm512_add_pd(_mm512_mul_pd(p, r), c1);
+ p = _mm512_add_pd(_mm512_mul_pd(p, r), c1);
+ const __m256i ki = _mm512_cvtpd_epi32(k);
+ const __m512i ki64 =
+ _mm512_cvtepi32_epi64(_mm256_sub_epi32(_mm256_set1_epi32(1023), ki));
+ const __m512d pow2 = _mm512_castsi512_pd(_mm512_slli_epi64(ki64, 52));
+ return _mm512_mul_pd(p, pow2);
+}
+
+static void apply_temporal_filter_avx512(
+ const uint8_t *frame1, const unsigned int stride, const uint8_t *frame2,
+ const unsigned int stride2, const int block_width, const int block_height,
+ const int *subblock_mses, unsigned int *accumulator, uint16_t *count,
+ uint16_t *frame_sse, uint32_t *luma_sse_sum,
+ const double inv_num_ref_pixels, const double decay_factor,
+ const double inv_factor, const double weight_factor, double *d_factor,
+ int tf_wgt_calc_lvl) {
+ assert(((block_width == 64) || (block_width == 32)) &&
+ ((block_height == 64) || (block_height == 32)));
+
+ DECLARE_ALIGNED(64, uint32_t, acc_5x5_sse[BH][BW]);
+
+ get_squared_error_avx512(frame1, stride, frame2, stride2, block_width,
+ block_height, frame_sse, SSE_STRIDE_AVX512);
+
+ __m512i vsrc[5];
+
+ for (int col = 0; col < block_width; col += 16) {
+ const uint16_t *src = frame_sse + 2 + col;
+
+ for (int i = 2; i < 5; i++) {
+ vsrc[i] = load_and_sum5_row_avx512(src);
+ src += SSE_STRIDE_AVX512;
+ }
+
+ vsrc[0] = vsrc[2];
+ vsrc[1] = vsrc[2];
+
+ for (int row = 0; row < block_height; row++) {
+ const __m512i vsum01 = _mm512_add_epi32(vsrc[0], vsrc[1]);
+ const __m512i vsum23 = _mm512_add_epi32(vsrc[2], vsrc[3]);
+ const __m512i vsum =
+ _mm512_add_epi32(_mm512_add_epi32(vsum01, vsum23), vsrc[4]);
+
+ _mm512_storeu_si512((__m512i *)&acc_5x5_sse[row][col], vsum);
+
+ vsrc[0] = vsrc[1];
+ vsrc[1] = vsrc[2];
+ vsrc[2] = vsrc[3];
+ vsrc[3] = vsrc[4];
+
+ if (row <= block_height - 4) {
+ vsrc[4] = load_and_sum5_row_avx512(src);
+ src += SSE_STRIDE_AVX512;
+ } else {
+ vsrc[4] = vsrc[3];
+ }
+ }
+ }
+
+ __m512d subblock_mses_reg[NUM_16X16];
+ __m512d d_factor_mul_n_decay_qr_invs[NUM_16X16];
+ for (int idx = 0; idx < NUM_16X16; idx++) {
+ subblock_mses_reg[idx] = _mm512_set1_pd(subblock_mses[idx] * inv_factor);
+ d_factor_mul_n_decay_qr_invs[idx] =
+ _mm512_set1_pd(d_factor[idx] * decay_factor);
+ }
+
+ const __m256 zero = _mm256_set1_ps(0.0f);
+ const __m256 point_five = _mm256_set1_ps(0.5f);
+ const __m256 seven = _mm256_set1_ps(7.0f);
+ const __m512d inv_num_ref_pixel_512 = _mm512_set1_pd(inv_num_ref_pixels);
+ const __m512d weight_factor_512 = _mm512_set1_pd(weight_factor);
+ const __m256 tf_weight_scale = _mm256_set1_ps((float)TF_WEIGHT_SCALE);
+ const __m512d tf_weight_scale_pd = _mm512_set1_pd((double)TF_WEIGHT_SCALE);
+
+ for (int i = 0; i < block_height; i++) {
+ const int y32_blk_raster_offset = (i >= (block_height >> 1)) << 1;
+ const int y16_blk_raster_offset =
+ ((i % (block_height >> 1)) >= (block_height >> 2)) << 1;
+ uint32_t *luma_sse_sum_temp = luma_sse_sum + i * BW;
+ for (int j = 0; j < block_width; j += 8) {
+ const __m256i acc_sse =
+ _mm256_loadu_si256((const __m256i *)(acc_5x5_sse[i] + j));
+ const __m256i luma_sse =
+ _mm256_loadu_si256((const __m256i *)(luma_sse_sum_temp + j));
+ const __m256i diff_sse = _mm256_add_epi32(acc_sse, luma_sse);
+ const __m512d diff_sse_pd = _mm512_cvtepi32_pd(diff_sse);
+ const __m512d window_error =
+ _mm512_mul_pd(diff_sse_pd, inv_num_ref_pixel_512);
+
+ const int x32_blk_raster_offset = (j >= (block_width >> 1));
+ const int x16_blk_raster_offset =
+ ((j % (block_width >> 1)) >= (block_width >> 2));
+ const int subblock_idx =
+ ((y32_blk_raster_offset + x32_blk_raster_offset) << 2) +
+ (y16_blk_raster_offset + x16_blk_raster_offset);
+
+ const __m512d combined_error =
+ _mm512_add_pd(_mm512_mul_pd(window_error, weight_factor_512),
+ subblock_mses_reg[subblock_idx]);
+ const __m512d scaled_error = _mm512_mul_pd(
+ combined_error, d_factor_mul_n_decay_qr_invs[subblock_idx]);
+
+ __m256i weights_in_32bit;
+ if (tf_wgt_calc_lvl == 0) {
+ weights_in_32bit = _mm512_cvttpd_epi32(_mm512_mul_pd(
+ exact_exp_neg_pd_avx512(scaled_error), tf_weight_scale_pd));
+ } else {
+ const __m256 scaled_error_ps = _mm512_cvtpd_ps(scaled_error);
+ const __m256 scaled_diff_ps = _mm256_min_ps(scaled_error_ps, seven);
+ const __m256 minus_scaled_diff_ps = _mm256_sub_ps(zero, scaled_diff_ps);
+ const __m256 exp_result = approx_exp_avx512(minus_scaled_diff_ps);
+ const __m256 scale_weight_exp_result =
+ _mm256_mul_ps(exp_result, tf_weight_scale);
+ const __m256 round_result =
+ _mm256_add_ps(scale_weight_exp_result, point_five);
+ weights_in_32bit = _mm256_cvttps_epi32(round_result);
+ }
+
+ const __m128i weights_in_16bit =
+ _mm_packus_epi32(_mm256_castsi256_si128(weights_in_32bit),
+ _mm256_extracti128_si256(weights_in_32bit, 0x1));
+
+ const int stride_idx = i * stride2 + j;
+ const __m128i count_array =
+ _mm_loadu_si128((const __m128i *)(count + stride_idx));
+ _mm_storeu_si128((__m128i *)(count + stride_idx),
+ _mm_add_epi16(count_array, weights_in_16bit));
+
+ const __m256i accumulator_array =
+ _mm256_loadu_si256((const __m256i *)(accumulator + stride_idx));
+ const __m128i pred_values =
+ _mm_loadl_epi64((const __m128i *)(frame2 + stride_idx));
+ const __m256i pred_values_u32 = _mm256_cvtepu8_epi32(pred_values);
+ const __m256i mull_frame2_weight_u32 =
+ _mm256_mullo_epi32(pred_values_u32, weights_in_32bit);
+ _mm256_storeu_si256(
+ (__m256i *)(accumulator + stride_idx),
+ _mm256_add_epi32(accumulator_array, mull_frame2_weight_u32));
+ }
+ }
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+__attribute__((force_align_arg_pointer))
+#endif
+void av1_apply_temporal_filter_avx512(
+ const YV12_BUFFER_CONFIG *frame_to_filter, const MACROBLOCKD *mbd,
+ const BLOCK_SIZE block_size, const int mb_row, const int mb_col,
+ const int num_planes, const double *noise_levels, const MV *subblock_mvs,
+ const int *subblock_mses, const int q_factor, const int filter_strength,
+ int tf_wgt_calc_lvl, const uint8_t *pred, uint32_t *accum,
+ uint16_t *count) {
+ const int is_high_bitdepth = frame_to_filter->flags & YV12_FLAG_HIGHBITDEPTH;
+ assert(block_size == BLOCK_64X64 && "Only support 64x64 block with avx512!");
+ assert(TF_WINDOW_LENGTH == 5 && "Only support window length 5 with avx512!");
+ assert(!is_high_bitdepth && "Only support low bit-depth with avx512!");
+ assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE);
+ (void)is_high_bitdepth;
+
+ const int mb_height = block_size_high[block_size];
+ const int mb_width = block_size_wide[block_size];
+ const int frame_height = frame_to_filter->y_crop_height;
+ const int frame_width = frame_to_filter->y_crop_width;
+ const int min_frame_size = AOMMIN(frame_height, frame_width);
+ const double inv_factor = 1.0 / ((TF_WINDOW_BLOCK_BALANCE_WEIGHT + 1) *
+ TF_SEARCH_ERROR_NORM_WEIGHT);
+ const double weight_factor =
+ (double)TF_WINDOW_BLOCK_BALANCE_WEIGHT * inv_factor;
+ double q_decay = pow((double)q_factor / TF_Q_DECAY_THRESHOLD, 2);
+ q_decay = CLIP(q_decay, 1e-5, 1);
+ if (q_factor >= TF_QINDEX_CUTOFF) {
+ q_decay = 0.5 * pow((double)q_factor / 64, 2);
+ }
+ double s_decay = pow((double)filter_strength / TF_STRENGTH_THRESHOLD, 2);
+ s_decay = CLIP(s_decay, 1e-5, 1);
+ double d_factor[NUM_16X16] = { 0 };
+ uint16_t *frame_sse = (uint16_t *)aom_memalign(
+ 64, sizeof(frame_sse[0]) * SSE_STRIDE_AVX512 * BH);
+ uint32_t *luma_sse_sum =
+ (uint32_t *)aom_memalign(64, sizeof(luma_sse_sum[0]) * BW * BH);
+ memset(frame_sse, 0, sizeof(frame_sse[0]) * SSE_STRIDE_AVX512 * BH);
+ memset(luma_sse_sum, 0, sizeof(luma_sse_sum[0]) * BW * BH);
+
+ double distance_threshold = min_frame_size * TF_SEARCH_DISTANCE_THRESHOLD;
+ distance_threshold = AOMMAX(distance_threshold, 1);
+ for (int subblock_idx = 0; subblock_idx < NUM_16X16; subblock_idx++) {
+ const MV mv = subblock_mvs[subblock_idx];
+ const double distance = sqrt(pow(mv.row, 2) + pow(mv.col, 2));
+ d_factor[subblock_idx] = distance / distance_threshold;
+ d_factor[subblock_idx] = AOMMAX(d_factor[subblock_idx], 1);
+ }
+
+ int plane_offset = 0;
+ for (int plane = 0; plane < num_planes; ++plane) {
+ const uint32_t plane_h = mb_height >> mbd->plane[plane].subsampling_y;
+ const uint32_t plane_w = mb_width >> mbd->plane[plane].subsampling_x;
+ const uint32_t frame_stride = frame_to_filter->strides[plane == 0 ? 0 : 1];
+ const int frame_offset = mb_row * plane_h * frame_stride + mb_col * plane_w;
+
+ const uint8_t *ref = frame_to_filter->buffers[plane] + frame_offset;
+ const int ss_x_shift =
+ mbd->plane[plane].subsampling_x - mbd->plane[AOM_PLANE_Y].subsampling_x;
+ const int ss_y_shift =
+ mbd->plane[plane].subsampling_y - mbd->plane[AOM_PLANE_Y].subsampling_y;
+ const int num_ref_pixels = TF_WINDOW_LENGTH * TF_WINDOW_LENGTH +
+ ((plane) ? (1 << (ss_x_shift + ss_y_shift)) : 0);
+ const double inv_num_ref_pixels = 1.0 / num_ref_pixels;
+ const double n_decay = 0.5 + log(2 * noise_levels[plane] + 5.0);
+ const double decay_factor = 1 / (n_decay * q_decay * s_decay);
+
+ if (plane == AOM_PLANE_U) {
+ if (ss_x_shift == 1 && ss_y_shift == 1) {
+ const __m512i mask_lo16 = _mm512_set1_epi32(0x0000FFFF);
+ for (unsigned int i = 0; i < plane_h; i++) {
+ const uint16_t *src_0 = &frame_sse[2 * i * SSE_STRIDE_AVX512 + 2];
+ const uint16_t *src_1 =
+ &frame_sse[(2 * i + 1) * SSE_STRIDE_AVX512 + 2];
+ for (unsigned int j = 0; j < plane_w; j += 16) {
+ const __m512i r0 =
+ _mm512_loadu_si512((const __m512i *)(src_0 + j * 2));
+ const __m512i r1 =
+ _mm512_loadu_si512((const __m512i *)(src_1 + j * 2));
+ const __m512i sum0 = _mm512_add_epi32(
+ _mm512_and_si512(r0, mask_lo16), _mm512_srli_epi32(r0, 16));
+ const __m512i sum1 = _mm512_add_epi32(
+ _mm512_and_si512(r1, mask_lo16), _mm512_srli_epi32(r1, 16));
+ const __m512i res = _mm512_add_epi32(sum0, sum1);
+ _mm512_storeu_si512((__m512i *)&luma_sse_sum[i * BW + j], res);
+ }
+ }
+ } else {
+ for (unsigned int i = 0; i < plane_h; i++) {
+ for (unsigned int j = 0; j < plane_w; j++) {
+ for (int ii = 0; ii < (1 << ss_y_shift); ++ii) {
+ for (int jj = 0; jj < (1 << ss_x_shift); ++jj) {
+ const int yy = (i << ss_y_shift) + ii;
+ const int xx = (j << ss_x_shift) + jj;
+ luma_sse_sum[i * BW + j] +=
+ frame_sse[yy * SSE_STRIDE_AVX512 + xx + 2];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ apply_temporal_filter_avx512(
+ ref, frame_stride, pred + plane_offset, plane_w, plane_w, plane_h,
+ subblock_mses, accum + plane_offset, count + plane_offset, frame_sse,
+ luma_sse_sum, inv_num_ref_pixels, decay_factor, inv_factor,
+ weight_factor, d_factor, tf_wgt_calc_lvl);
+ plane_offset += plane_h * plane_w;
+ }
+ aom_free(frame_sse);
+ aom_free(luma_sse_sum);
+}
+
+#if CONFIG_AV1_HIGHBITDEPTH
+static AOM_FORCE_INLINE void highbd_get_squared_error_avx512(
+ const uint16_t *frame1, const unsigned int stride, const uint16_t *frame2,
+ const unsigned int stride2, const int block_width, const int block_height,
+ uint32_t *frame_sse, const unsigned int sse_stride) {
+ const uint16_t *src1 = frame1;
+ const uint16_t *src2 = frame2;
+ uint32_t *dst = frame_sse + 2;
+ for (int i = 0; i < block_height; i++) {
+ for (int j = 0; j < block_width; j += 16) {
+ const __m512i s1 = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src1 + j)));
+ const __m512i s2 = _mm512_cvtepu16_epi32(
+ _mm256_loadu_si256((const __m256i *)(src2 + j)));
+ const __m512i diff = _mm512_sub_epi32(s1, s2);
+ const __m512i res = _mm512_mullo_epi32(diff, diff);
+ _mm512_storeu_si512((__m512i *)(dst + j), res);
+ }
+ dst[-2] = dst[-1] = dst[0];
+ dst[block_width] = dst[block_width + 1] = dst[block_width - 1];
+ src1 += stride;
+ src2 += stride2;
+ dst += sse_stride;
+ }
+}
+
+static AOM_FORCE_INLINE __m512i
+highbd_load_and_sum5_row_avx512(const uint32_t *src) {
+ const __m512i c0 = _mm512_loadu_si512((const __m512i *)(src - 2));
+ const __m512i c1 = _mm512_loadu_si512((const __m512i *)(src - 1));
+ const __m512i c2 = _mm512_loadu_si512((const __m512i *)(src));
+ const __m512i c3 = _mm512_loadu_si512((const __m512i *)(src + 1));
+ const __m512i c4 = _mm512_loadu_si512((const __m512i *)(src + 2));
+ return _mm512_add_epi32(_mm512_add_epi32(c0, c1),
+ _mm512_add_epi32(_mm512_add_epi32(c2, c3), c4));
+}
+
+static void highbd_apply_temporal_filter_avx512(
+ const uint16_t *frame1, const unsigned int stride, const uint16_t *frame2,
+ const unsigned int stride2, const int block_width, const int block_height,
+ const int *subblock_mses, unsigned int *accumulator, uint16_t *count,
+ uint32_t *frame_sse, uint32_t *luma_sse_sum, int bd,
+ const double inv_num_ref_pixels, const double decay_factor,
+ const double inv_factor, const double weight_factor, double *d_factor,
+ int tf_wgt_calc_lvl) {
+ assert(((block_width == 64) || (block_width == 32)) &&
+ ((block_height == 64) || (block_height == 32)));
+
+ DECLARE_ALIGNED(64, uint32_t, acc_5x5_sse[BH][BW]);
+
+ highbd_get_squared_error_avx512(frame1, stride, frame2, stride2, block_width,
+ block_height, frame_sse, SSE_STRIDE_AVX512);
+
+ __m512i vsrc[5];
+
+ for (int col = 0; col < block_width; col += 16) {
+ const uint32_t *src = frame_sse + 2 + col;
+
+ for (int i = 2; i < 5; i++) {
+ vsrc[i] = highbd_load_and_sum5_row_avx512(src);
+ src += SSE_STRIDE_AVX512;
+ }
+
+ vsrc[0] = vsrc[2];
+ vsrc[1] = vsrc[2];
+
+ for (int row = 0; row < block_height; row++) {
+ const __m512i vsum01 = _mm512_add_epi32(vsrc[0], vsrc[1]);
+ const __m512i vsum23 = _mm512_add_epi32(vsrc[2], vsrc[3]);
+ const __m512i vsum =
+ _mm512_add_epi32(_mm512_add_epi32(vsum01, vsum23), vsrc[4]);
+
+ _mm512_storeu_si512((__m512i *)&acc_5x5_sse[row][col], vsum);
+
+ vsrc[0] = vsrc[1];
+ vsrc[1] = vsrc[2];
+ vsrc[2] = vsrc[3];
+ vsrc[3] = vsrc[4];
+
+ if (row <= block_height - 4) {
+ vsrc[4] = highbd_load_and_sum5_row_avx512(src);
+ src += SSE_STRIDE_AVX512;
+ } else {
+ vsrc[4] = vsrc[3];
+ }
+ }
+ }
+
+ __m512d subblock_mses_reg[NUM_16X16];
+ __m512d d_factor_mul_n_decay_qr_invs[NUM_16X16];
+ for (int idx = 0; idx < NUM_16X16; idx++) {
+ subblock_mses_reg[idx] = _mm512_set1_pd(subblock_mses[idx] * inv_factor);
+ d_factor_mul_n_decay_qr_invs[idx] =
+ _mm512_set1_pd(d_factor[idx] * decay_factor);
+ }
+
+ const unsigned int bd_shift = (unsigned int)((bd - 8) * 2);
+ const __m256 zero = _mm256_set1_ps(0.0f);
+ const __m256 point_five = _mm256_set1_ps(0.5f);
+ const __m256 seven = _mm256_set1_ps(7.0f);
+ const __m512d inv_num_ref_pixel_512 = _mm512_set1_pd(inv_num_ref_pixels);
+ const __m512d weight_factor_512 = _mm512_set1_pd(weight_factor);
+ const __m256 tf_weight_scale = _mm256_set1_ps((float)TF_WEIGHT_SCALE);
+ const __m512d tf_weight_scale_pd = _mm512_set1_pd((double)TF_WEIGHT_SCALE);
+
+ for (int i = 0; i < block_height; i++) {
+ const int y32_blk_raster_offset = (i >= (block_height >> 1)) << 1;
+ const int y16_blk_raster_offset =
+ ((i % (block_height >> 1)) >= (block_height >> 2)) << 1;
+ uint32_t *luma_sse_sum_temp = luma_sse_sum + i * BW;
+ for (int j = 0; j < block_width; j += 8) {
+ const __m256i acc_sse =
+ _mm256_loadu_si256((const __m256i *)(acc_5x5_sse[i] + j));
+ const __m256i luma_sse =
+ _mm256_loadu_si256((const __m256i *)(luma_sse_sum_temp + j));
+ const __m256i diff_sse =
+ _mm256_srli_epi32(_mm256_add_epi32(acc_sse, luma_sse), bd_shift);
+ const __m512d diff_sse_pd = _mm512_cvtepu32_pd(diff_sse);
+ const __m512d window_error =
+ _mm512_mul_pd(diff_sse_pd, inv_num_ref_pixel_512);
+
+ const int x32_blk_raster_offset = (j >= (block_width >> 1));
+ const int x16_blk_raster_offset =
+ ((j % (block_width >> 1)) >= (block_width >> 2));
+ const int subblock_idx =
+ ((y32_blk_raster_offset + x32_blk_raster_offset) << 2) +
+ (y16_blk_raster_offset + x16_blk_raster_offset);
+
+ const __m512d combined_error =
+ _mm512_add_pd(_mm512_mul_pd(window_error, weight_factor_512),
+ subblock_mses_reg[subblock_idx]);
+ const __m512d scaled_error = _mm512_mul_pd(
+ combined_error, d_factor_mul_n_decay_qr_invs[subblock_idx]);
+
+ __m256i weights_in_32bit;
+ if (tf_wgt_calc_lvl == 0) {
+ weights_in_32bit = _mm512_cvttpd_epi32(_mm512_mul_pd(
+ exact_exp_neg_pd_avx512(scaled_error), tf_weight_scale_pd));
+ } else {
+ const __m256 scaled_error_ps = _mm512_cvtpd_ps(scaled_error);
+ const __m256 scaled_diff_ps = _mm256_min_ps(scaled_error_ps, seven);
+ const __m256 minus_scaled_diff_ps = _mm256_sub_ps(zero, scaled_diff_ps);
+ const __m256 exp_result = approx_exp_avx512(minus_scaled_diff_ps);
+ const __m256 scale_weight_exp_result =
+ _mm256_mul_ps(exp_result, tf_weight_scale);
+ const __m256 round_result =
+ _mm256_add_ps(scale_weight_exp_result, point_five);
+ weights_in_32bit = _mm256_cvttps_epi32(round_result);
+ }
+
+ const __m128i weights_in_16bit =
+ _mm_packus_epi32(_mm256_castsi256_si128(weights_in_32bit),
+ _mm256_extracti128_si256(weights_in_32bit, 0x1));
+
+ const int stride_idx = i * stride2 + j;
+ const __m128i count_array =
+ _mm_loadu_si128((const __m128i *)(count + stride_idx));
+ _mm_storeu_si128((__m128i *)(count + stride_idx),
+ _mm_add_epi16(count_array, weights_in_16bit));
+
+ const __m256i accumulator_array =
+ _mm256_loadu_si256((const __m256i *)(accumulator + stride_idx));
+ const __m128i pred_values =
+ _mm_loadu_si128((const __m128i *)(frame2 + stride_idx));
+ const __m256i pred_values_u32 = _mm256_cvtepu16_epi32(pred_values);
+ const __m256i mull_frame2_weight_u32 =
+ _mm256_mullo_epi32(pred_values_u32, weights_in_32bit);
+ _mm256_storeu_si256(
+ (__m256i *)(accumulator + stride_idx),
+ _mm256_add_epi32(accumulator_array, mull_frame2_weight_u32));
+ }
+ }
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+__attribute__((force_align_arg_pointer))
+#endif
+void av1_highbd_apply_temporal_filter_avx512(
+ const YV12_BUFFER_CONFIG *frame_to_filter, const MACROBLOCKD *mbd,
+ const BLOCK_SIZE block_size, const int mb_row, const int mb_col,
+ const int num_planes, const double *noise_levels, const MV *subblock_mvs,
+ const int *subblock_mses, const int q_factor, const int filter_strength,
+ int tf_wgt_calc_lvl, const uint8_t *pred, uint32_t *accum,
+ uint16_t *count) {
+ const int is_high_bitdepth = frame_to_filter->flags & YV12_FLAG_HIGHBITDEPTH;
+ assert(block_size == BLOCK_64X64 && "Only support 64x64 block with avx512!");
+ assert(TF_WINDOW_LENGTH == 5 && "Only support window length 5 with avx512!");
+ assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE);
+ (void)is_high_bitdepth;
+
+ const int mb_height = block_size_high[block_size];
+ const int mb_width = block_size_wide[block_size];
+ const int frame_height = frame_to_filter->y_crop_height;
+ const int frame_width = frame_to_filter->y_crop_width;
+ const int min_frame_size = AOMMIN(frame_height, frame_width);
+ const double inv_factor = 1.0 / ((TF_WINDOW_BLOCK_BALANCE_WEIGHT + 1) *
+ TF_SEARCH_ERROR_NORM_WEIGHT);
+ const double weight_factor =
+ (double)TF_WINDOW_BLOCK_BALANCE_WEIGHT * inv_factor;
+ double q_decay = pow((double)q_factor / TF_Q_DECAY_THRESHOLD, 2);
+ q_decay = CLIP(q_decay, 1e-5, 1);
+ if (q_factor >= TF_QINDEX_CUTOFF) {
+ q_decay = 0.5 * pow((double)q_factor / 64, 2);
+ }
+ double s_decay = pow((double)filter_strength / TF_STRENGTH_THRESHOLD, 2);
+ s_decay = CLIP(s_decay, 1e-5, 1);
+ double d_factor[NUM_16X16] = { 0 };
+ uint32_t *frame_sse = (uint32_t *)aom_memalign(
+ 64, sizeof(frame_sse[0]) * SSE_STRIDE_AVX512 * BH);
+ uint32_t *luma_sse_sum =
+ (uint32_t *)aom_memalign(64, sizeof(luma_sse_sum[0]) * BW * BH);
+ memset(frame_sse, 0, sizeof(frame_sse[0]) * SSE_STRIDE_AVX512 * BH);
+ memset(luma_sse_sum, 0, sizeof(luma_sse_sum[0]) * BW * BH);
+ uint16_t *pred1 = CONVERT_TO_SHORTPTR(pred);
+
+ double distance_threshold = min_frame_size * TF_SEARCH_DISTANCE_THRESHOLD;
+ distance_threshold = AOMMAX(distance_threshold, 1);
+ for (int subblock_idx = 0; subblock_idx < NUM_16X16; subblock_idx++) {
+ const MV mv = subblock_mvs[subblock_idx];
+ const double distance = sqrt(pow(mv.row, 2) + pow(mv.col, 2));
+ d_factor[subblock_idx] = distance / distance_threshold;
+ d_factor[subblock_idx] = AOMMAX(d_factor[subblock_idx], 1);
+ }
+
+ int plane_offset = 0;
+ for (int plane = 0; plane < num_planes; ++plane) {
+ const uint32_t plane_h = mb_height >> mbd->plane[plane].subsampling_y;
+ const uint32_t plane_w = mb_width >> mbd->plane[plane].subsampling_x;
+ const uint32_t frame_stride = frame_to_filter->strides[plane == 0 ? 0 : 1];
+ const int frame_offset = mb_row * plane_h * frame_stride + mb_col * plane_w;
+
+ const uint16_t *ref =
+ CONVERT_TO_SHORTPTR(frame_to_filter->buffers[plane]) + frame_offset;
+ const int ss_x_shift =
+ mbd->plane[plane].subsampling_x - mbd->plane[AOM_PLANE_Y].subsampling_x;
+ const int ss_y_shift =
+ mbd->plane[plane].subsampling_y - mbd->plane[AOM_PLANE_Y].subsampling_y;
+ const int num_ref_pixels = TF_WINDOW_LENGTH * TF_WINDOW_LENGTH +
+ ((plane) ? (1 << (ss_x_shift + ss_y_shift)) : 0);
+ const double inv_num_ref_pixels = 1.0 / num_ref_pixels;
+ const double n_decay = 0.5 + log(2 * noise_levels[plane] + 5.0);
+ const double decay_factor = 1 / (n_decay * q_decay * s_decay);
+
+ if (plane == AOM_PLANE_U) {
+ if (ss_x_shift == 1 && ss_y_shift == 1) {
+ const __m512i even_idx = _mm512_setr_epi32(
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30);
+ const __m512i odd_idx = _mm512_setr_epi32(1, 3, 5, 7, 9, 11, 13, 15, 17,
+ 19, 21, 23, 25, 27, 29, 31);
+ for (unsigned int i = 0; i < plane_h; i++) {
+ const uint32_t *src_0 = &frame_sse[2 * i * SSE_STRIDE_AVX512 + 2];
+ const uint32_t *src_1 =
+ &frame_sse[(2 * i + 1) * SSE_STRIDE_AVX512 + 2];
+ for (unsigned int j = 0; j < plane_w; j += 16) {
+ const __m512i r0_lo =
+ _mm512_loadu_si512((const __m512i *)(src_0 + 2 * j));
+ const __m512i r0_hi =
+ _mm512_loadu_si512((const __m512i *)(src_0 + 2 * j + 16));
+ const __m512i r1_lo =
+ _mm512_loadu_si512((const __m512i *)(src_1 + 2 * j));
+ const __m512i r1_hi =
+ _mm512_loadu_si512((const __m512i *)(src_1 + 2 * j + 16));
+ const __m512i s_lo = _mm512_add_epi32(r0_lo, r1_lo);
+ const __m512i s_hi = _mm512_add_epi32(r0_hi, r1_hi);
+ const __m512i evens =
+ _mm512_permutex2var_epi32(s_lo, even_idx, s_hi);
+ const __m512i odds = _mm512_permutex2var_epi32(s_lo, odd_idx, s_hi);
+ const __m512i res = _mm512_add_epi32(evens, odds);
+ _mm512_storeu_si512((__m512i *)&luma_sse_sum[i * BW + j], res);
+ }
+ }
+ } else {
+ for (unsigned int i = 0; i < plane_h; i++) {
+ for (unsigned int j = 0; j < plane_w; j++) {
+ for (int ii = 0; ii < (1 << ss_y_shift); ++ii) {
+ for (int jj = 0; jj < (1 << ss_x_shift); ++jj) {
+ const int yy = (i << ss_y_shift) + ii;
+ const int xx = (j << ss_x_shift) + jj;
+ luma_sse_sum[i * BW + j] +=
+ frame_sse[yy * SSE_STRIDE_AVX512 + xx + 2];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ highbd_apply_temporal_filter_avx512(
+ ref, frame_stride, pred1 + plane_offset, plane_w, plane_w, plane_h,
+ subblock_mses, accum + plane_offset, count + plane_offset, frame_sse,
+ luma_sse_sum, mbd->bd, inv_num_ref_pixels, decay_factor, inv_factor,
+ weight_factor, d_factor, tf_wgt_calc_lvl);
+ plane_offset += plane_h * plane_w;
+ }
+ aom_free(frame_sse);
+ aom_free(luma_sse_sum);
+}
+#endif // CONFIG_AV1_HIGHBITDEPTH