diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 668b2d0310..9238e1b478 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -171,6 +171,8 @@ namespace SixLabors.ImageSharp.PixelFormats } } + // TODO: The Vector4 helpers should be moved to a utility class. + /// /// Provides an efficient default implementation for and /// which is applicable for -compatible pixel types where @@ -195,15 +197,19 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) - { - Span tempSpan = tempBuffer.Memory.Span; - this.ToRgba32(configuration, sourcePixels, tempSpan); + // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: + int countWithoutLastItem = count - 1; + ReadOnlySpan reducedSource = sourcePixels.Slice(0, countWithoutLastItem); + Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); + this.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); - SimdUtils.BulkConvertByteToNormalizedFloat( - MemoryMarshal.Cast(tempSpan), - MemoryMarshal.Cast(destVectors)); - } + // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, + // but we are always reading/writing at different positions: + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(lastQuarterOfDestBuffer), + MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); + + destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); } /// @@ -230,6 +236,8 @@ namespace SixLabors.ImageSharp.PixelFormats return; } + // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, + // so let's allocate a temporary buffer as usually: using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) { Span tempSpan = tempBuffer.Memory.Span;