diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index 2824f53eef..4218810d77 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -649,13 +649,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization for (int r = cube.RMin + 1; r <= cube.RMax; r++) { + // Currently, RyuJIT hoists the invariants of multi-level nested loop only to the + // immediate outer loop. See https://github.com/dotnet/runtime/issues/61420 + // To ensure the calculation doesn't happen repeatedly, hoist some of the calculations + // in the form of ind1* manually. + int ind1R = (r << ((IndexBits * 2) + IndexAlphaBits)) + + (r << (IndexBits + IndexAlphaBits + 1)) + + (r << (IndexBits * 2)) + + (r << (IndexBits + 1)) + + r; + for (int g = cube.GMin + 1; g <= cube.GMax; g++) { + int ind1G = ind1R + + (g << (IndexBits + IndexAlphaBits)) + + (g << IndexBits) + + g; + int r_g = r + g; + for (int b = cube.BMin + 1; b <= cube.BMax; b++) { + int ind1B = ind1G + + ((r_g + b) << IndexAlphaBits) + + b; + for (int a = cube.AMin + 1; a <= cube.AMax; a++) { - tagSpan[GetPaletteIndex(r, g, b, a)] = label; + int index = ind1B + a; + + tagSpan[index] = label; } } }