Skip to content

Commit f6a774f

Browse files
committed
Re-enable avx512 vert float resize_v_avx512_planar_float_w_sr
1 parent 7d831a5 commit f6a774f

3 files changed

Lines changed: 72 additions & 64 deletions

File tree

avs_core/filters/intel/resample_avx2.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,12 +1069,12 @@ void resize_v_avx2_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pitch
10691069

10701070
src2_ptr += src_pitch;
10711071
}
1072-
// here we use store instead of stream store; in multithreading stream is better;
1072+
// here we use stream instead of store; in multithreading stream is better;
10731073
// consider two templated versions if needed depending on actual MT usage
1074-
_mm256_store_ps(dst + x, result_1);
1075-
_mm256_store_ps(dst + x + 8, result_2);
1076-
_mm256_store_ps(dst + x + 16, result_3);
1077-
_mm256_store_ps(dst + x + 24, result_4);
1074+
_mm256_stream_ps(dst + x, result_1);
1075+
_mm256_stream_ps(dst + x + 8, result_2);
1076+
_mm256_stream_ps(dst + x + 16, result_3);
1077+
_mm256_stream_ps(dst + x + 24, result_4);
10781078
} // width_mod32
10791079

10801080
// Part #2: process remaining. 32 byte 8 floats (AVX2 register holds 8 floats)
@@ -1287,7 +1287,7 @@ void resize_h_planar_float_avx_transpose_vstripe_ks4(BYTE* dst8, const BYTE* src
12871287
result = _mm256_fmadd_ps(data_3_data_7, coef_3_coef_7, result);
12881288
result = _mm256_fmadd_ps(data_4_data_8, coef_4_coef_8, result);
12891289

1290-
_mm256_store_ps(dst_ptr, result);
1290+
_mm256_stream_ps(dst_ptr, result);
12911291

12921292
dst_ptr += dst_pitch;
12931293
src_ptr += src_pitch;
@@ -2218,8 +2218,8 @@ void resize_h_planar_float_avx2_permutex_vstripe_ks4_pix16(BYTE* dst8, const BYT
22182218
// 4. Store
22192219
// ---------------------------------------------------------------------------
22202220

2221-
_mm256_store_ps(dst_ptr, final_result_L); // dst[0..7]
2222-
_mm256_store_ps(dst_ptr + 8, final_result_H); // dst[8..15]
2221+
_mm256_stream_ps(dst_ptr, final_result_L); // dst[0..7]
2222+
_mm256_stream_ps(dst_ptr + 8, final_result_H); // dst[8..15]
22232223

22242224
dst_ptr += dst_pitch;
22252225
src_ptr += src_pitch;

avs_core/filters/intel/resample_avx512.cpp

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,29 +1036,30 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
10361036
AVS_UNUSED(bits_per_pixel);
10371037

10381038
const int filter_size = program->filter_size;
1039-
const float* AVS_RESTRICT current_coeff = program->pixel_coefficient_float;
1039+
const float* AVS_RESTRICT current_coeff = (const float* AVS_RESTRICT)program->pixel_coefficient_float;
10401040

10411041
const float* src = (const float*)src8;
10421042
float* AVS_RESTRICT dst = (float*)dst8;
1043-
dst_pitch = dst_pitch / sizeof(float);
1044-
src_pitch = src_pitch / sizeof(float);
10451043

1046-
const int kernel_size = program->filter_size_real; // not the aligned
1047-
const int kernel_size_mod2 = (kernel_size / 2) * 2; // Process pairs of rows for better efficiency
1044+
const int dst_stride_float = dst_pitch / sizeof(float);
1045+
const int src_stride_float = src_pitch / sizeof(float);
1046+
1047+
const int kernel_size = program->filter_size_real;
1048+
// Pre-calculate Mod2 size for the remainder loop
1049+
const int kernel_size_mod2 = (kernel_size / 2) * 2;
10481050
const bool notMod2 = kernel_size_mod2 < kernel_size;
10491051

10501052
for (int y = 0; y < target_height; y++) {
10511053
int offset = program->pixel_offset[y];
1052-
const float* src_ptr = src + offset * src_pitch;
1054+
const float* src_row_start = src + offset * src_stride_float;
10531055

10541056
int x = 0;
10551057

1056-
// 128-64-32 pixels prelude
1057-
// we spare some coeff reload per unrolled loop
1058-
// Perhaps for an i7-11700 which has only 1x512 as 2x256 fma unit, not ideal.
1059-
1060-
// Process by 8x 512 (8 x 16 floats) to make memory read/write linear streams longer
1061-
// 32x512 bit registers should be enough
1058+
// -----------------------------------------------------------------------
1059+
// 128 pixels (512 bytes) per iteration
1060+
// Uses ~17 ZMM registers. Safe for x64 (32 regs available).
1061+
// Provides 8 independent dependency chains to hide FMA latency.
1062+
// -----------------------------------------------------------------------
10621063
const int width_mod128 = (width / 128) * 128;
10631064
for (; x < width_mod128; x += 128) {
10641065
__m512 result_1 = _mm512_setzero_ps();
@@ -1070,19 +1071,21 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
10701071
__m512 result_7 = _mm512_setzero_ps();
10711072
__m512 result_8 = _mm512_setzero_ps();
10721073

1073-
const float* AVS_RESTRICT src2_ptr = src_ptr + x;
1074-
int i = 0;
1075-
for (; i < kernel_size; i++) {
1074+
const float* AVS_RESTRICT src2_ptr = src_row_start + x;
1075+
1076+
for (int i = 0; i < kernel_size; i++) {
10761077
__m512 coeff = _mm512_set1_ps(current_coeff[i]);
10771078

1078-
__m512 src_1 = _mm512_load_ps(src2_ptr);
1079-
__m512 src_2 = _mm512_load_ps(src2_ptr + 16);
1079+
// Loading 512 bytes contiguous memory (8 cache lines)
1080+
__m512 src_1 = _mm512_load_ps(src2_ptr); // 0..15
1081+
__m512 src_2 = _mm512_load_ps(src2_ptr + 16); // 16..31 (offset in floats)
10801082
__m512 src_3 = _mm512_load_ps(src2_ptr + 32);
10811083
__m512 src_4 = _mm512_load_ps(src2_ptr + 48);
10821084
__m512 src_5 = _mm512_load_ps(src2_ptr + 64);
10831085
__m512 src_6 = _mm512_load_ps(src2_ptr + 80);
10841086
__m512 src_7 = _mm512_load_ps(src2_ptr + 96);
10851087
__m512 src_8 = _mm512_load_ps(src2_ptr + 112);
1088+
10861089
result_1 = _mm512_fmadd_ps(src_1, coeff, result_1);
10871090
result_2 = _mm512_fmadd_ps(src_2, coeff, result_2);
10881091
result_3 = _mm512_fmadd_ps(src_3, coeff, result_3);
@@ -1092,31 +1095,32 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
10921095
result_7 = _mm512_fmadd_ps(src_7, coeff, result_7);
10931096
result_8 = _mm512_fmadd_ps(src_8, coeff, result_8);
10941097

1095-
src2_ptr += src_pitch;
1098+
src2_ptr += src_stride_float;
10961099
}
10971100

1098-
_mm512_store_ps(dst + x, result_1);
1099-
_mm512_store_ps(dst + x + 16, result_2);
1100-
_mm512_store_ps(dst + x + 32, result_3);
1101-
_mm512_store_ps(dst + x + 48, result_4);
1102-
_mm512_store_ps(dst + x + 64, result_5);
1103-
_mm512_store_ps(dst + x + 80, result_6);
1104-
_mm512_store_ps(dst + x + 96, result_7);
1105-
_mm512_store_ps(dst + x + 112, result_8);
1101+
_mm512_stream_ps(dst + x, result_1);
1102+
_mm512_stream_ps(dst + x + 16, result_2);
1103+
_mm512_stream_ps(dst + x + 32, result_3);
1104+
_mm512_stream_ps(dst + x + 48, result_4);
1105+
_mm512_stream_ps(dst + x + 64, result_5);
1106+
_mm512_stream_ps(dst + x + 80, result_6);
1107+
_mm512_stream_ps(dst + x + 96, result_7);
1108+
_mm512_stream_ps(dst + x + 112, result_8);
11061109
}
11071110

1108-
// Process by 4x512 (4 x 16 floats) to make memory read/write linear streams longer
1111+
// -----------------------------------------------------------------------
1112+
// 64 pixels per iteration
1113+
// -----------------------------------------------------------------------
11091114
const int width_mod64 = (width / 64) * 64;
11101115
for (; x < width_mod64; x += 64) {
11111116
__m512 result_1 = _mm512_setzero_ps();
11121117
__m512 result_2 = _mm512_setzero_ps();
11131118
__m512 result_3 = _mm512_setzero_ps();
11141119
__m512 result_4 = _mm512_setzero_ps();
11151120

1116-
const float* AVS_RESTRICT src2_ptr = src_ptr + x;
1121+
const float* AVS_RESTRICT src2_ptr = src_row_start + x;
11171122

1118-
int i = 0;
1119-
for (; i < kernel_size; i++) {
1123+
for (int i = 0; i < kernel_size; i++) {
11201124
__m512 coeff = _mm512_set1_ps(current_coeff[i]);
11211125

11221126
__m512 src_1 = _mm512_load_ps(src2_ptr);
@@ -1129,25 +1133,26 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
11291133
result_3 = _mm512_fmadd_ps(src_3, coeff, result_3);
11301134
result_4 = _mm512_fmadd_ps(src_4, coeff, result_4);
11311135

1132-
src2_ptr += src_pitch;
1136+
src2_ptr += src_stride_float;
11331137
}
11341138

1135-
_mm512_store_ps(dst + x, result_1);
1136-
_mm512_store_ps(dst + x + 16, result_2);
1137-
_mm512_store_ps(dst + x + 32, result_3);
1138-
_mm512_store_ps(dst + x + 48, result_4);
1139+
_mm512_stream_ps(dst + x, result_1);
1140+
_mm512_stream_ps(dst + x + 16, result_2);
1141+
_mm512_stream_ps(dst + x + 32, result_3);
1142+
_mm512_stream_ps(dst + x + 48, result_4);
11391143
}
11401144

1141-
// Process by 2x512 (2 x 16 floats) to make memory read/write linear streams longer,
1145+
// -----------------------------------------------------------------------
1146+
// 32 pixels per iteration
1147+
// -----------------------------------------------------------------------
11421148
const int width_mod32 = (width / 32) * 32;
11431149
for (; x < width_mod32; x += 32) {
11441150
__m512 result_1 = _mm512_setzero_ps();
11451151
__m512 result_2 = _mm512_setzero_ps();
11461152

1147-
const float* AVS_RESTRICT src2_ptr = src_ptr + x;
1153+
const float* AVS_RESTRICT src2_ptr = src_row_start + x;
11481154

1149-
int i = 0;
1150-
for (; i < kernel_size; i++) {
1155+
for (int i = 0; i < kernel_size; i++) {
11511156
__m512 coeff = _mm512_set1_ps(current_coeff[i]);
11521157

11531158
__m512 src_1 = _mm512_load_ps(src2_ptr);
@@ -1156,36 +1161,39 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
11561161
result_1 = _mm512_fmadd_ps(src_1, coeff, result_1);
11571162
result_2 = _mm512_fmadd_ps(src_2, coeff, result_2);
11581163

1159-
src2_ptr += src_pitch;
1164+
src2_ptr += src_stride_float;
11601165
}
11611166

1162-
_mm512_store_ps(dst + x, result_1);
1163-
_mm512_store_ps(dst + x + 16, result_2);
1167+
_mm512_stream_ps(dst + x, result_1);
1168+
_mm512_stream_ps(dst + x + 16, result_2);
11641169
}
11651170

1166-
// Process 1x512 dual
1167-
// 64 byte 16 floats (AVX512 register holds 16 floats)
1168-
// row alignment is 64 bytes - so it is safe to load mod16 of float32.
1171+
// -----------------------------------------------------------------------
1172+
// Remainder loop (16 pixels)
1173+
// Uses vertical loop unrolling (pairs of taps) to hide FMA latency
1174+
// because we don't have enough horizontal data to do it spatially.
1175+
// -----------------------------------------------------------------------
1176+
const int src_stride_2 = src_stride_float * 2;
1177+
11691178
for (; x < width; x += 16) {
11701179
__m512 result_single = _mm512_setzero_ps();
11711180
__m512 result_single_2 = _mm512_setzero_ps();
11721181

1173-
const float* AVS_RESTRICT src2_ptr = src_ptr + x;
1174-
1175-
// Process pairs of rows for better efficiency (2 coeffs/cycle)
1176-
// two result variables for potential parallel operation
1182+
const float* AVS_RESTRICT src2_ptr = src_row_start + x;
11771183
int i = 0;
1184+
1185+
// Process pairs of rows
11781186
for (; i < kernel_size_mod2; i += 2) {
11791187
__m512 coeff_even = _mm512_set1_ps(current_coeff[i]);
11801188
__m512 coeff_odd = _mm512_set1_ps(current_coeff[i + 1]);
11811189

11821190
__m512 src_even = _mm512_load_ps(src2_ptr);
1183-
__m512 src_odd = _mm512_load_ps(src2_ptr + src_pitch);
1191+
__m512 src_odd = _mm512_load_ps(src2_ptr + src_stride_float);
11841192

11851193
result_single = _mm512_fmadd_ps(src_even, coeff_even, result_single);
11861194
result_single_2 = _mm512_fmadd_ps(src_odd, coeff_odd, result_single_2);
11871195

1188-
src2_ptr += 2 * src_pitch;
1196+
src2_ptr += src_stride_2;
11891197
}
11901198

11911199
result_single = _mm512_add_ps(result_single, result_single_2);
@@ -1197,11 +1205,10 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
11971205
result_single = _mm512_fmadd_ps(src_val, coeff, result_single);
11981206
}
11991207

1200-
_mm512_store_ps(dst + x, result_single);
1208+
_mm512_stream_ps(dst + x, result_single);
12011209
}
12021210

1203-
1204-
dst += dst_pitch;
1211+
dst += dst_stride_float;
12051212
current_coeff += filter_size;
12061213
}
12071214
}

avs_core/filters/resample.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,9 +1894,10 @@ ResamplerV FilteredResizeV::GetResampler(int CPU, int pixelsize, int bits_per_pi
18941894
#ifdef INTEL_INTRINSICS
18951895
#ifdef INTEL_INTRINSICS_AVX512
18961896
if ((CPU & CPUF_AVX512_FAST) == CPUF_AVX512_FAST) {
1897-
//return resize_v_avx512_planar_float; // Old, base version, quicker than avx2 version
1897+
// return resize_v_avx512_planar_float; // Old, base version, quicker than avx2 version
18981898
// This one is about equal to avx2 version, but only with clang,
1899-
// clang is probably unrolls it out-of-box better than MSVC.
1899+
// it seems that clang is too good and, probably unrolls the old function version
1900+
// out-of-box so much better than MSVC, that it competes with the _w_sr version.
19001901
// With MSVC its no-brainer to use avx512
19011902
return resize_v_avx512_planar_float_w_sr;
19021903
}

0 commit comments

Comments
 (0)