From ed54845498ca459cc5ad63e5c1cd5496a9e4bb11 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 21 Jul 2026 10:58:08 +0300 Subject: [PATCH 1/2] Speed up i2l with branchless operations so the loop autovectorizes --- src/libImaging/Convert.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index 4a35a9a1fb1..d80c5c2934c 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -587,17 +587,11 @@ l2i(UINT8 *out_, const UINT8 *in, int xsize) { static void i2l(UINT8 *out, const UINT8 *in_, int xsize) { - int x; - for (x = 0; x < xsize; x++, out++, in_ += 4) { + for (int x = 0; x < xsize; x++, out++, in_ += 4) { INT32 v; memcpy(&v, in_, sizeof(v)); - if (v <= 0) { - *out = 0; - } else if (v >= 255) { - *out = 255; - } else { - *out = (UINT8)v; - } + // Branchless saturation + *out = (UINT8)(v <= 0 ? 0 : (v >= 255 ? 255 : v)); } } From b31fed70f9d5e12168fa99a50080c0b9a9c91439 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 21 Jul 2026 11:07:13 +0300 Subject: [PATCH 2/2] Speed up palettized-to-RGB* conversions --- src/libImaging/Convert.c | 52 +++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index d80c5c2934c..b2b7ff26a22 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -974,27 +974,30 @@ pa2f(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) { } } +// Set the alpha channel of the UINT32 `v` in-place to the given value. +#ifdef WORDS_BIGENDIAN +#define SET_ALPHA_32(v, alpha) v = ((v & 0xFFFFFF00u) | (alpha)) +#else +#define SET_ALPHA_32(v, alpha) v = ((v & 0x00FFFFFFu) | ((UINT32)(alpha) << 24)) +#endif + static void p2rgb(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { - int x; - for (x = 0; x < xsize; x++) { - const UINT8 *rgb = &palette->palette[*in++ * 4]; - *out++ = rgb[0]; - *out++ = rgb[1]; - *out++ = rgb[2]; - *out++ = 255; + for (int x = 0; x < xsize; x++, in++, out += 4) { + UINT32 v; + memcpy(&v, &palette->palette[in[0] * 4], sizeof(v)); + SET_ALPHA_32(v, 0xFF); + memcpy(out, &v, sizeof(v)); } } static void pa2rgb(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { - int x; - for (x = 0; x < xsize; x++, in += 4) { - const UINT8 *rgb = &palette->palette[in[0] * 4]; - *out++ = rgb[0]; - *out++ = rgb[1]; - *out++ = rgb[2]; - *out++ = 255; + for (int x = 0; x < xsize; x++, in += 4, out += 4) { + UINT32 v; + memcpy(&v, &palette->palette[in[0] * 4], sizeof(v)); + SET_ALPHA_32(v, 0xFF); + memcpy(out, &v, sizeof(v)); } } @@ -1020,25 +1023,18 @@ pa2hsv(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { static void p2rgba(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { - int x; - for (x = 0; x < xsize; x++) { - const UINT8 *rgba = &palette->palette[*in++ * 4]; - *out++ = rgba[0]; - *out++ = rgba[1]; - *out++ = rgba[2]; - *out++ = rgba[3]; + for (int x = 0; x < xsize; x++, in++, out += 4) { + memcpy(out, &palette->palette[in[0] * 4], 4); } } static void pa2rgba(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { - int x; - for (x = 0; x < xsize; x++, in += 4) { - const UINT8 *rgb = &palette->palette[in[0] * 4]; - *out++ = rgb[0]; - *out++ = rgb[1]; - *out++ = rgb[2]; - *out++ = in[3]; + for (int x = 0; x < xsize; x++, in += 4, out += 4) { + UINT32 v; + memcpy(&v, &palette->palette[in[0] * 4], sizeof(v)); + SET_ALPHA_32(v, in[3]); + memcpy(out, &v, sizeof(v)); } }