diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index 770d44065..0c6e0d3b4 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs index c3f81868b..1ef4bb9ec 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs @@ -140,7 +140,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.source.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs index 2ce9a7ce5..46ed36f68 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs @@ -170,7 +170,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.Target.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index dc73420f3..0957904c6 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -79,8 +79,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int width = maxX - minX; - MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; - var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); ParallelHelper.IterateRows( @@ -93,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing Span background = source.GetPixelRowSpan(y).Slice(minX, width); Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); - blender.Blend(memoryAllocator, background, background, foreground, this.Opacity); + blender.Blend(configuration, background, background, foreground, this.Opacity); } }); } diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs index 2968b68b5..09a1ff71f 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs @@ -158,7 +158,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.Target.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 6b69c33f0..a77c6728b 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -92,10 +92,11 @@ namespace SixLabors.ImageSharp.Processing Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; + Configuration configuration = this.Target.Configuration; if (this.Options.BlendPercentage == 1f) { - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); + this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); } else { @@ -108,7 +109,12 @@ namespace SixLabors.ImageSharp.Processing amountSpan[i] = scanline[i] * this.Options.BlendPercentage; } - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan); + this.Blender.Blend( + configuration, + destinationRow, + destinationRow, + this.Colors.GetSpan(), + amountSpan); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 77cd32222..cea90cb45 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -436,7 +436,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgr24Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgr24Bytes( + this.configuration, + row.GetSpan(), + pixelSpan, + width); } } } @@ -461,7 +465,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgra32Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgra32Bytes( + this.configuration, + row.GetSpan(), + pixelSpan, + width); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 186ff812f..a67c581eb 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -3,6 +3,8 @@ using System; using System.IO; + +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; @@ -23,6 +25,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp private readonly MemoryAllocator memoryAllocator; + private Configuration configuration; + private BmpBitsPerPixel? bitsPerPixel; /// @@ -48,6 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); ImageMetaData metaData = image.MetaData; BmpMetaData bmpMetaData = metaData.GetFormatMetaData(BmpFormat.Instance); this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel; @@ -163,7 +168,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = pixels.Height - 1; y >= 0; y--) { Span pixelSpan = pixels.GetRowSpan(y); - PixelOperations.Instance.ToBgra32Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length); + PixelOperations.Instance.ToBgra32Bytes( + this.configuration, + pixelSpan, + row.GetSpan(), + pixelSpan.Length); stream.Write(row.Array, 0, row.Length()); } } @@ -183,7 +192,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = pixels.Height - 1; y >= 0; y--) { Span pixelSpan = pixels.GetRowSpan(y); - PixelOperations.Instance.ToBgr24Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length); + PixelOperations.Instance.ToBgr24Bytes( + this.configuration, + pixelSpan, + row.GetSpan(), + pixelSpan.Length); stream.Write(row.Array, 0, row.Length()); } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 7db347aa6..d7e2e40e2 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; @@ -26,6 +27,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private readonly MemoryAllocator memoryAllocator; + /// + /// Configuration bound to the encoding operation. + /// + private Configuration configuration; + /// /// A reusable buffer used to reduce allocations. /// @@ -81,6 +87,8 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); + ImageMetaData metaData = image.MetaData; this.gifMetaData = metaData.GetFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; @@ -88,7 +96,7 @@ namespace SixLabors.ImageSharp.Formats.Gif // Quantize the image returning a palette. QuantizedFrame quantized = - this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); + this.quantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(image.Frames.RootFrame); // Get the number of bits. this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); @@ -151,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Gif else { using (QuantizedFrame paletteQuantized - = palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame)) + = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration(), () => quantized.Palette).QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } @@ -171,15 +179,17 @@ namespace SixLabors.ImageSharp.Formats.Gif if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. - if (previousFrame != null - && previousMeta.ColorTableLength != frameMetaData.ColorTableLength - && frameMetaData.ColorTableLength > 0) + if (previousFrame != null && previousMeta.ColorTableLength != frameMetaData.ColorTableLength + && frameMetaData.ColorTableLength > 0) { - quantized = this.quantizer.CreateFrameQuantizer(frameMetaData.ColorTableLength).QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer( + image.GetConfiguration(), + frameMetaData.ColorTableLength).QuantizeFrame(frame); } else { - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) + .QuantizeFrame(frame); } } @@ -217,7 +227,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan); + PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { @@ -319,7 +329,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The stream to write to. private void WriteComments(ImageMetaData metadata, Stream stream) { - if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) || string.IsNullOrEmpty(property.Value)) + if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) + || string.IsNullOrEmpty(property.Value)) { return; } @@ -417,7 +428,11 @@ namespace SixLabors.ImageSharp.Formats.Gif using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) { - PixelOperations.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount); + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + image.Palette.AsSpan(), + colorTable.GetSpan(), + pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 6bd287732..7ce86b4c9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -26,6 +26,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// internal class JpegImagePostProcessor : IDisposable { + private readonly Configuration configuration; + /// /// The number of block rows to be processed in one Step. /// @@ -49,15 +51,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Initializes a new instance of the class. /// - /// The to use for buffer allocations. + /// The to configure internal operations. /// The representing the uncompressed spectral Jpeg data - public JpegImagePostProcessor(MemoryAllocator memoryAllocator, IRawJpegData rawJpeg) + public JpegImagePostProcessor(Configuration configuration, IRawJpegData rawJpeg) { + this.configuration = configuration; this.RawJpeg = rawJpeg; IJpegComponent c0 = rawJpeg.Components.First(); this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / BlockRowsPerStep; this.PostProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, PixelRowsPerStep); + MemoryAllocator memoryAllocator = configuration.MemoryAllocator; this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryAllocator, this, c)).ToArray(); this.rgbaBuffer = memoryAllocator.Allocate(rawJpeg.ImageSizeInPixels.Width); this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace); @@ -160,7 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Span destRow = destination.GetPixelRowSpan(yy); // TODO: Investigate if slicing is actually necessary - PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); + PixelOperations.Instance.FromVector4(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs index b2a8fccf4..d775425c5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs @@ -53,12 +53,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// /// Converts a 8x8 image area inside 'pixels' at position (x,y) placing the result members of the structure (, , ) /// - public void Convert(IPixelSource pixels, int x, int y) + public void Convert(ImageFrame frame, int x, int y) { - this.pixelBlock.LoadAndStretchEdges(pixels, x, y); + this.pixelBlock.LoadAndStretchEdges(frame, x, y); Span rgbSpan = this.rgbBlock.AsSpanUnsafe(); - PixelOperations.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan); + PixelOperations.Instance.ToRgb24(frame.Configuration, this.pixelBlock.AsSpanUnsafe(), rgbSpan); ref float yBlockStart = ref Unsafe.As(ref this.Y); ref float cbBlockStart = ref Unsafe.As(ref this.Cb); diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 22d9cbdee..36246c682 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -936,7 +936,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private Image PostProcessIntoImage() where TPixel : struct, IPixel { - using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this)) + using (var postProcessor = new JpegImagePostProcessor(this.configuration, this)) { var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); postProcessor.PostProcess(image.Frames.RootFrame); diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d66ac6c0d..11c4d831b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -702,6 +702,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Rgb: PngScanlineProcessor.ProcessRgbScanline( + this.configuration, this.header, scanlineSpan, rowSpan, @@ -715,6 +716,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.RgbWithAlpha: PngScanlineProcessor.ProcessRgbaScanline( + this.configuration, this.header, scanlineSpan, rowSpan, diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 84f7cb6cc..7ae716aa0 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -43,6 +43,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly MemoryAllocator memoryAllocator; + /// + /// The configuration instance for the decoding operation + /// + private Configuration configuration; + /// /// The maximum block size, defaults at 64k for uncompressed blocks. /// @@ -201,6 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Png Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); this.width = image.Width; this.height = image.Height; @@ -237,7 +243,8 @@ namespace SixLabors.ImageSharp.Formats.Png } // Create quantized frame returning the palette and set the bit depth. - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); + quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) + .QuantizeFrame(image.Frames.RootFrame); byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); bits = Math.Max(bits, quantizedBits); @@ -327,7 +334,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span luminanceSpan = luminanceBuffer.GetSpan(); ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); - PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan); + PixelOperations.Instance.ToGray16(this.configuration, rowSpan, luminanceSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) @@ -342,19 +349,28 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.bitDepth == 8) { // 8 bit grayscale - PixelOperations.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length); + PixelOperations.Instance.ToGray8Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + rowSpan.Length); } else { // 1, 2, and 4 bit grayscale - using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(rowSpan.Length, AllocationOptions.Clean)) + using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer( + rowSpan.Length, + AllocationOptions.Clean)) { int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(this.bitDepth) - 1); Span tempSpan = temp.GetSpan(); - ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); // We need to first create an array of luminance bytes then scale them down to the correct bit depth. - PixelOperations.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length); + PixelOperations.Instance.ToGray8Bytes( + this.configuration, + rowSpan, + tempSpan, + rowSpan.Length); this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor); } } @@ -370,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); + PixelOperations.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) @@ -390,7 +406,8 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); - Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); + Unsafe.Add(ref rawScanlineSpanRef, o) = + ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } } @@ -412,14 +429,22 @@ namespace SixLabors.ImageSharp.Formats.Png case 4: { // 8 bit Rgba - PixelOperations.Instance.ToRgba32Bytes(rowSpan, rawScanlineSpan, this.width); + PixelOperations.Instance.ToRgba32Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + this.width); break; } case 3: { // 8 bit Rgb - PixelOperations.Instance.ToRgb24Bytes(rowSpan, rawScanlineSpan, this.width); + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + this.width); break; } @@ -430,7 +455,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); + PixelOperations.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) @@ -453,7 +478,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbSpan = rgbBuffer.GetSpan(); ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); - PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan); + PixelOperations.Instance.ToRgb48(this.configuration, rowSpan, rgbSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index e4a2562e6..3fe590ee2 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Png { /// /// Provides methods to allow the decoding of raw scanlines to image rows of different pixel formats. + /// TODO: We should make this a stateful class or struct to reduce the number of arguments on methods (most are invariant). /// internal static class PngScanlineProcessor { @@ -346,6 +347,7 @@ namespace SixLabors.ImageSharp.Formats.Png } public static void ProcessRgbScanline( + Configuration configuration, in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, @@ -357,7 +359,6 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { TPixel pixel = default; - ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (!hasTrans) @@ -377,7 +378,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.FromRgb24Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgb24Bytes(configuration, scanlineSpan, rowSpan, header.Width); } return; @@ -500,6 +501,7 @@ namespace SixLabors.ImageSharp.Formats.Png } public static void ProcessRgbaScanline( + Configuration configuration, in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, @@ -526,7 +528,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.FromRgba32Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgba32Bytes(configuration, scanlineSpan, rowSpan, header.Width); } } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 25c517d44..f69ae3757 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -21,7 +21,6 @@ namespace SixLabors.ImageSharp public sealed class ImageFrame : IPixelSource, IDisposable where TPixel : struct, IPixel { - private readonly Configuration configuration; private bool isDisposed; /// @@ -84,7 +83,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(width, height); this.MetaData = metaData ?? new ImageFrameMetaData(); @@ -118,7 +117,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.NotNull(metaData, nameof(metaData)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = new Buffer2D(memorySource, width, height); this.MetaData = metaData; @@ -134,7 +133,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); @@ -146,6 +145,11 @@ namespace SixLabors.ImageSharp /// public MemoryAllocator MemoryAllocator { get; } + /// + /// Gets the instance associated with this . + /// + internal Configuration Configuration { get; } + /// /// Gets the image pixels. Not private as Buffer2D requires an array in its constructor. /// @@ -248,13 +252,13 @@ namespace SixLabors.ImageSharp } /// - public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>({this.Width}x{this.Height})"; /// /// Clones the current instance. /// /// The - internal ImageFrame Clone() => this.Clone(this.configuration); + internal ImageFrame Clone() => this.Clone(this.Configuration); /// /// Clones the current instance. @@ -269,7 +273,7 @@ namespace SixLabors.ImageSharp /// The pixel format. /// The internal ImageFrame CloneAs() - where TPixel2 : struct, IPixel => this.CloneAs(this.configuration); + where TPixel2 : struct, IPixel => this.CloneAs(this.Configuration); /// /// Returns a copy of the image frame in the given pixel format. @@ -296,7 +300,7 @@ namespace SixLabors.ImageSharp { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); - PixelOperations.Instance.To(sourceRow, targetRow); + PixelOperations.Instance.To(configuration, sourceRow, targetRow); } }); diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 1923faa1f..08530c2bb 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -739,7 +739,11 @@ namespace SixLabors.ImageSharp.PixelFormats var safe = new TPixel[constants.Length + 1]; Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan()); - PixelOperations.Instance.FromRgba32Bytes(constantsBytes, safe, constants.Length); + PixelOperations.Instance.FromRgba32Bytes( + Configuration.Default, + constantsBytes, + safe, + constants.Length); return safe; } } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 6f0bba5cf..5c8e506ae 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -4,8 +4,8 @@ using System; using System.Buffers; using System.Numerics; + using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; namespace SixLabors.ImageSharp.PixelFormats { @@ -38,7 +38,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// A value between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount); + protected abstract void BlendFunction( + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + float amount); /// /// Blend 2 rows together. @@ -50,12 +54,16 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount); + protected abstract void BlendFunction( + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount); /// /// Blends 2 rows together /// - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -63,16 +71,21 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount) { - this.Blend(memoryManager, destination, background, source, amount); + this.Blend(configuration, destination, background, source, amount); } /// /// Blends 2 rows together /// /// the pixel format of the source span - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -80,25 +93,40 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount) where TPixelSrc : struct, IPixel { Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = + configuration.MemoryAllocator.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + background.Slice(0, background.Length), + backgroundSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + source.Slice(0, background.Length), + sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); + PixelOperations.Instance.FromScaledVector4( + configuration, + destinationSpan.Slice(0, background.Length), + destination); } } @@ -106,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Blends 2 rows together /// /// the pixel format of the source span - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -114,26 +142,41 @@ namespace SixLabors.ImageSharp.PixelFormats /// A value between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + float amount) where TPixelSrc : struct, IPixel { Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount)); - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = + configuration.MemoryAllocator.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + background.Slice(0, background.Length), + backgroundSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + source.Slice(0, background.Length), + sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); + PixelOperations.Instance.FromScaledVector4( + configuration, + destinationSpan.Slice(0, background.Length), + destination); } } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelExtensions.cs b/src/ImageSharp/PixelFormats/PixelExtensions.cs deleted file mode 100644 index 175696ab6..000000000 --- a/src/ImageSharp/PixelFormats/PixelExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Low-performance extension methods to help conversion syntax, suitable for testing purposes. - /// - internal static class PixelExtensions - { - /// - /// Returns the result of as a new instance. - /// - public static Rgba32 ToRgba32(this TPixel pixel) - where TPixel : struct, IPixel - { - Rgba32 result = default; - pixel.ToRgba32(ref result); - return result; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 26e85e043..6449351cc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,127 +25,187 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromArgb32(ReadOnlySpan source, Span destPixels) + internal override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); } } - + /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); + } + } + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); + } + } - dp.FromArgb32(sp); + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); } } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +221,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 080a25429..9232cf454 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,25 +25,53 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgr24(ReadOnlySpan source, Span destPixels) + internal override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -56,8 +87,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -73,8 +105,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -90,8 +123,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -107,8 +141,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -124,8 +159,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -141,8 +177,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +195,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 6a1bb6cdc..4f56b75c5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,127 +25,187 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgra32(ReadOnlySpan source, Span destPixels) + internal override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); } } - + /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); + } + } + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); + } + } - dp.FromBgra32(sp); + /// + internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); } } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +221,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index cbb9df445..81882185d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,16 +25,18 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray16(ReadOnlySpan source, Span destPixels) + internal override void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -39,8 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -56,8 +62,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -73,8 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -90,8 +98,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -107,8 +116,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -124,8 +134,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -141,8 +152,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +170,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index b88f18e8d..f6678a4f8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,16 +25,18 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray8(ReadOnlySpan source, Span destPixels) + internal override void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -39,8 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -56,8 +62,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -73,8 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -90,8 +98,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -107,8 +116,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -124,8 +134,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -141,8 +152,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +170,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 49c56f4fa..aae8b2f63 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,25 +25,53 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb24(ReadOnlySpan source, Span destPixels) + internal override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -56,8 +87,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -73,8 +105,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -90,8 +123,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -107,8 +141,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -124,8 +159,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -141,8 +177,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +195,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index cda6dbf72..c828053a4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,16 +25,18 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb48(ReadOnlySpan source, Span destPixels) + internal override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -39,8 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -56,8 +62,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -73,8 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -90,8 +98,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -107,8 +116,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -124,8 +134,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -141,8 +152,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +170,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index ab264f870..9c29bd044 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,76 +25,108 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba32(ReadOnlySpan source, Span destPixels) + internal override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); } } - + /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); + } + } + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); + } + } - dp.FromRgba32(sp); + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); } } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -107,8 +142,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -124,8 +160,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -141,8 +178,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +196,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index 4bc6b101a..db9cb84be 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -3,7 +3,10 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,16 +25,18 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba64(ReadOnlySpan source, Span destPixels) + internal override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -39,8 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -56,8 +62,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -73,8 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -90,8 +98,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -107,8 +116,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -124,8 +134,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -141,8 +152,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,8 +170,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index 176075a40..cc8cb0e2f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -8,27 +8,37 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ - static readonly string[] CommonPixelTypeNames = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + + static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" }; + + // Types with Rgba32-combatible to/from Vector4 conversion + static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" }; void GenerateDefaultSelfConversionMethods(string pixelType) { #> /// - internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) + internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); } /// - internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) + internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -42,8 +52,9 @@ using System.Runtime.InteropServices; #> /// - internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) + internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,13 +71,97 @@ using System.Runtime.InteropServices; <#+ } + void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType) + { + #> + /// + internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As<<#=thisPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As<<#=otherPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(sp); + } + } + + /// + internal override void From<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=otherPixelType#>> sourcePixels, Span<<#=thisPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As<<#=otherPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As<<#=thisPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sp); + } + } + <#+ + } + + void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType) + { + #> + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + <#+ + } + void GenerateAllDefaultConversionMethods(string pixelType) { GenerateDefaultSelfConversionMethods(pixelType); - var allOtherPixelTypes = CommonPixelTypeNames.Where(p => p != pixelType); + if (Rgba32CompatibleTypes.Contains(pixelType)) + { + GenerateRgba32CompatibleVector4ConversionMethods(pixelType); + } + + var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ? + Optimized32BitTypes.Where(p => p != pixelType) : + Enumerable.Empty(); + + foreach (string destPixelType in matching32BitTypes) + { + GenerateOptimized32BitConversionMethods(pixelType, destPixelType); + } + + var otherCommonNon32Types = CommonPixelTypes + .Where(p => p != pixelType) + .Except(matching32BitTypes); - foreach (string destPixelType in allOtherPixelTypes) + foreach (string destPixelType in otherCommonNon32Types) { GenerateDefaultConvertToMethod(pixelType, destPixelType); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs index d23fda799..4ed5904c2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() => $"Gray8({this.PackedValue}"; + public override string ToString() => $"Gray8({this.PackedValue})"; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index c25baa451..004b25cd3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -19,41 +19,51 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations : PixelOperations { /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) { - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - destinationVectors = destinationVectors.Slice(0, sourceColors.Length); + destVectors = destVectors.Slice(0, sourcePixels.Length); SimdUtils.BulkConvertByteToNormalizedFloat( - MemoryMarshal.Cast(sourceColors), - MemoryMarshal.Cast(destinationVectors)); + MemoryMarshal.Cast(sourcePixels), + MemoryMarshal.Cast(destVectors)); } /// - internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) + internal override void FromVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) { - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - destinationColors = destinationColors.Slice(0, sourceVectors.Length); + destPixels = destPixels.Slice(0, sourceVectors.Length); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(destinationColors)); + MemoryMarshal.Cast(destPixels)); } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { - this.ToVector4(sourceColors, destinationVectors); + this.ToVector4(configuration, sourceColors, destinationVectors); } /// internal override void FromScaledVector4( + Configuration configuration, ReadOnlySpan sourceVectors, Span destinationColors) { - this.FromVector4(sourceVectors, destinationColors); + this.FromVector4(configuration, sourceVectors, destinationColors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index d1f326365..bffaf57dd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// internal override void FromScaledVector4( + Configuration configuration, ReadOnlySpan sourceVectors, Span destinationColors) { @@ -29,16 +30,20 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToScaledVector4( + Configuration configuration, ReadOnlySpan sourceColors, Span destinationVectors) - => this.ToVector4(sourceColors, destinationVectors); + => this.ToVector4(configuration, sourceColors, destinationVectors); /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) { - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - MemoryMarshal.Cast(sourceColors).CopyTo(destinationVectors); + MemoryMarshal.Cast(sourcePixels).CopyTo(destVectors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 07ecf8756..207a8767d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -13,9 +13,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels) + internal virtual void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -32,24 +33,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromArgb32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromArgb32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromArgb32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -66,24 +69,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToArgb32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels) + internal virtual void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -100,24 +105,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgr24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgr24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromBgr24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -134,24 +141,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToBgr24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgr24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels) + internal virtual void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -168,24 +177,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgra32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgra32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromBgra32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -202,24 +213,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToBgra32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgra32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromGray8(ReadOnlySpan source, Span destPixels) + internal virtual void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -236,24 +249,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray8Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray8(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromGray8(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -270,24 +285,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToGray8Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToGray8(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromGray16(ReadOnlySpan source, Span destPixels) + internal virtual void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -304,24 +321,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray16(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromGray16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -338,24 +357,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToGray16Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToGray16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -372,24 +393,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgb24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -406,24 +429,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgb24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -440,24 +465,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgba32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -474,24 +501,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgba32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -508,24 +537,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb48Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb48(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgb48(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -542,24 +573,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgb48Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb48(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -576,24 +609,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba64Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba64(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgba64(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -610,16 +645,17 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgba64Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba64(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index ef73378a2..8579423b3 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -18,9 +18,10 @@ /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels) + internal virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -37,16 +38,17 @@ } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void From<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); + this.From<#=pixelType#>(configuration, MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); } <# @@ -58,9 +60,10 @@ /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) + internal virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -77,16 +80,17 @@ } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); + this.To<#=pixelType#>(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); } <# } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 126db8533..f4eb19be3 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,94 +25,85 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// + /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. - internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) + /// The to the destination colors. + internal virtual void FromVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) { - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < sourceVectors.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromVector4(sp); - } + Utils.Vector4Converters.Default.DangerousFromVector4(sourceVectors, destPixels); } /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// - /// The to the source colors. - /// The to the destination vectors. - internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + /// A to configure internal operations + /// The to the source colors. + /// The to the destination vectors. + internal virtual void ToVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) { - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); - - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - for (int i = 0; i < sourceColors.Length; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } + Utils.Vector4Converters.Default.DangerousToVector4(sourcePixels, destVectors); } /// /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// + /// A to configure internal operations /// The to the source vectors. /// The to the destination colors. - internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors) + internal virtual void FromScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < sourceVectors.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromScaledVector4(sp); - } + Utils.Vector4Converters.Default.DangerousFromScaledVector4(sourceVectors, destinationColors); } /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// + /// A to configure internal operations /// The to the source colors. /// The to the destination vectors. - internal virtual void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal virtual void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - - for (int i = 0; i < sourceColors.Length; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToScaledVector4(); - } + Utils.Vector4Converters.Default.DangerousToScaledVector4(sourceColors, destinationVectors); } /// /// Converts 'sourceColors.Length' pixels from 'sourceColors' into 'destinationColors'. /// /// The destination pixel type. + /// A to configure internal operations /// The to the source colors. /// The to the destination colors. internal virtual void To( + Configuration configuration, ReadOnlySpan sourceColors, Span destinationColors) where TDestinationPixel : struct, IPixel { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationColors, nameof(destinationColors)); int count = sourceColors.Length; @@ -156,27 +148,5 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromScaledVector4(sp.ToScaledVector4()); } } - - /// - /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size. - /// Throwing an if the condition is not met. - /// - /// The source element type - /// The destination element type - /// The source span - /// The source parameter name - /// The destination span - /// The destination parameter name - /// The minimum length - protected internal static void GuardSpans( - ReadOnlySpan source, - string sourceParamName, - Span destination, - string destinationParamName, - int minLength) - { - Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); - Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs new file mode 100644 index 000000000..55a94fc81 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -0,0 +1,108 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Buffers.Binary; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Contains optimized implementations for conversion between pixel formats. + /// + /// + /// Implementations are based on ideas in: + /// https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs#L84 + /// The JIT can detect and optimize rotation idioms ROTL (Rotate Left) + /// and ROTR (Rotate Right) emitting efficient CPU instructions: + /// https://github.com/dotnet/coreclr/pull/1830 + /// + internal static class PixelConverter + { + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROTL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROTL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + + public static class FromArgb32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // ROTR(8, packedArgb) = [aa bb gg rr] + return (packedArgb >> 8) | (packedArgb << 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // REVERSE(packedArgb) = [aa rr gg bb] + return BinaryPrimitives.ReverseEndianness(packedArgb); + } + } + + public static class FromBgra32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedBgra) + { + // packedBgra = [aa rr gg bb] + // REVERSE(packedBgra) = [bb gg rr aa] + return BinaryPrimitives.ReverseEndianness(packedBgra); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedBgra) + { + // packedRgba = [aa rr gg bb] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 rr 00 bb] + // tmp3=ROTL(16, tmp2) = [00 bb 00 rr] + // tmp1 + tmp3 = [aa bb gg rr] + uint tmp1 = packedBgra & 0xFF00FF00; + uint tmp2 = packedBgra & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs new file mode 100644 index 000000000..139dbfa10 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs @@ -0,0 +1,89 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Helper class for (bulk) conversion of buffers to/from other buffer types. + /// + internal static partial class Vector4Converters + { + /// + /// Provides default implementations for batched to/from conversion. + /// WARNING: The methods are operating without bounds checking and input validation! + /// Input validation is the responsibility of the caller! + /// + public static class Default + { + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromVector4( + ReadOnlySpan sourceVectors, + Span destPixels) + where TPixel : struct, IPixel + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToVector4( + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromScaledVector4( + ReadOnlySpan sourceVectors, + Span destinationColors) + where TPixel : struct, IPixel + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromScaledVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToScaledVector4( + ReadOnlySpan sourceColors, + Span destinationVectors) + where TPixel : struct, IPixel + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + + for (int i = 0; i < sourceColors.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToScaledVector4(); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs new file mode 100644 index 000000000..7c57fe4fb --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -0,0 +1,154 @@ +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Contains + /// + internal static partial class Vector4Converters + { + /// + /// Provides efficient implementations for batched to/from conversion. + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + public static class RgbaCompatible + { + /// + /// It's not worth to bother the transitive pixel conversion method below this limit. + /// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT. + /// + private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); + + /// + /// Provides an efficient default implementation for + /// and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ToVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors, + bool scaled) + where TPixel : struct, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + int count = sourcePixels.Length; + + // Not worth for small buffers: + if (count < Vector4ConversionThreshold) + { + ToVector4Fallback(sourcePixels, destVectors, scaled); + + return; + } + + // 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); + pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); + + // '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(); + } + + /// + /// Provides an efficient default implementation for + /// and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void FromVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourceVectors, + Span destPixels, + bool scaled) + where TPixel : struct, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + int count = sourceVectors.Length; + + // Not worth for small buffers: + if (count < Vector4ConversionThreshold) + { + FromVector4Fallback(sourceVectors, destPixels, scaled); + + 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; + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(tempSpan)); + + pixelOperations.FromRgba32(configuration, tempSpan, destPixels); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ToVector4Fallback(ReadOnlySpan sourcePixels, Span destVectors, bool scaled) + where TPixel : struct, IPixel + { + if (scaled) + { + Default.DangerousToScaledVector4(sourcePixels, destVectors); + } + else + { + Default.DangerousToVector4(sourcePixels, destVectors); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void FromVector4Fallback(ReadOnlySpan sourceVectors, Span destPixels, bool scaled) + where TPixel : struct, IPixel + { + if (scaled) + { + Default.DangerousFromScaledVector4(sourceVectors, destPixels); + } + else + { + Default.DangerousFromVector4(sourceVectors, destPixels); + } + } + + private static int CalculateVector4ConversionThreshold() + { + if (!Vector.IsHardwareAccelerated) + { + return int.MaxValue; + } + + return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index a26fe6bfd..bd1419e4b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 98accb606..05007c370 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index dcecf2b82..8ef64bdac 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs index fd9380109..f01865ec0 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering { @@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// The vector representation of the image palette. /// - private readonly Vector4[] paletteVector; + private Vector4[] paletteVector; /// /// Initializes a new instance of the class. @@ -30,8 +31,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering protected PaletteDitherProcessorBase(TPixel[] palette) { this.Palette = palette ?? throw new ArgumentNullException(nameof(palette)); - this.paletteVector = new Vector4[this.Palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.Palette, this.paletteVector); } /// @@ -40,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public TPixel[] Palette { get; } /// - /// Returns the two closest colors from the palette calcluated via Euclidean distance in the Rgba space. + /// Returns the two closest colors from the palette calculated via Euclidean distance in the Rgba space. /// /// The source color to match. /// The . @@ -90,5 +89,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering return pair; } + + protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + base.BeforeFrameApply(source, sourceRectangle, configuration); + + // Lazy init paletteVector: + if (this.paletteVector == null) + { + this.paletteVector = new Vector4[this.Palette.Length]; + PixelOperations.Instance.ToScaledVector4(configuration, this.Palette, this.paletteVector); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 4adddd153..25787ff92 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, colors.GetSpan(), destination, diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 93d6edff1..21f6be69f 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, destination, rowColors.GetSpan(), diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 52dade4ef..a8fa1d65c 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, destination, rowColors.GetSpan(), diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index bc0ed0eab..a8c6c5d7e 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Collect the palette. Required before the second pass runs. TPixel[] palette = this.GetPalette(); this.paletteVector = new Vector4[palette.Length]; - PixelOperations.Instance.ToScaledVector4(palette, this.paletteVector); + PixelOperations.Instance.ToScaledVector4(image.Configuration, palette, this.paletteVector); var quantizedFrame = new QuantizedFrame(image.MemoryAllocator, width, height, palette); if (this.Dither) diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs index 3da09cde0..f1490a6d2 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs @@ -19,18 +19,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Creates the generic frame quantizer /// + /// The to configure internal operations. /// The pixel format. /// The - IFrameQuantizer CreateFrameQuantizer() + IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel; /// /// Creates the generic frame quantizer /// /// The pixel format. + /// The to configure internal operations. /// The maximum number of colors to hold in the color palette. /// The - IFrameQuantizer CreateFrameQuantizer(int maxColors) + IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 22bb5223f..38962c768 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -74,13 +74,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public int MaxColors { get; } + /// /// - public IFrameQuantizer CreateFrameQuantizer() + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel => new OctreeFrameQuantizer(this); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { maxColors = maxColors.Clamp(1, DefaultMaxColors); diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index 625400413..cab3af6de 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -31,9 +31,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Initializes a new instance of the class. /// + /// The to configure internal operations. /// The palette quantizer. /// An array of all colors in the palette. - public PaletteFrameQuantizer(PaletteQuantizer quantizer, TPixel[] colors) + public PaletteFrameQuantizer(Configuration configuration, PaletteQuantizer quantizer, TPixel[] colors) : base(quantizer, true) { // TODO: Why is this value constrained? Gif has limitations but theoretically @@ -41,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors)); this.palette = colors; this.paletteVector = new Vector4[this.palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector); + PixelOperations.Instance.ToScaledVector4(configuration, this.palette, this.paletteVector); } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 27ef05dfe..361791253 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -43,12 +43,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public IErrorDiffuser Diffuser { get; } /// - public virtual IFrameQuantizer CreateFrameQuantizer() + public virtual IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel - => this.CreateFrameQuantizer(() => NamedColors.WebSafePalette); + => this.CreateFrameQuantizer(configuration, () => NamedColors.WebSafePalette); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { TPixel[] websafe = NamedColors.WebSafePalette; @@ -56,21 +56,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (max != websafe.Length) { - return this.CreateFrameQuantizer(() => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); + return this.CreateFrameQuantizer(configuration, () => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); } - return this.CreateFrameQuantizer(() => websafe); + return this.CreateFrameQuantizer(configuration, () => websafe); } /// /// Gets the palette to use to quantize the image. /// /// The pixel format. + /// The to configure internal operations /// The method to return the palette. /// The - public IFrameQuantizer CreateFrameQuantizer(Func paletteFunction) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, Func paletteFunction) where TPixel : struct, IPixel - => new PaletteFrameQuantizer(this, paletteFunction.Invoke()); + => new PaletteFrameQuantizer(configuration, this, paletteFunction.Invoke()); private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs index bd5a6e9ec..8da89bf94 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(); + IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(configuration); using (QuantizedFrame quantized = executor.QuantizeFrame(source)) { int paletteCount = quantized.Palette.Length - 1; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 98a5d5eb5..43d22597d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { Span row = source.GetPixelRowSpan(y); Span rgbaSpan = rgbaBuffer.GetSpan(); - PixelOperations.Instance.ToRgba32(row, rgbaSpan); + PixelOperations.Instance.ToRgba32(source.Configuration, row, rgbaSpan); ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); // And loop through each column diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 5123e737d..4cd09a14f 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -73,13 +73,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public int MaxColors { get; } + /// /// - public IFrameQuantizer CreateFrameQuantizer() + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel => new WuFrameQuantizer(this); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { maxColors = maxColors.Clamp(1, DefaultMaxColors); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 05c4464f1..4d4ed06ce 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span sourceRow = source.GetPixelRowSpan(y); Span tempRowSpan = tempRowBuffer.Span; - PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan); + PixelOperations.Instance.ToVector4(configuration, sourceRow, tempRowSpan); Vector4Utils.Premultiply(tempRowSpan); ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; @@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, tempRowSpan, targetRowSpan); } }); } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs index f3245ebaf..b96422176 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -20,14 +20,20 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner source; - [Params(16, 128, 1024)] + private Configuration configuration; + + [Params( + 128, + 1024, + 2048)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count * 4); + this.configuration = Configuration.Default; + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count); + this.source = this.configuration.MemoryAllocator.Allocate(this.Count * 4); } [GlobalCleanup] @@ -37,8 +43,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.Dispose(); } - [Benchmark(Baseline = true)] - public void PerElement() + //[Benchmark] + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -52,20 +58,35 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() { - new PixelOperations().FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] public void OptimizedBulk() { - PixelOperations.Instance.FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } - public class FromRgba32BytesRgba32 : FromRgba32Bytes + public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes + { + } + + public class FromRgba32Bytes_ToBgra32 : FromRgba32Bytes { + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------- |------ |-----------:|----------:|----------:|-------:| + // CommonBulk | 128 | 207.1 ns | 3.723 ns | 3.300 ns | 1.00 | + // OptimizedBulk | 128 | 166.5 ns | 1.204 ns | 1.005 ns | 0.80 | + // | | | | | | + // CommonBulk | 1024 | 1,333.9 ns | 12.426 ns | 11.624 ns | 1.00 | + // OptimizedBulk | 1024 | 974.1 ns | 18.803 ns | 16.669 ns | 0.73 | + // | | | | | | + // CommonBulk | 2048 | 2,625.4 ns | 30.143 ns | 26.721 ns | 1.00 | + // OptimizedBulk | 2048 | 1,843.0 ns | 20.505 ns | 18.177 ns | 0.70 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 1cd8c0196..2b9573ed7 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -24,6 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; + protected Configuration Configuration => Configuration.Default; + [Params( 64, 2048 @@ -33,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [GlobalSetup] public void Setup() { - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); + this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] @@ -59,13 +61,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan()); + new PixelOperations().FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan()); + PixelOperations.Instance.FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs new file mode 100644 index 000000000..294baa9d5 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs @@ -0,0 +1,60 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming + +using System.Buffers; +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + public abstract class Rgb24Bytes + where TPixel : struct, IPixel + { + private IMemoryOwner source; + + private IMemoryOwner destination; + + private Configuration configuration; + + [Params(16, 128, 1024)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.configuration = Configuration.Default; + this.source = this.configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count * 3); + } + + [GlobalCleanup] + public void Cleanup() + { + this.source.Dispose(); + this.destination.Dispose(); + } + + [Benchmark(Baseline = true)] + public void CommonBulk() => + new PixelOperations().ToRgb24Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); + + [Benchmark] + public void OptimizedBulk() => + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); + } + + public class Rgb24Bytes_Rgba32 : Rgb24Bytes + { + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs similarity index 55% rename from tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs index 0cf7087d4..7f4b2bc41 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs @@ -12,21 +12,24 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - public abstract class ToXyzw + public abstract class ToRgba32Bytes where TPixel : struct, IPixel { private IMemoryOwner source; private IMemoryOwner destination; + private Configuration configuration; + [Params(16, 128, 1024)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count * 4); + this.configuration = Configuration.Default; + this.source = this.configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count * 4); } [GlobalCleanup] @@ -36,8 +39,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark(Baseline = true)] - public void PerElement() + //[Benchmark] + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -55,18 +58,32 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] - public void CommonBulk() => new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + [Benchmark(Baseline = true)] + public void CommonBulk() => + new PixelOperations().ToRgba32Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); [Benchmark] - public void OptimizedBulk() => PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void OptimizedBulk() => + PixelOperations.Instance.ToRgba32Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); + } + + public class ToRgba32Bytes_FromRgba32 : ToRgba32Bytes + { } - public class ToXyzw_Rgba32 : ToXyzw + public class ToRgba32Bytes_FromArgb32 : ToRgba32Bytes { } - public class ToXyzw_Argb32 : ToXyzw + public class ToRgba32Bytes_FromBgra32 : ToRgba32Bytes { } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index e313953a6..70de8f4e2 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -6,14 +6,8 @@ using System.Buffers; using System; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Attributes.Jobs; -using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Environments; -using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -27,20 +21,21 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; + protected Configuration Configuration => Configuration.Default; + [Params( - 64, - //256, + 64, + 256, //512, //1024, - 2048 - )] + 2048)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); + this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] @@ -51,7 +46,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } //[Benchmark] - public void PerElement() + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -61,160 +56,15 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk d[i] = s[i].ToVector4(); } } - - [Benchmark] - public void PixelOperations_Base() - { - new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan()); - } - - [Benchmark] - public void PixelOperations_Specialized() - { - PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan()); - } - } - - [Config(typeof(Config.ShortClr))] - public class ToVector4_Rgba32 : ToVector4 - { - [Benchmark] - public void FallbackIntrinsics128() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - [Benchmark(Baseline = true)] - public void BasicIntrinsics256() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } [Benchmark] - public void ExtendedIntrinsics() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - - //[Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - int n = dFloats.Length / Vector.Count; - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); - ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); - - for (int i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); - d = w0; - Unsafe.Add(ref d, 1) = w1; - Unsafe.Add(ref d, 2) = w2; - Unsafe.Add(ref d, 3) = w3; - } - - n = dFloats.Length / Vector.Count; - var scale = new Vector(1f / 255f); - - for (int i = 0; i < n; i++) - { - ref Vector dRef = ref Unsafe.Add(ref destBase, i); - - Vector du = Vector.AsVectorInt32(dRef); - Vector v = Vector.ConvertToSingle(du); - v *= scale; - - dRef = v; - } - } - - //[Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - int n = dFloats.Length / Vector.Count; - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); - var scale = new Vector(1f / 255f); - - for (int i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - Vector f0 = ConvertToNormalizedSingle(w0, scale); - Vector f1 = ConvertToNormalizedSingle(w1, scale); - Vector f2 = ConvertToNormalizedSingle(w2, scale); - Vector f3 = ConvertToNormalizedSingle(w3, scale); - - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) + public void PixelOperations_Specialized() { - Vector vi = Vector.AsVectorInt32(u); - Vector v = Vector.ConvertToSingle(vi); - v *= scale; - return v; + PixelOperations.Instance.ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); } - - // RESULTS (2018 October): - // - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| - // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | - // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | - // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! - // | | | | | | | | | | - // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | - // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | - // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | - // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | - // | | | | | | | | | | - // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | - // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! - // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( - // | | | | | | | | | | - // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | - // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! - // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs new file mode 100644 index 000000000..39702d525 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs @@ -0,0 +1,41 @@ +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public class ToVector4_Bgra32 : ToVector4 + { + [Benchmark(Baseline = true)] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + + // RESULTS: + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |-----------:|------------:|-----------:|-------:|---------:|-------:|----------:| + // PixelOperations_Base | Clr | 64 | 339.9 ns | 138.30 ns | 7.8144 ns | 1.00 | 0.00 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 338.1 ns | 13.30 ns | 0.7515 ns | 0.99 | 0.02 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 64 | 245.6 ns | 29.05 ns | 1.6413 ns | 1.00 | 0.00 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 257.1 ns | 37.89 ns | 2.1407 ns | 1.05 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Clr | 256 | 972.7 ns | 61.98 ns | 3.5020 ns | 1.00 | 0.00 | 0.0057 | 24 B | + // PixelOperations_Specialized | Clr | 256 | 882.9 ns | 126.21 ns | 7.1312 ns | 0.91 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 256 | 910.0 ns | 90.87 ns | 5.1346 ns | 1.00 | 0.00 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 256 | 448.4 ns | 15.77 ns | 0.8910 ns | 0.49 | 0.00 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Clr | 2048 | 6,951.8 ns | 1,299.01 ns | 73.3963 ns | 1.00 | 0.00 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 5,852.3 ns | 630.56 ns | 35.6279 ns | 0.84 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 2048 | 6,937.5 ns | 1,692.19 ns | 95.6121 ns | 1.00 | 0.00 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,994.5 ns | 1,126.65 ns | 63.6578 ns | 0.43 | 0.01 | - | 0 B | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs new file mode 100644 index 000000000..ab05a1407 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs @@ -0,0 +1,164 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public class ToVector4_Rgba32 : ToVector4 + { + [Benchmark] + public void FallbackIntrinsics128() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + + [Benchmark(Baseline = true)] + public void BasicIntrinsics256() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsics() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dFloats.Length / Vector.Count; + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector dRef = ref Unsafe.Add(ref destBase, i); + + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + dRef = v; + } + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToNormalizedSingle(w0, scale); + Vector f1 = ConvertToNormalizedSingle(w1, scale); + Vector f2 = ConvertToNormalizedSingle(w2, scale); + Vector f3 = ConvertToNormalizedSingle(w3, scale); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } + + // RESULTS (2018 October): + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | + // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs deleted file mode 100644 index f96023f00..000000000 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// ReSharper disable InconsistentNaming - -using System.Buffers; -using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk -{ - public abstract class ToXyz - where TPixel : struct, IPixel - { - private IMemoryOwner source; - - private IMemoryOwner destination; - - [Params(16, 128, 1024)] - public int Count { get; set; } - - [GlobalSetup] - public void Setup() - { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count * 3); - } - - [GlobalCleanup] - public void Cleanup() - { - this.source.Dispose(); - this.destination.Dispose(); - } - - [Benchmark(Baseline = true)] - public void CommonBulk() => new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - - [Benchmark] - public void OptimizedBulk() => PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - public class ToXyz_Rgba32 : ToXyz - { - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 6a96c8576..9f1b2721b 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -1,21 +1,24 @@ // ReSharper disable InconsistentNaming +using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.Utils; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { - public class PixelConversion_ConvertFromRgba32 + public abstract class PixelConversion_ConvertFromRgba32 { - struct ConversionRunner + internal struct ConversionRunner where T : struct, ITestPixel { - private T[] dest; + public readonly T[] dest; - private Rgba32[] source; + public readonly Rgba32[] source; public ConversionRunner(int count) { @@ -67,72 +70,146 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - private ConversionRunner compatibleMemLayoutRunner; + internal ConversionRunner compatibleMemLayoutRunner; - private ConversionRunner permutedRunner; + internal ConversionRunner permutedRunnerRgbaToArgb; - [Params(32)] + [Params( + 256, + 2048 + )] public int Count { get; set; } [GlobalSetup] public void Setup() { this.compatibleMemLayoutRunner = new ConversionRunner(this.Count); - this.permutedRunner = new ConversionRunner(this.Count); + this.permutedRunnerRgbaToArgb = new ConversionRunner(this.Count); } + } + public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_ConvertFromRgba32 + { [Benchmark(Baseline = true)] - public void CompatibleByRef() + public void ByRef() { this.compatibleMemLayoutRunner.RunByRefConversion(); } [Benchmark] - public void CompatibleByVal() + public void ByVal() { this.compatibleMemLayoutRunner.RunByValConversion(); } [Benchmark] - public void CompatibleFromBytes() + public void FromBytes() { this.compatibleMemLayoutRunner.RunFromBytesConversion(); } + [Benchmark] + public void Inline() + { + ref Rgba32 sBase = ref this.compatibleMemLayoutRunner.source[0]; + ref Rgba32 dBase = ref Unsafe.As(ref this.compatibleMemLayoutRunner.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i); + } + } + + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------- |------ |---------:|---------:|---------:|-------:|---------:| + // ByRef | 256 | 128.5 ns | 1.217 ns | 1.138 ns | 1.00 | 0.00 | + // ByVal | 256 | 196.7 ns | 2.792 ns | 2.612 ns | 1.53 | 0.02 | + // FromBytes | 256 | 321.7 ns | 2.180 ns | 1.820 ns | 2.50 | 0.03 | + // Inline | 256 | 129.9 ns | 2.759 ns | 2.581 ns | 1.01 | 0.02 | + } + + public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConversion_ConvertFromRgba32 + { + [Benchmark(Baseline = true)] + public void ByRef() + { + this.permutedRunnerRgbaToArgb.RunByRefConversion(); + } + + [Benchmark] + public void ByVal() + { + this.permutedRunnerRgbaToArgb.RunByValConversion(); + } + + [Benchmark] + public void FromBytes() + { + this.permutedRunnerRgbaToArgb.RunFromBytesConversion(); + } [Benchmark] - public void PermutedByRef() + public void InlineShuffle() { - this.permutedRunner.RunByRefConversion(); + ref Rgba32 sBase = ref this.permutedRunnerRgbaToArgb.source[0]; + ref TestArgb dBase = ref this.permutedRunnerRgbaToArgb.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + ref TestArgb d = ref Unsafe.Add(ref dBase, i); + + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + } } [Benchmark] - public void PermutedByVal() + public void PixelConverter_Rgba32_ToArgb32() { - this.permutedRunner.RunByValConversion(); + ref uint sBase = ref Unsafe.As(ref this.permutedRunnerRgbaToArgb.source[0]); + ref uint dBase = ref Unsafe.As(ref this.permutedRunnerRgbaToArgb.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); + } } [Benchmark] - public void PermutedFromBytes() + public void PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer() { - this.permutedRunner.RunFromBytesConversion(); + Span source = MemoryMarshal.Cast(this.permutedRunnerRgbaToArgb.source); + Span dest = MemoryMarshal.Cast(this.permutedRunnerRgbaToArgb.dest); + source.CopyTo(dest); + + ref uint dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref dBase, i); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); + } } - } - /* - * Results: - * Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | - * ------------------ |------ |----------- |---------- |------- |-------------- | - * CompatibleByRef | 32 | 20.6339 ns | 0.0742 ns | 1.00 | 0.00 | - * CompatibleByVal | 32 | 23.7425 ns | 0.0997 ns | 1.15 | 0.01 | - * CompatibleFromBytes | 32 | 38.7017 ns | 0.1103 ns | 1.88 | 0.01 | - * PermutedByRef | 32 | 39.2892 ns | 0.1366 ns | 1.90 | 0.01 | - * PermutedByVal | 32 | 38.5178 ns | 0.1946 ns | 1.87 | 0.01 | - * PermutedFromBytes | 32 | 38.6683 ns | 0.0801 ns | 1.87 | 0.01 | - * - * !!! Conclusion !!! - * All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution. - * In memory compatible cases we should use the optimized Bulk-copying variant anyways, - * so there is no benefit introducing non-bulk API-s other than FromBytes() OR FromRgba32(). - */ + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------------------------------------------------------- |------ |-----------:|-----------:|-----------:|-------:|---------:| + // ByRef | 256 | 328.7 ns | 6.6141 ns | 6.1868 ns | 1.00 | 0.00 | + // ByVal | 256 | 322.0 ns | 4.3541 ns | 4.0728 ns | 0.98 | 0.02 | + // FromBytes | 256 | 321.5 ns | 3.3499 ns | 3.1335 ns | 0.98 | 0.02 | + // InlineShuffle | 256 | 330.7 ns | 4.2525 ns | 3.9778 ns | 1.01 | 0.02 | + // PixelConverter_Rgba32_ToArgb32 | 256 | 167.4 ns | 0.6357 ns | 0.5309 ns | 0.51 | 0.01 | + // PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 256 | 196.6 ns | 0.8929 ns | 0.7915 ns | 0.60 | 0.01 | + // | | | | | | | + // ByRef | 2048 | 2,534.4 ns | 8.2947 ns | 6.9265 ns | 1.00 | 0.00 | + // ByVal | 2048 | 2,638.5 ns | 52.6843 ns | 70.3320 ns | 1.04 | 0.03 | + // FromBytes | 2048 | 2,517.2 ns | 40.8055 ns | 38.1695 ns | 0.99 | 0.01 | + // InlineShuffle | 2048 | 2,546.5 ns | 21.2506 ns | 19.8778 ns | 1.00 | 0.01 | + // PixelConverter_Rgba32_ToArgb32 | 2048 | 1,265.7 ns | 5.1397 ns | 4.5562 ns | 0.50 | 0.00 | + // PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 2048 | 1,410.3 ns | 11.1939 ns | 9.9231 ns | 0.56 | 0.00 |// + } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs new file mode 100644 index 000000000..40893914e --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -0,0 +1,176 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_Rgba32_To_Argb32 + { + private Rgba32[] source; + + private Argb32[] dest; + + [Params(64)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.source = new Rgba32[this.Count]; + this.dest = new Argb32[this.Count]; + } + + [Benchmark(Baseline = true)] + public void Default() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Default_GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [Benchmark] + public void Default_Generic() + { + Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void Default_Group2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i += 2) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + Rgba32 s1 = Unsafe.Add(ref s0, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + d0.FromRgba32(s0); + Unsafe.Add(ref d0, 1).FromRgba32(s1); + } + } + + + [Benchmark] + public void Default_Group4() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); + ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [Benchmark] + public void BitOps() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = FromRgba32.ToArgb32(s); + } + } + + [Benchmark] + public void BitOps_GroupAsULong() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + lo = FromRgba32.ToArgb32(lo); + hi = FromRgba32.ToArgb32(hi); + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------------- |------ |----------:|----------:|----------:|-------:| + // Default | 64 | 107.33 ns | 1.0633 ns | 0.9426 ns | 1.00 | + // Default_Generic | 64 | 111.15 ns | 0.3789 ns | 0.3544 ns | 1.04 | + // Default_Group2 | 64 | 90.36 ns | 0.7779 ns | 0.6896 ns | 0.84 | + // Default_Group4 | 64 | 82.39 ns | 0.2726 ns | 0.2550 ns | 0.77 | + // BitOps | 64 | 39.25 ns | 0.3266 ns | 0.2895 ns | 0.37 | + // BitOps_GroupAsULong | 64 | 41.80 ns | 0.2227 ns | 0.2083 ns | 0.39 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs new file mode 100644 index 000000000..a8fea6866 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -0,0 +1,392 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tuples; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + //[MonoJob] + //[RyuJitX64Job] + public class PixelConversion_Rgba32_To_Bgra32 + { + private Rgba32[] source; + + private Bgra32[] dest; + + [StructLayout(LayoutKind.Sequential)] + struct Tuple4OfUInt32 + { + public uint V0, V1, V2, V3; + + public void ConvertMe() + { + this.V0 = FromRgba32.ToBgra32(this.V0); + this.V1 = FromRgba32.ToBgra32(this.V1); + this.V2 = FromRgba32.ToBgra32(this.V2); + this.V3 = FromRgba32.ToBgra32(this.V3); + } + } + + [Params(64)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.source = new Rgba32[this.Count]; + this.dest = new Bgra32[this.Count]; + } + + [Benchmark(Baseline = true)] + public void Default() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Default_GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i++) + { + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [Benchmark] + public void Default_Generic() + { + Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void Default_Group2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i+=2) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + Rgba32 s1 = Unsafe.Add(ref s0, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + d0.FromRgba32(s0); + Unsafe.Add(ref d0, 1).FromRgba32(s1); + } + } + + [Benchmark] + public void Default_Group4() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); + ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Group4GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref TPixel d0 = ref Unsafe.Add(ref dBase, i); + ref TPixel d1 = ref Unsafe.Add(ref d0, 1); + ref TPixel d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + //[Benchmark] + public void Default_Group4_Generic() + { + Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + //[Benchmark] + public void Default_Group8() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + ref Rgba32 s3 = ref Unsafe.Add(ref s1, 1); + + ref Rgba32 s4 = ref Unsafe.Add(ref s3, 1); + ref Rgba32 s5 = ref Unsafe.Add(ref s4, 1); + ref Rgba32 s6 = ref Unsafe.Add(ref s5, 1); + Rgba32 s7 = Unsafe.Add(ref s6, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); + ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); + ref Bgra32 d3 = ref Unsafe.Add(ref d2, 1); + ref Bgra32 d4 = ref Unsafe.Add(ref d3, 1); + + ref Bgra32 d5 = ref Unsafe.Add(ref d4, 1); + ref Bgra32 d6 = ref Unsafe.Add(ref d5, 1); + + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + d3.FromRgba32(s3); + + d4.FromRgba32(s4); + d5.FromRgba32(s5); + d6.FromRgba32(s6); + Unsafe.Add(ref d6, 1).FromRgba32(s7); + } + } + + [Benchmark] + public void BitOps() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = FromRgba32.ToBgra32(s); + } + } + + [Benchmark] + public void Bitops_Tuple() + { + ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + ref Tuple4OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 4; i++) + { + ref Tuple4OfUInt32 d = ref Unsafe.Add(ref dBase, i); + d = Unsafe.Add(ref sBase, i); + d.ConvertMe(); + } + } + + //[Benchmark] + public void Bitops_SingleTuple() + { + ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + + for (int i = 0; i < this.Count / 4; i++) + { + Unsafe.Add(ref sBase, i).ConvertMe(); + } + } + + //[Benchmark] + public void Bitops_Simd() + { + ref Octet.OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + ref Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 8; i++) + { + BitopsSimdImpl(ref Unsafe.Add(ref sBase, i), ref Unsafe.Add(ref dBase, i)); + } + } + + [StructLayout(LayoutKind.Sequential)] + struct B + { + public uint tmp2, tmp5, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23; + } + + [StructLayout(LayoutKind.Sequential)] + struct C + { + public uint tmp3, tmp6, tmp9, tmp12, tmp15, tmp18, tmp21, tmp24; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void BitopsSimdImpl(ref Octet.OfUInt32 s, ref Octet.OfUInt32 d) + { + Vector sVec = Unsafe.As>(ref s); + Vector aMask = new Vector(0xFF00FF00); + Vector bMask = new Vector(0x00FF00FF); + + Vector aa = sVec & aMask; + Vector bb = sVec & bMask; + + B b = Unsafe.As, B>(ref bb); + + C c = default; + + c.tmp3 = (b.tmp2 << 16) | (b.tmp2 >> 16); + c.tmp6 = (b.tmp5 << 16) | (b.tmp5 >> 16); + c.tmp9 = (b.tmp8 << 16) | (b.tmp8 >> 16); + c.tmp12 = (b.tmp11 << 16) | (b.tmp11 >> 16); + c.tmp15 = (b.tmp14 << 16) | (b.tmp14 >> 16); + c.tmp18 = (b.tmp17 << 16) | (b.tmp17 >> 16); + c.tmp21 = (b.tmp20 << 16) | (b.tmp20 >> 16); + c.tmp24 = (b.tmp23 << 16) | (b.tmp23 >> 16); + + Vector cc = Unsafe.As>(ref c); + Vector dd = aa + cc; + + d = Unsafe.As, Octet.OfUInt32>(ref dd); + } + + //[Benchmark] + public void BitOps_Group2() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + ref uint s0 = ref Unsafe.Add(ref sBase, i); + uint s1 = Unsafe.Add(ref s0, 1); + + ref uint d0 = ref Unsafe.Add(ref dBase, i); + d0 = FromRgba32.ToBgra32(s0); + Unsafe.Add(ref d0, 1) = FromRgba32.ToBgra32(s1); + } + } + + [Benchmark] + public void BitOps_GroupAsULong() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + lo = FromRgba32.ToBgra32(lo); + hi = FromRgba32.ToBgra32(hi); + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + //[Benchmark] + public void BitOps_GroupAsULong_V2() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + + uint tmp1 = lo & 0xFF00FF00; + uint tmp4 = hi & 0xFF00FF00; + + uint tmp2 = lo & 0x00FF00FF; + uint tmp5 = hi & 0x00FF00FF; + + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + uint tmp6 = (tmp5 << 16) | (tmp5 >> 16); + + lo = tmp1 + tmp3; + hi = tmp4 + tmp6; + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // -------------------- |------ |---------:|----------:|----------:|-------:|---------:| + // Default | 64 | 82.67 ns | 0.6737 ns | 0.5625 ns | 1.00 | 0.00 | + // Default_Generic | 64 | 88.73 ns | 1.7959 ns | 1.7638 ns | 1.07 | 0.02 | + // Default_Group2 | 64 | 91.03 ns | 1.5237 ns | 1.3508 ns | 1.10 | 0.02 | + // Default_Group4 | 64 | 86.62 ns | 1.5737 ns | 1.4720 ns | 1.05 | 0.02 | + // BitOps | 64 | 57.45 ns | 0.6067 ns | 0.5066 ns | 0.69 | 0.01 | + // Bitops_Tuple | 64 | 75.47 ns | 1.1824 ns | 1.1060 ns | 0.91 | 0.01 | + // BitOps_GroupAsULong | 64 | 65.42 ns | 0.7157 ns | 0.6695 ns | 0.79 | 0.01 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs index 61a7df81d..76de794ec 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -9,81 +9,81 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [StructLayout(LayoutKind.Sequential)] struct TestArgb : ITestPixel { - private byte a, r, g, b; + public byte A, R, G, B; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(Rgba32 p) { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; + this.R = p.R; + this.G = p.G; + this.B = p.B; + this.A = p.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(ref Rgba32 p) { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; + this.R = p.R; + this.G = p.G; + this.B = p.B; + this.A = p.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte r, byte g, byte b, byte a) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; + this.R = r; + this.G = g; + this.B = b; + this.A = a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.R = (byte)p.X; + this.G = (byte)p.Y; + this.B = (byte)p.Z; + this.A = (byte)p.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(ref Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.R = (byte)p.X; + this.G = (byte)p.Y; + this.B = (byte)p.Z; + this.A = (byte)p.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32 ToRgba32() { - return new Rgba32(this.r, this.g, this.b, this.a); + return new Rgba32(this.R, this.G, this.B, this.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToRgba32(ref Rgba32 dest) { - dest.R = this.r; - dest.G = this.g; - dest.B = this.b; - dest.A = this.a; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.r, this.g, this.b, this.a); + return new Vector4(this.R, this.G, this.B, this.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToVector4(ref Vector4 dest) { - dest.X = this.r; - dest.Y = this.g; - dest.Z = this.b; - dest.W = this.a; + dest.X = this.R; + dest.Y = this.G; + dest.Z = this.B; + dest.W = this.A; } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index cc8cf352a..36d5f3e5b 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [StructLayout(LayoutKind.Sequential)] struct TestRgba : ITestPixel { - private byte r, g, b, a; + public byte R, G, B, A; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(Rgba32 source) @@ -26,10 +26,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte r, byte g, byte b, byte a) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; + this.R = r; + this.G = g; + this.B = b; + this.A = a; } public void FromVector4(Vector4 source) @@ -57,13 +57,13 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.r, this.g, this.b, this.a) * new Vector4(1f / 255f); + return new Vector4(this.R, this.G, this.B, this.A) * new Vector4(1f / 255f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToVector4(ref Vector4 dest) { - var tmp = new Vector4(this.r, this.g, this.b, this.a); + var tmp = new Vector4(this.R, this.G, this.B, this.A); tmp *= new Vector4(1f / 255f); dest = tmp; } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 051646f90..cdd56fa07 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Benchmarks public class PorterDuffBulkVsPixel : BenchmarkBase { + private Configuration Configuration => Configuration.Default; + private void BulkVectorConvert( Span destination, Span background, @@ -35,15 +37,15 @@ namespace SixLabors.ImageSharp.Benchmarks Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToVector4(background, backgroundSpan); - PixelOperations.Instance.ToVector4(source, sourceSpan); + PixelOperations.Instance.ToVector4(this.Configuration, background, backgroundSpan); + PixelOperations.Instance.ToVector4(this.Configuration, source, sourceSpan); for (int i = 0; i < destination.Length; i++) { destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } - PixelOperations.Instance.FromVector4(destinationSpan, destination); + PixelOperations.Instance.FromVector4(this.Configuration, destinationSpan, destination); } } diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 4d89929a0..3a3a7d31c 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -3,6 +3,8 @@ // Licensed under the Apache License, Version 2.0. // +using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; + namespace SixLabors.ImageSharp.Sandbox46 { using System; diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 963d67446..208387e6d 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -6,6 +6,7 @@ using System.Linq; using Moq; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.IO; + using Xunit; // ReSharper disable InconsistentNaming diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index 9121649f4..556ec9c9c 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -328,7 +328,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing TPixel color = colors[stopColorCodes[i % colors.Length]]; float position = stopPositions[i]; colorStops[i] = new ColorStop(position, color); - coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color.ToRgba32().ToHex(), position); + Rgba32 rgba = default; + color.ToRgba32(ref rgba); + coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", rgba.ToHex(), position); } FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]"; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs index cfa421a82..b3219115d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { string imageFile = provider.SourceFileOrDescription; using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile)) - using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder)) + using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder)) using (var imageFrame = new ImageFrame(Configuration.Default, decoder.ImageWidth, decoder.ImageHeight)) { pp.DoPostProcessorStep(imageFrame); @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { string imageFile = provider.SourceFileOrDescription; using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile)) - using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder)) + using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder)) using (var image = new Image(decoder.ImageWidth, decoder.ImageHeight)) { pp.PostProcess(image.Frames.RootFrame); diff --git a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs new file mode 100644 index 000000000..6ff38626d --- /dev/null +++ b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public class GraphicsOptionsTests + { + [Fact] + public void IsOpaqueColor() + { + Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 148b928fa..8f68c9d03 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -90,7 +90,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var input = new Alpha8(128); var expected = new Rgba32(0, 0, 0, 128); - var actual = input.ToRgba32(); + Rgba32 actual = default; + input.ToRgba32(ref actual); Assert.Equal(expected, actual); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 220ca2899..cb19c031d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -117,7 +117,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var gray = new Gray16(input); // Act - var actual = gray.ToRgba32(); + Rgba32 actual = default; + gray.ToRgba32(ref actual); // Assert Assert.Equal(expected, actual.R); diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 988002c09..6a7b20cbe 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -115,10 +115,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var gray = new Gray8(input); // Act - var actual = gray.ToRgba32(); + Rgba32 actual = default; + gray.ToRgba32(ref actual); // Assert - Assert.Equal(input, actual.R); + Assert.Equal(input, actual.R); Assert.Equal(input, actual.G); Assert.Equal(input, actual.B); Assert.Equal(byte.MaxValue, actual.A); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs index 3ea9bcad4..7de1cbb19 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders { new TestPixel(1,1,1,1), new TestPixel(0,0,0,.8f), .5f, new TestPixel(0.6f, 0.6f, 0.6f, 1) }, }; - private MemoryAllocator MemoryAllocator { get; } = Configuration.Default.MemoryAllocator; + private Configuration Configuration => Configuration.Default; [Theory] [MemberData(nameof(NormalBlendFunctionData))] @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.NormalSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.NormalSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.MultiplySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.MultiplySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.AddSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.AddSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.SubtractSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.SubtractSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -206,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.ScreenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.ScreenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.DarkenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.DarkenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.LightenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.LightenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.OverlaySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.OverlaySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -362,7 +362,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.HardLightSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.HardLightSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs new file mode 100644 index 000000000..c539e9dcf --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -0,0 +1,160 @@ +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.Utils; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public abstract class PixelConverterTests + { + public static readonly TheoryData RgbaData = + new TheoryData + { + { 0, 0, 0, 0 }, + { 0, 0, 0, 255 }, + { 0, 0, 255, 0 }, + { 0, 255, 0, 0 }, + { 255, 0, 0, 0 }, + { 255, 255, 255, 255 }, + { 0, 0, 0, 1 }, + { 0, 0, 1, 0 }, + { 0, 1, 0, 0 }, + { 1, 0, 0, 0 }, + { 3, 5, 7, 11 }, + { 67, 71, 101, 109 } + }; + + public class FromRgba32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + public class FromArgb32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + public class FromBgra32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + + private static class ReferenceImplementations + { + public static Rgba32 MakeRgba32(byte r, byte g, byte b, byte a) + { + Rgba32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Argb32 MakeArgb32(byte r, byte g, byte b, byte a) + { + Argb32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Bgra32 MakeBgra32(byte r, byte g, byte b, byte a) + { + Bgra32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs new file mode 100644 index 000000000..c881ae96b --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs @@ -0,0 +1,25 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Argb32OperationsTests : PixelOperationsTests + { + + public Argb32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs new file mode 100644 index 000000000..323d3914c --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Bgr24OperationsTests : PixelOperationsTests + { + public Bgr24OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs new file mode 100644 index 000000000..1c966951f --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Bgra32OperationsTests : PixelOperationsTests + { + public Bgra32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs new file mode 100644 index 000000000..c3de33547 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs @@ -0,0 +1,114 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Gray16OperationsTests : PixelOperationsTests + { + public Gray16OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + expected[i].FromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs new file mode 100644 index 000000000..acd6ef23a --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs @@ -0,0 +1,114 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Gray8OperationsTests : PixelOperationsTests + { + public Gray8OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + expected[i].FromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs new file mode 100644 index 000000000..0a28db6b0 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgb48OperationsTests : PixelOperationsTests + { + public Rgb48OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs new file mode 100644 index 000000000..1ecbaf361 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs @@ -0,0 +1,46 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Buffers; +using System.Numerics; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgba32OperationsTests : PixelOperationsTests + { + public Rgba32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Fact(Skip = SkipProfilingBenchmarks)] + public void Benchmark_ToVector4() + { + const int times = 200000; + const int count = 1024; + + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) + { + this.Measure( + times, + () => PixelOperations.Instance.ToVector4( + this.Configuration, + source.GetSpan(), + dest.GetSpan())); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs new file mode 100644 index 000000000..6787602bb --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgba64OperationsTests : PixelOperationsTests + { + public Rgba64OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs new file mode 100644 index 000000000..f9cc042a7 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class RgbaVectorOperationsTests : PixelOperationsTests + { + public RgbaVectorOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs similarity index 59% rename from tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs rename to tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index 0082e6c0e..d9845e474 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -6,332 +6,67 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; + using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.PixelFormats +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { - public class PixelOperationsTests + public partial class PixelOperationsTests { - public const string SkipProfilingBenchmarks = -#if true - "Profiling benchmark - enable manually!"; -#else - null; -#endif - - public class Argb32OperationsTests : PixelOperationsTests - { - - public Argb32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Bgr24OperationsTests : PixelOperationsTests - { - public Bgr24OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Bgra32OperationsTests : PixelOperationsTests - { - public Bgra32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Gray8OperationsTests : PixelOperationsTests - { - public Gray8OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray8Bytes(int count) - { - byte[] source = CreateByteTestData(count); - var expected = new Gray8[count]; - - for (int i = 0; i < count; i++) - { - expected[i].FromGray8(new Gray8(source[i])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray8Bytes(int count) - { - Gray8[] source = CreatePixelTestData(count); - byte[] expected = new byte[count]; - var gray = default(Gray8); - - for (int i = 0; i < count; i++) - { - gray.FromScaledVector4(source[i].ToScaledVector4()); - expected[i] = gray.PackedValue; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray16Bytes(int count) - { - byte[] source = CreateByteTestData(count * 2); - Span sourceSpan = source.AsSpan(); - var expected = new Gray8[count]; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray16Bytes(int count) - { - Gray8[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 2]; - Gray16 gray = default; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - gray.FromScaledVector4(source[i].ToScaledVector4()); - OctetBytes bytes = Unsafe.As(ref gray); - expected[i2] = bytes[0]; - expected[i2 + 1] = bytes[1]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) - ); - } - } - - public class Gray16OperationsTests : PixelOperationsTests - { - public Gray16OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray8Bytes(int count) - { - byte[] source = CreateByteTestData(count); - var expected = new Gray16[count]; - - for (int i = 0; i < count; i++) - { - expected[i].FromGray8(new Gray8(source[i])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray8Bytes(int count) - { - Gray16[] source = CreatePixelTestData(count); - byte[] expected = new byte[count]; - var gray = default(Gray8); - - for (int i = 0; i < count; i++) - { - gray.FromScaledVector4(source[i].ToScaledVector4()); - expected[i] = gray.PackedValue; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray16Bytes(int count) - { - byte[] source = CreateByteTestData(count * 2); - Span sourceSpan = source.AsSpan(); - var expected = new Gray16[count]; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray16Bytes(int count) - { - Gray16[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 2]; - Gray16 gray = default; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - gray.FromScaledVector4(source[i].ToScaledVector4()); - OctetBytes bytes = Unsafe.As(ref gray); - expected[i2] = bytes[0]; - expected[i2 + 1] = bytes[1]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) - ); - } - } - - public class Rgba32OperationsTests : PixelOperationsTests - { - public Rgba32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Fact(Skip = SkipProfilingBenchmarks)] - public void Benchmark_ToVector4() - { - const int times = 200000; - const int count = 1024; - - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) - { - this.Measure( - times, - () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan())); - } - } - } - - public class Rgb48OperationsTests : PixelOperationsTests - { - public Rgb48OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Rgba64OperationsTests : PixelOperationsTests - { - public Rgba64OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class RgbaVectorOperationsTests : PixelOperationsTests - { - public RgbaVectorOperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - [Theory] [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider _) - where TPixel : struct, IPixel => Assert.NotNull(PixelOperations.Instance); - - [Fact] - public void IsOpaqueColor() - { - Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); - } + public void GetGlobalInstance(TestImageProvider _) + where T : struct, IPixel => Assert.NotNull(PixelOperations.Instance); } public abstract class PixelOperationsTests : MeasureFixture where TPixel : struct, IPixel { + public const string SkipProfilingBenchmarks = +#if true + "Profiling benchmark - enable manually!"; +#else + null; +#endif + protected PixelOperationsTests(ITestOutputHelper output) : base(output) { } - public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 }; + public static TheoryData ArraySizesData => + new TheoryData + { + 0, + 1, + 2, + 7, + 16, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520, + 521, + 522, + 523, + 524, + 525, + 526, + 527, + 528, + 1111 + }; + + protected Configuration Configuration => Configuration.Default; internal static PixelOperations Operations => PixelOperations.Instance; @@ -367,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromVector4(s, d.GetSpan()) + (s, d) => Operations.FromVector4(this.Configuration, s, d.GetSpan()) ); } @@ -381,32 +116,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromScaledVector4(s, d.GetSpan()) + (s, d) => Operations.FromScaledVector4(this.Configuration, s, d.GetSpan()) ); } - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToVector4(); - } - return expected; - } - - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToScaledVector4(); - } - return expected; - } - [Theory] [MemberData(nameof(ArraySizesData))] public void ToVector4(int count) @@ -417,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToVector4(s, d.GetSpan()) + (s, d) => Operations.ToVector4(this.Configuration, s, d.GetSpan()) ); } @@ -431,7 +144,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan()) + (s, d) => Operations.ToScaledVector4(this.Configuration, s, d.GetSpan()) ); } @@ -452,7 +165,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromArgb32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -478,7 +191,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToArgb32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -499,7 +212,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgr24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -523,7 +236,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgr24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -544,7 +257,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgra32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -569,7 +282,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgra32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -590,7 +303,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -614,7 +327,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -635,7 +348,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -660,7 +373,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -681,7 +394,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb48Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -709,7 +422,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb48Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -730,7 +443,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba64Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -760,10 +473,32 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba64Bytes(this.Configuration, s, d.GetSpan(), count) ); } + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToVector4(); + } + return expected; + } + + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToScaledVector4(); + } + return expected; + } + internal static void TestOperation( TSource[] source, TDest[] expected, diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index a60509146..92e8d302d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -104,7 +104,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void ToRgba32() { var rgb = new Rgb24(1, 2, 3); - var rgba = rgb.ToRgba32(); + Rgba32 rgba = default; + rgb.ToRgba32(ref rgba); Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index a7f0e5edf..d30e49860 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -52,7 +52,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 76, 255); // act - var actual = rgba48.ToRgba32(); + Rgba32 actual = default; + rgba48.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index ad7df3076..a897dd4cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -79,7 +79,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(25, 0, 128, 0); // act - var actual = rgba.ToRgba32(); + Rgba32 actual = default; + rgba.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 8c702f66d..ad1d13740 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.PixelFormats { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 564c26b8b..3e5d7a56e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 76, 115); // act - actual = rgba64.ToRgba32(); + rgba64.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 725e1a0d1..c9a3b33c9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(128, 127, 0, 255); // act - actual = short2.ToRgba32(); + short2.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short2.FromRgba32(expected); - actual = short2.ToRgba32(); + short2.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index b19917f34..247342a05 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(172, 177, 243, 128); // act - actual = shortValue.ToRgba32(); + shortValue.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromRgba32(expected); - actual = short4.ToRgba32(); + short4.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -124,7 +124,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromBgra32(expected); - actual.FromRgba32(short4.ToRgba32()); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -140,7 +142,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromArgb32(expected); - actual.FromRgba32(short4.ToRgba32()); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 29c97ce35..bd8c64742 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -84,8 +84,10 @@ namespace SixLabors.ImageSharp.Tests.Colors var color = new Rgba32(24, 48, 96, 192); var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - var rgba = color.ToRgba32(); - var rgbaVector = colorVector.ToRgba32(); + Rgba32 rgba = default; + Rgba32 rgbaVector = default; + color.ToRgba32(ref rgba); + colorVector.ToRgba32(ref rgbaVector); Assert.Equal(rgba, rgbaVector); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 719e9793a..577dc83c5 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -10,6 +10,8 @@ namespace SixLabors.ImageSharp.Tests { public class QuantizedImageTests { + private Configuration Configuration => Configuration.Default; + [Fact] public void QuantizersDitherByDefault() { @@ -21,15 +23,17 @@ namespace SixLabors.ImageSharp.Tests Assert.NotNull(octree.Diffuser); Assert.NotNull(wu.Diffuser); - Assert.True(palette.CreateFrameQuantizer().Dither); - Assert.True(octree.CreateFrameQuantizer().Dither); - Assert.True(wu.CreateFrameQuantizer().Dither); + Assert.True(palette.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(octree.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(wu.CreateFrameQuantizer(this.Configuration).Dither); } [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void PaletteQuantizerYieldsCorrectTransparentPixel(TestImageProvider provider, bool dither) + public void PaletteQuantizerYieldsCorrectTransparentPixel( + TestImageProvider provider, + bool dither) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -40,7 +44,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -51,7 +56,9 @@ namespace SixLabors.ImageSharp.Tests [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void OctreeQuantizerYieldsCorrectTransparentPixel(TestImageProvider provider, bool dither) + public void OctreeQuantizerYieldsCorrectTransparentPixel( + TestImageProvider provider, + bool dither) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -62,7 +69,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -84,7 +92,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -97,9 +106,10 @@ namespace SixLabors.ImageSharp.Tests { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; + Rgba32 trans = default; for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - var trans = quantized.Palette[i].ToRgba32(); + quantized.Palette[i].ToRgba32(ref trans); if (trans.Equals(default)) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 886e02c13..462782ba5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -28,14 +28,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison var bBuffer = new Rgba64[width]; var differences = new List(); + Configuration configuration = expected.Configuration; for (int y = 0; y < actual.Height; y++) { Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer); + PixelOperations.Instance.ToRgba64(configuration, aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(configuration, bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 9563edbb5..be12f5621 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -74,14 +74,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison float totalDifference = 0F; var differences = new List(); + Configuration configuration = expected.Configuration; for (int y = 0; y < actual.Height; y++) { Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer); + PixelOperations.Instance.ToRgba64(configuration, aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(configuration, bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 2409ff9ad..3dd330e4d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -31,14 +31,22 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); - PixelOperations.Instance.FromRgba32Bytes(data, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba32Bytes( + configuration, + data, + resultPixels, + resultPixels.Length); } else if (magickImage.Depth == 16) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); - PixelOperations.Instance.FromRgba64Bytes(bytes, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba64Bytes( + configuration, + bytes, + resultPixels, + resultPixels.Length); } else { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index e96825db1..7e87c23db 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -33,7 +33,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs if (bmp.PixelFormat != PixelFormat.Format32bppArgb) { - throw new ArgumentException($"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", nameof(bmp)); + throw new ArgumentException( + $"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", + nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -43,6 +45,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = w * sizeof(Bgra32); var image = new Image(w, h); + Configuration configuration = image.GetConfiguration(); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { @@ -55,7 +58,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgra32(workBuffer.GetSpan().Slice(0, w), row); + PixelOperations.Instance.FromBgra32( + configuration, + workBuffer.GetSpan().Slice(0, w), + row); } } } @@ -79,7 +85,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs if (bmp.PixelFormat != PixelFormat.Format24bppRgb) { - throw new ArgumentException($"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", nameof(bmp)); + throw new ArgumentException( + $"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", + nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -89,6 +97,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = w * sizeof(Bgr24); var image = new Image(w, h); + Configuration configuration = image.GetConfiguration(); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { @@ -101,7 +110,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(0, w), row); + PixelOperations.Instance.FromBgr24( + configuration, + workBuffer.GetSpan().Slice(0, w), + row); } } } @@ -112,6 +124,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image image) where TPixel : struct, IPixel { + Configuration configuration = image.GetConfiguration(); int w = image.Width; int h = image.Height; @@ -130,7 +143,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan()); + PixelOperations.Instance.ToBgra32(configuration, row, workBuffer.GetSpan()); byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index f055ce548..29d39596b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -30,27 +30,29 @@ namespace SixLabors.ImageSharp.Tests { MemoryAllocator memoryAllocator = ctx.MemoryAllocator; - ctx.Apply(img => - { - using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) - { - Span tempSpan = temp.GetSpan(); - foreach (ImageFrame frame in img.Frames) + ctx.Apply( + img => { - Span pixelSpan = frame.GetPixelSpan(); + Configuration configuration = img.GetConfiguration(); + using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) + { + Span tempSpan = temp.GetSpan(); + foreach (ImageFrame frame in img.Frames) + { + Span pixelSpan = frame.GetPixelSpan(); - PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan); + PixelOperations.Instance.ToScaledVector4(configuration, pixelSpan, tempSpan); - for (int i = 0; i < tempSpan.Length; i++) - { - ref Vector4 v = ref tempSpan[i]; - v.W = 1F; - } + for (int i = 0; i < tempSpan.Length; i++) + { + ref Vector4 v = ref tempSpan[i]; + v.W = 1F; + } - PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan); - } - } - }); + PixelOperations.Instance.FromScaledVector4(configuration, tempSpan, pixelSpan); + } + } + }); } public static Image DebugSave( diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index e6a5ffc84..d7755ff7a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -80,8 +80,11 @@ namespace SixLabors.ImageSharp.Tests } else { - rgb1 = ca.ToRgba32().Rgb; - rgb2 = cb.ToRgba32().Rgb; + Rgba32 rgba = default; + ca.ToRgba32(ref rgba); + rgb1 = rgba.Rgb; + cb.ToRgba32(ref rgba); + rgb2 = rgba.Rgb; if (!rgb1.Equals(rgb2)) { diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 1d284af15..a8140e39d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -275,11 +275,12 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(20, img.Height); Buffer2D pixels = img.GetRootFramePixelBuffer(); + Rgba32 rgba = default; for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) { - var rgba = pixels[x, y].ToRgba32(); + pixels[x, y].ToRgba32(ref rgba); Assert.Equal(255, rgba.R); Assert.Equal(100, rgba.G);