From b6c2c801228c32449afd946bf2b7dcbd6530a382 Mon Sep 17 00:00:00 2001 From: Simon Hardy-Francis Date: Thu, 22 Oct 2026 21:28:06 -0700 Subject: [PATCH 1/2] Speed up 8-bit horizontal resampling loops Step a pointer through the input pixels in the 2, 3 and 4 band loops of _ImagingResampleHorizontal_8bpc(), which compilers vectorise better for long filters. For 3 bands with short filters, keep the indexed loop, which is faster with gcc on aarch64. The output is unchanged. Assisted-by: LLM Signed-off-by: Simon Hardy-Francis --- src/libImaging/Resample.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/libImaging/Resample.c b/src/libImaging/Resample.c index 5834ad15457..6c845bddd0c 100644 --- a/src/libImaging/Resample.c +++ b/src/libImaging/Resample.c @@ -380,9 +380,10 @@ _ImagingResampleHorizontal_8bpc( xmax = bounds[xx * 2 + 1]; k = &kk[xx * ksize]; ss0 = ss3 = 1 << (PRECISION_BITS - 1); - for (x = 0; x < xmax; x++) { - ss0 += lineIn[(x + xmin) * 4 + 0] * k[x]; - ss3 += lineIn[(x + xmin) * 4 + 3] * k[x]; + const UINT8 *p = lineIn + xmin * 4; + for (x = 0; x < xmax; x++, p += 4) { + ss0 += p[0] * k[x]; + ss3 += p[3] * k[x]; } v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3)); memcpy(lineOut + xx * sizeof(v), &v, sizeof(v)); @@ -399,10 +400,21 @@ _ImagingResampleHorizontal_8bpc( xmax = bounds[xx * 2 + 1]; k = &kk[xx * ksize]; ss0 = ss1 = ss2 = 1 << (PRECISION_BITS - 1); - for (x = 0; x < xmax; x++) { - ss0 += lineIn[(x + xmin) * 4 + 0] * k[x]; - ss1 += lineIn[(x + xmin) * 4 + 1] * k[x]; - ss2 += lineIn[(x + xmin) * 4 + 2] * k[x]; + // For short filters, the indexed loop is faster with gcc + // on aarch64; the pointer loop is faster for longer ones. + if (xmax < 12) { + for (x = 0; x < xmax; x++) { + ss0 += lineIn[(x + xmin) * 4 + 0] * k[x]; + ss1 += lineIn[(x + xmin) * 4 + 1] * k[x]; + ss2 += lineIn[(x + xmin) * 4 + 2] * k[x]; + } + } else { + const UINT8 *p = lineIn + xmin * 4; + for (x = 0; x < xmax; x++, p += 4) { + ss0 += p[0] * k[x]; + ss1 += p[1] * k[x]; + ss2 += p[2] * k[x]; + } } v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0); memcpy(lineOut + xx * sizeof(v), &v, sizeof(v)); @@ -419,11 +431,12 @@ _ImagingResampleHorizontal_8bpc( xmax = bounds[xx * 2 + 1]; k = &kk[xx * ksize]; ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS - 1); - for (x = 0; x < xmax; x++) { - ss0 += lineIn[(x + xmin) * 4 + 0] * k[x]; - ss1 += lineIn[(x + xmin) * 4 + 1] * k[x]; - ss2 += lineIn[(x + xmin) * 4 + 2] * k[x]; - ss3 += lineIn[(x + xmin) * 4 + 3] * k[x]; + const UINT8 *p = lineIn + xmin * 4; + for (x = 0; x < xmax; x++, p += 4) { + ss0 += p[0] * k[x]; + ss1 += p[1] * k[x]; + ss2 += p[2] * k[x]; + ss3 += p[3] * k[x]; } v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3)); memcpy(lineOut + xx * sizeof(v), &v, sizeof(v)); From 058bdba999893ac0efb6dacb5dcb55f48b316091 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 23 Oct 2026 19:44:52 +1100 Subject: [PATCH 2/2] Simplify code --- src/libImaging/Resample.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/libImaging/Resample.c b/src/libImaging/Resample.c index 6c845bddd0c..05a7a0a86b0 100644 --- a/src/libImaging/Resample.c +++ b/src/libImaging/Resample.c @@ -400,21 +400,11 @@ _ImagingResampleHorizontal_8bpc( xmax = bounds[xx * 2 + 1]; k = &kk[xx * ksize]; ss0 = ss1 = ss2 = 1 << (PRECISION_BITS - 1); - // For short filters, the indexed loop is faster with gcc - // on aarch64; the pointer loop is faster for longer ones. - if (xmax < 12) { - for (x = 0; x < xmax; x++) { - ss0 += lineIn[(x + xmin) * 4 + 0] * k[x]; - ss1 += lineIn[(x + xmin) * 4 + 1] * k[x]; - ss2 += lineIn[(x + xmin) * 4 + 2] * k[x]; - } - } else { - const UINT8 *p = lineIn + xmin * 4; - for (x = 0; x < xmax; x++, p += 4) { - ss0 += p[0] * k[x]; - ss1 += p[1] * k[x]; - ss2 += p[2] * k[x]; - } + const UINT8 *p = lineIn + xmin * 4; + for (x = 0; x < xmax; x++, p += 4) { + ss0 += p[0] * k[x]; + ss1 += p[1] * k[x]; + ss2 += p[2] * k[x]; } v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0); memcpy(lineOut + xx * sizeof(v), &v, sizeof(v));