diff --git a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs index 5ae4629137..bbd454fbe8 100644 --- a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs @@ -30,9 +30,7 @@ public static void Expand(Span vectors) for (int i = 0; i < vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - v.X = Expand(v.X); - v.Y = Expand(v.Y); - v.Z = Expand(v.Z); + Expand(ref v); } } @@ -48,9 +46,7 @@ public static void Compress(Span vectors) for (int i = 0; i < vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - v.X = Compress(v.X); - v.Y = Compress(v.Y); - v.Z = Compress(v.Z); + Compress(ref v); } } @@ -58,17 +54,25 @@ public static void Compress(Span vectors) /// Expands a companded vector to its linear equivalent with respect to the energy. /// /// The vector. - /// The representing the linear channel values. [MethodImpl(InliningOptions.ShortMethod)] - public static Vector4 Expand(Vector4 vector) => new Vector4(Expand(vector.X), Expand(vector.Y), Expand(vector.Z), vector.W); + public static void Expand(ref Vector4 vector) + { + vector.X = Expand(vector.X); + vector.Y = Expand(vector.Y); + vector.Z = Expand(vector.Z); + } /// /// Compresses an uncompanded vector (linear) to its nonlinear equivalent. /// /// The vector. - /// The representing the nonlinear channel values. [MethodImpl(InliningOptions.ShortMethod)] - public static Vector4 Compress(Vector4 vector) => new Vector4(Compress(vector.X), Compress(vector.Y), Compress(vector.Z), vector.W); + public static void Compress(ref Vector4 vector) + { + vector.X = Compress(vector.X); + vector.Y = Compress(vector.Y); + vector.Z = Compress(vector.Z); + } /// /// Expands a companded channel to its linear equivalent with respect to the energy. diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index d8cf69a52e..3accea2949 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -278,20 +278,14 @@ public static void MustBeSizedAtLeast(Span source, int minLength, string p [MethodImpl(InliningOptions.ColdPath)] private static void ThrowArgumentException(string message, string parameterName) - { - throw new ArgumentException(message, parameterName); - } + => throw new ArgumentException(message, parameterName); [MethodImpl(InliningOptions.ColdPath)] private static void ThrowArgumentOutOfRangeException(string parameterName, string message) - { - throw new ArgumentOutOfRangeException(parameterName, message); - } + => throw new ArgumentOutOfRangeException(parameterName, message); [MethodImpl(InliningOptions.ColdPath)] private static void ThrowArgumentNullException(string parameterName) - { - throw new ArgumentNullException(parameterName); - } + => throw new ArgumentNullException(parameterName); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 2ec965dfb0..aa39333c10 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -44,25 +44,49 @@ internal override void ToArgb32(Configuration configuration, ReadOnlySpan internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + Vector4Converters.RgbaCompatible.FromScaledVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + Vector4Converters.RgbaCompatible.ToScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 711a9d1c16..5adf8418e1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -44,25 +44,49 @@ internal override void ToBgr24(Configuration configuration, ReadOnlySpan /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + Vector4Converters.RgbaCompatible.FromScaledVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + Vector4Converters.RgbaCompatible.ToScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index b669dd5348..d1490e5341 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -44,25 +44,49 @@ internal override void ToBgra32(Configuration configuration, ReadOnlySpan internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + Vector4Converters.RgbaCompatible.FromScaledVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + Vector4Converters.RgbaCompatible.ToScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index dbf3102c4a..0cf3a2a200 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -44,25 +44,49 @@ internal override void ToRgb24(Configuration configuration, ReadOnlySpan /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + Vector4Converters.RgbaCompatible.FromScaledVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + Vector4Converters.RgbaCompatible.ToScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index f0675cb5b3..8fc5ef89d7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -113,25 +113,49 @@ using System.Runtime.InteropServices; /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + Vector4Converters.RgbaCompatible.FromScaledVector4(configuration, this, sourceVectors, destPixels); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + Vector4Converters.RgbaCompatible.ToScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedScaledVector4(configuration, this, sourcePixels, destVectors); + } + + /// + internal override void ToCompandedPremultipliedScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToCompandedPremultipliedScaledVector4(configuration, this, sourcePixels, destVectors); } <#+ diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 004b25cd33..4dd6adf3d2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -4,7 +4,7 @@ using System; using System.Numerics; using System.Runtime.InteropServices; -using SixLabors.Memory; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.PixelFormats { @@ -51,19 +51,55 @@ internal override void FromVector4( /// internal override void ToScaledVector4( Configuration configuration, - ReadOnlySpan sourceColors, - Span destinationVectors) - { - this.ToVector4(configuration, sourceColors, destinationVectors); - } + ReadOnlySpan sourcePixels, + Span destVectors) => this.ToVector4(configuration, sourcePixels, destVectors); /// internal override void FromScaledVector4( Configuration configuration, ReadOnlySpan sourceVectors, - Span destinationColors) + Span destPixels) => this.FromVector4(configuration, sourceVectors, destPixels); + + /// + internal override void ToPremultipliedVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) { - this.FromVector4(configuration, sourceVectors, destinationColors); + this.ToVector4(configuration, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + Vector4Utils.Premultiply(destVectors); + } + + /// + internal override void ToPremultipliedScaledVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) => this.ToPremultipliedVector4(configuration, sourcePixels, destVectors); + + /// + internal override void ToCompandedScaledVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + this.ToVector4(configuration, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + SRgbCompanding.Expand(destVectors); + } + + /// + internal override void ToCompandedPremultipliedScaledVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + this.ToCompandedScaledVector4(configuration, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + Vector4Utils.Premultiply(destVectors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index bffaf57ddd..36917bf4f4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.PixelFormats { @@ -45,6 +46,42 @@ internal override void ToVector4( MemoryMarshal.Cast(sourcePixels).CopyTo(destVectors); } + + /// + internal override void ToPremultipliedVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + this.ToVector4(configuration, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + Vector4Utils.Premultiply(destVectors); + } + + /// + internal override void ToCompandedScaledVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + this.ToVector4(configuration, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + SRgbCompanding.Expand(destVectors); + } + + /// + internal override void ToCompandedPremultipliedScaledVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + this.ToCompandedScaledVector4(configuration, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + Vector4Utils.Premultiply(destVectors); + } } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 115dd7a43d..337a43d6d6 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -61,33 +60,169 @@ internal virtual void ToVector4( /// /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. + /// The to the destination colors. internal virtual void FromScaledVector4( Configuration configuration, ReadOnlySpan sourceVectors, - Span destinationColors) + Span destPixels) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - Utils.Vector4Converters.Default.DangerousFromScaledVector4(sourceVectors, destinationColors); + Utils.Vector4Converters.Default.DangerousFromScaledVector4(sourceVectors, destPixels); } /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// A to configure internal operations - /// The to the source colors. - /// The to the destination vectors. + /// The to the source colors. + /// The to the destination vectors. internal virtual void ToScaledVector4( Configuration configuration, - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan sourcePixels, + Span destVectors) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + Utils.Vector4Converters.Default.DangerousToScaledVector4(sourcePixels, destVectors); + } + + /// + /// Bulk version of converting alpha premultiplied 'sourceVectors.Length' pixels into 'destinationColors'. + /// + /// A to configure internal operations + /// The to the source vectors. + /// The to the destination colors. + internal virtual void FromPremultipliedVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + Utils.Vector4Converters.Default.DangerousFromPremultipliedVector4(sourceVectors, destPixels); + } + + /// + /// Bulk version of converting 'sourceColors.Length' pixels into alpha premultiplied 'destinationVectors'. + /// + /// A to configure internal operations + /// The to the source colors. + /// The to the destination vectors. + internal virtual void ToPremultipliedVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + Utils.Vector4Converters.Default.DangerousToPremultipliedVector4(sourcePixels, destVectors); + } + + /// + /// Bulk version of converting alpha premultiplied 'sourceVectors.Length' pixels into 'destinationColors'. + /// + /// A to configure internal operations + /// The to the source vectors. + /// The to the destination colors. + internal virtual void FromPremultipliedScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + Utils.Vector4Converters.Default.DangerousFromPremultipliedScaledVector4(sourceVectors, destPixels); + } + + /// + /// Bulk version of converting 'sourceColors.Length' pixels into alpha premultiplied 'destinationVectors'. + /// + /// A to configure internal operations + /// The to the source colors. + /// The to the destination vectors. + internal virtual void ToPremultipliedScaledVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + Utils.Vector4Converters.Default.DangerousToPremultipliedScaledVector4(sourcePixels, destVectors); + } + + /// + /// Bulk version of converting companded 'sourceVectors.Length' pixels into 'destinationColors'. + /// + /// A to configure internal operations + /// The to the source vectors. + /// The to the destination colors. + internal virtual void FromCompandedScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + Utils.Vector4Converters.Default.DangerousFromCompandedScaledVector4(sourceVectors, destPixels); + } + + /// + /// Bulk version of converting 'sourceColors.Length' pixels into companded 'destinationVectors'. + /// + /// A to configure internal operations + /// The to the source colors. + /// The to the destination vectors. + internal virtual void ToCompandedScaledVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + Utils.Vector4Converters.Default.DangerousToCompandedScaledVector4(sourcePixels, destVectors); + } + + /// + /// Bulk version of converting companded, alpha premultiplied 'sourceVectors.Length' pixels into 'destinationColors'. + /// + /// A to configure internal operations + /// The to the source vectors. + /// The to the destination colors. + internal virtual void FromCompandedPremultipliedScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + Utils.Vector4Converters.Default.DangerousFromCompandedPremultipliedScaledVector4(sourceVectors, destPixels); + } + + /// + /// Bulk version of converting 'sourceColors.Length' pixels into companded, alpha premultiplied 'destinationVectors'. + /// + /// A to configure internal operations + /// The to the source colors. + /// The to the destination vectors. + internal virtual void ToCompandedPremultipliedScaledVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - Utils.Vector4Converters.Default.DangerousToScaledVector4(sourceColors, destinationVectors); + Utils.Vector4Converters.Default.DangerousToCompandedPremultipliedScaledVector4(sourcePixels, destVectors); } /// diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs index e784e3b5a6..500799936a 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.PixelFormats.Utils { @@ -54,6 +55,43 @@ internal static void DangerousToVector4( } } + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromPremultipliedVector4( + 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++) + { + Vector4 sp = Unsafe.Add(ref sourceRef, i); + Vector4Utils.UnPremultiply(ref sp); + + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToPremultipliedVector4( + 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(); + Vector4Utils.Premultiply(ref dp); + } + } + [MethodImpl(InliningOptions.ShortMethod)] internal static void DangerousFromScaledVector4( ReadOnlySpan sourceVectors, @@ -87,6 +125,122 @@ internal static void DangerousToScaledVector4( dp = sp.ToScaledVector4(); } } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromPremultipliedScaledVector4( + 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++) + { + Vector4 sp = Unsafe.Add(ref sourceRef, i); + Vector4Utils.UnPremultiply(ref sp); + + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromScaledVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToPremultipliedScaledVector4( + 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(); + Vector4Utils.Premultiply(ref dp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromCompandedScaledVector4( + 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++) + { + Vector4 sp = Unsafe.Add(ref sourceRef, i); + SRgbCompanding.Compress(ref sp); + + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromScaledVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToCompandedScaledVector4( + 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.ToScaledVector4(); + SRgbCompanding.Expand(ref dp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromCompandedPremultipliedScaledVector4( + 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++) + { + Vector4 sp = Unsafe.Add(ref sourceRef, i); + Vector4Utils.UnPremultiply(ref sp); + SRgbCompanding.Compress(ref sp); + + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromScaledVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToCompandedPremultipliedScaledVector4( + 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(); + SRgbCompanding.Expand(ref dp); + Vector4Utils.Premultiply(ref dp); + } + } } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index 06c33d79c7..2fd1c043a8 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -6,6 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.PixelFormats.Utils { @@ -30,13 +31,146 @@ public static class RgbaCompatible /// /// 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) + where TPixel : struct, IPixel + => ToVector4Impl(configuration, pixelOperations, sourcePixels, destVectors, false); + + /// + /// Provides an efficient default implementation for + /// 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) + where TPixel : struct, IPixel + => FromVector4Impl(configuration, pixelOperations, sourceVectors, destPixels, false); + + /// + /// Provides an efficient default implementation for + /// 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 ToScaledVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + => ToVector4Impl(configuration, pixelOperations, sourcePixels, destVectors, true); + + /// + /// Provides an efficient default implementation for + /// 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 FromScaledVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourceVectors, + Span destPixels) + where TPixel : struct, IPixel + => FromVector4Impl(configuration, pixelOperations, sourceVectors, destPixels, true); + + /// + /// Provides an efficient default implementation for converting pixels into alpha premultiplied destination vectors. + /// 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 ToPremultipliedVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + { + ToVector4(configuration, pixelOperations, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + Vector4Utils.Premultiply(destVectors); + } + + /// + /// Provides an efficient default implementation for converting pixels into alpha premultiplied, scaled destination vectors. + /// 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 ToPremultipliedScaledVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + { + ToScaledVector4(configuration, pixelOperations, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + Vector4Utils.Premultiply(destVectors); + } + + /// + /// Provides an efficient default implementation for converting pixels into companded, scaled destination vectors. + /// 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 ToCompandedScaledVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + { + ToScaledVector4(configuration, pixelOperations, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + SRgbCompanding.Expand(destVectors); + } + + /// + /// Provides an efficient default implementation for converting pixels into alpha premultiplied, scaled destination vectors. + /// 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 ToCompandedPremultipliedScaledVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + { + ToCompandedScaledVector4(configuration, pixelOperations, sourcePixels, destVectors); + + // TODO: Investigate optimized 1-pass approach. + Vector4Utils.Premultiply(destVectors); + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static void ToVector4Impl( Configuration configuration, PixelOperations pixelOperations, ReadOnlySpan sourcePixels, @@ -72,15 +206,8 @@ internal static void ToVector4( 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( + internal static void FromVector4Impl( Configuration configuration, PixelOperations pixelOperations, ReadOnlySpan sourceVectors, diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 189e21de7a..e0ab6f0dd3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -9,7 +9,6 @@ using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; @@ -257,21 +256,21 @@ protected override void OnFrameApply(ImageFrame source, ImageFrame sourceRow = source.GetPixelRowSpan(y).Slice(sourceX); Span tempRowSpan = tempRowBuffer.Span.Slice(sourceX); - PixelOperations.Instance.ToVector4(configuration, sourceRow, tempRowSpan); - Vector4Utils.Premultiply(tempRowSpan); - - ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; - if (this.Compand) { - SRgbCompanding.Expand(tempRowSpan); + PixelOperations.Instance.ToCompandedPremultipliedScaledVector4(configuration, sourceRow, tempRowSpan); } + else + { + PixelOperations.Instance.ToPremultipliedVector4(configuration, sourceRow, tempRowSpan); + } + + ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; for (int x = minX; x < maxX; x++) { ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - startX); - Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - kernel.Convolve(tempRowSpan); + Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = kernel.Convolve(tempRowSpan); } } }); @@ -301,15 +300,16 @@ protected override void OnFrameApply(ImageFrame source, ImageFrame targetRowSpan = destination.GetPixelRowSpan(y); if (this.Compand) { - SRgbCompanding.Compress(tempRowSpan); + PixelOperations.Instance.FromCompandedPremultipliedScaledVector4(configuration, tempRowSpan, targetRowSpan); + } + else + { + PixelOperations.Instance.FromPremultipliedVector4(configuration, tempRowSpan, targetRowSpan); } - - Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.FromVector4(configuration, tempRowSpan, targetRowSpan); } }); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index fe112042ef..618832cc61 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -35,8 +35,8 @@ public class ShortClr : Benchmarks.Config public ShortClr() { this.Add( - //Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3), - Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3) + //Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3), + Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3) ); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index 446c038596..145528ae66 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -38,7 +38,7 @@ public class ShortClr : Benchmarks.Config public ShortClr() { this.Add( - Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithTargetCount(2) + Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithIterationCount(2) ); } } diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index b467579425..8c36d32387 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -22,9 +22,8 @@ public class ShortClr : Config public ShortClr() { this.Add( - Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithTargetCount(3), - Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithTargetCount(3) - ); + Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), + Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3)); } } } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index 148b253281..58c330e3c2 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -14,11 +14,12 @@ namespace SixLabors.ImageSharp.Benchmarks { [Config(typeof(Config.ShortClr))] - public abstract class ResizeBenchmarkBase + public abstract class ResizeBenchmarkBase + where TPixel : struct, IPixel { protected readonly Configuration Configuration = new Configuration(new JpegConfigurationModule()); - private Image sourceImage; + private Image sourceImage; private Bitmap sourceBitmap; @@ -31,7 +32,7 @@ public abstract class ResizeBenchmarkBase [GlobalSetup] public void Setup() { - this.sourceImage = new Image(this.Configuration, this.SourceSize, this.SourceSize); + this.sourceImage = new Image(this.Configuration, this.SourceSize, this.SourceSize); this.sourceBitmap = new Bitmap(this.SourceSize, this.SourceSize); } @@ -65,26 +66,29 @@ public int SystemDrawing() [Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 1")] public int ImageSharp_P1() => this.RunImageSharpResize(1); - [Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 4")] - public int ImageSharp_P4() => this.RunImageSharpResize(4); + // Parallel cases have been disabled for fast benchmark execution. + // Uncomment, if you are interested in parallel speedup - [Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 8")] - public int ImageSharp_P8() => this.RunImageSharpResize(8); + //[Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 4")] + //public int ImageSharp_P4() => this.RunImageSharpResize(4); + + //[Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 8")] + //public int ImageSharp_P8() => this.RunImageSharpResize(8); protected int RunImageSharpResize(int maxDegreeOfParallelism) { this.Configuration.MaxDegreeOfParallelism = maxDegreeOfParallelism; - using (Image clone = this.sourceImage.Clone(this.ExecuteResizeOperation)) + using (Image clone = this.sourceImage.Clone(this.ExecuteResizeOperation)) { return clone.Width; } } - protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx); + protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx); } - - public class Resize_Bicubic : ResizeBenchmarkBase + + public class Resize_Bicubic_Rgba32 : ResizeBenchmarkBase { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { @@ -115,7 +119,15 @@ protected override void ExecuteResizeOperation(IImageProcessingContext c } - public class Resize_BicubicCompand : ResizeBenchmarkBase + public class Resize_Bicubic_Bgra32 : ResizeBenchmarkBase + { + protected override void ExecuteResizeOperation(IImageProcessingContext ctx) + { + ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); + } + } + + public class Resize_BicubicCompand_Rgba32 : ResizeBenchmarkBase { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { diff --git a/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs b/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs index 91cacfe3f0..b2ee030483 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs @@ -53,7 +53,15 @@ public void SRgbCompanding_Expand_VectorSpan(int length) { var rnd = new Random(42); Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => SRgbCompanding.Expand(v)).ToArray(); + var expected = new Vector4[source.Length]; + + for (int i = 0; i < source.Length; i++) + { + Vector4 s = source[i]; + ref Vector4 e = ref expected[i]; + SRgbCompanding.Expand(ref s); + e = s; + } SRgbCompanding.Expand(source); @@ -68,7 +76,15 @@ public void SRgbCompanding_Compress_VectorSpan(int length) { var rnd = new Random(42); Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => SRgbCompanding.Compress(v)).ToArray(); + var expected = new Vector4[source.Length]; + + for (int i = 0; i < source.Length; i++) + { + Vector4 s = source[i]; + ref Vector4 e = ref expected[i]; + SRgbCompanding.Compress(ref s); + e = s; + } SRgbCompanding.Compress(source); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb24OperationsTests.cs new file mode 100644 index 0000000000..a2b711576e --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb24OperationsTests.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 Rgb24OperationsTests : PixelOperationsTests + { + public Rgb24OperationsTests(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.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index d9845e4741..f105876c93 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - +using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -70,25 +70,33 @@ protected PixelOperationsTests(ITestOutputHelper output) internal static PixelOperations Operations => PixelOperations.Instance; - internal static TPixel[] CreateExpectedPixelData(Vector4[] source) + internal static TPixel[] CreateExpectedPixelData(Vector4[] source, RefAction vectorModifier = null) { var expected = new TPixel[source.Length]; for (int i = 0; i < expected.Length; i++) { - expected[i].FromVector4(source[i]); + Vector4 v = source[i]; + vectorModifier?.Invoke(ref v); + + expected[i].FromVector4(v); } + return expected; } - internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) + internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source, RefAction vectorModifier = null) { var expected = new TPixel[source.Length]; for (int i = 0; i < expected.Length; i++) { - expected[i].FromScaledVector4(source[i]); + Vector4 v = source[i]; + vectorModifier?.Invoke(ref v); + + expected[i].FromScaledVector4(v); } + return expected; } @@ -120,6 +128,104 @@ public void FromScaledVector4(int count) ); } + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromCompandedScaledVector4(int count) + { + void sourceAction(ref Vector4 v) + { + SRgbCompanding.Expand(ref v); + } + + void expectedAction(ref Vector4 v) + { + SRgbCompanding.Compress(ref v); + } + + Vector4[] source = CreateVector4TestData(count, (ref Vector4 v) => sourceAction(ref v)); + TPixel[] expected = CreateScaledExpectedPixelData(source, (ref Vector4 v) => expectedAction(ref v)); + + TestOperation( + source, + expected, + (s, d) => Operations.FromCompandedScaledVector4(this.Configuration, s, d.GetSpan()) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromPremultipliedVector4(int count) + { + void sourceAction(ref Vector4 v) + { + Vector4Utils.Premultiply(ref v); + } + + void expectedAction(ref Vector4 v) + { + Vector4Utils.UnPremultiply(ref v); + } + + Vector4[] source = CreateVector4TestData(count, (ref Vector4 v) => sourceAction(ref v)); + TPixel[] expected = CreateExpectedPixelData(source, (ref Vector4 v) => expectedAction(ref v)); + + TestOperation( + source, + expected, + (s, d) => Operations.FromPremultipliedVector4(this.Configuration, s, d.GetSpan()) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromPremultipliedScaledVector4(int count) + { + void sourceAction(ref Vector4 v) + { + Vector4Utils.Premultiply(ref v); + } + + void expectedAction(ref Vector4 v) + { + Vector4Utils.UnPremultiply(ref v); + } + + Vector4[] source = CreateVector4TestData(count, (ref Vector4 v) => sourceAction(ref v)); + TPixel[] expected = CreateScaledExpectedPixelData(source, (ref Vector4 v) => expectedAction(ref v)); + + TestOperation( + source, + expected, + (s, d) => Operations.FromPremultipliedScaledVector4(this.Configuration, s, d.GetSpan()) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromCompandedPremultipliedScaledVector4(int count) + { + void sourceAction(ref Vector4 v) + { + SRgbCompanding.Expand(ref v); + Vector4Utils.Premultiply(ref v); + } + + void expectedAction(ref Vector4 v) + { + Vector4Utils.UnPremultiply(ref v); + SRgbCompanding.Compress(ref v); + } + + Vector4[] source = CreateVector4TestData(count, (ref Vector4 v) => sourceAction(ref v)); + TPixel[] expected = CreateScaledExpectedPixelData(source, (ref Vector4 v) => expectedAction(ref v)); + + TestOperation( + source, + expected, + (s, d) => Operations.FromCompandedPremultipliedScaledVector4(this.Configuration, s, d.GetSpan()) + ); + } + [Theory] [MemberData(nameof(ArraySizesData))] public void ToVector4(int count) @@ -148,6 +254,104 @@ public void ToScaledVector4(int count) ); } + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToCompandedScaledVector4(int count) + { + void sourceAction(ref Vector4 v) + { + SRgbCompanding.Compress(ref v); + } + + void expectedAction(ref Vector4 v) + { + SRgbCompanding.Expand(ref v); + } + + TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => sourceAction(ref v)); + Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => expectedAction(ref v)); + + TestOperation( + source, + expected, + (s, d) => Operations.ToCompandedScaledVector4(this.Configuration, s, d.GetSpan()) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToPremultipliedVector4(int count) + { + void sourceAction(ref Vector4 v) + { + Vector4Utils.UnPremultiply(ref v); + } + + void expectedAction(ref Vector4 v) + { + Vector4Utils.Premultiply(ref v); + } + + TPixel[] source = CreatePixelTestData(count, (ref Vector4 v) => sourceAction(ref v)); + Vector4[] expected = CreateExpectedVector4Data(source, (ref Vector4 v) => expectedAction(ref v)); + + TestOperation( + source, + expected, + (s, d) => Operations.ToPremultipliedVector4(this.Configuration, s, d.GetSpan()) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToPremultipliedScaledVector4(int count) + { + void sourceAction(ref Vector4 v) + { + Vector4Utils.UnPremultiply(ref v); + } + + void expectedAction(ref Vector4 v) + { + Vector4Utils.Premultiply(ref v); + } + + TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => sourceAction(ref v)); + Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => expectedAction(ref v)); + + TestOperation( + source, + expected, + (s, d) => Operations.ToPremultipliedScaledVector4(this.Configuration, s, d.GetSpan()) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToCompandedPremultipliedScaledVector4(int count) + { + void sourceAction(ref Vector4 v) + { + Vector4Utils.UnPremultiply(ref v); + SRgbCompanding.Compress(ref v); + } + + void expectedAction(ref Vector4 v) + { + SRgbCompanding.Expand(ref v); + Vector4Utils.Premultiply(ref v); + } + + TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => sourceAction(ref v)); + Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => expectedAction(ref v)); + + TestOperation( + source, + expected, + (s, d) => Operations.ToCompandedPremultipliedScaledVector4(this.Configuration, s, d.GetSpan()) + ); + } + [Theory] [MemberData(nameof(ArraySizesData))] public void FromArgb32Bytes(int count) @@ -477,25 +681,37 @@ public void ToRgba64Bytes(int count) ); } - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) + public delegate void RefAction(ref T1 arg1); + + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source, RefAction vectorModifier = null) { var expected = new Vector4[source.Length]; for (int i = 0; i < expected.Length; i++) { - expected[i] = source[i].ToVector4(); + var v = source[i].ToVector4(); + + vectorModifier?.Invoke(ref v); + + expected[i] = v; } + return expected; } - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source, RefAction vectorModifier = null) { var expected = new Vector4[source.Length]; for (int i = 0; i < expected.Length; i++) { - expected[i] = source[i].ToScaledVector4(); + Vector4 v = source[i].ToScaledVector4(); + + vectorModifier?.Invoke(ref v); + + expected[i] = v; } + return expected; } @@ -513,19 +729,22 @@ internal static void TestOperation( } } - internal static Vector4[] CreateVector4TestData(int length) + internal static Vector4[] CreateVector4TestData(int length, RefAction vectorModifier = null) { var result = new Vector4[length]; var rnd = new Random(42); // Deterministic random values for (int i = 0; i < result.Length; i++) { - result[i] = GetVector(rnd); + Vector4 v = GetVector(rnd); + vectorModifier?.Invoke(ref v); + + result[i] = v; } return result; } - internal static TPixel[] CreatePixelTestData(int length) + internal static TPixel[] CreatePixelTestData(int length, RefAction vectorModifier = null) { var result = new TPixel[length]; @@ -534,13 +753,16 @@ internal static TPixel[] CreatePixelTestData(int length) for (int i = 0; i < result.Length; i++) { Vector4 v = GetVector(rnd); + + vectorModifier?.Invoke(ref v); + result[i].FromVector4(v); } return result; } - internal static TPixel[] CreateScaledPixelTestData(int length) + internal static TPixel[] CreateScaledPixelTestData(int length, RefAction vectorModifier = null) { var result = new TPixel[length]; @@ -549,6 +771,9 @@ internal static TPixel[] CreateScaledPixelTestData(int length) for (int i = 0; i < result.Length; i++) { Vector4 v = GetVector(rnd); + + vectorModifier?.Invoke(ref v); + result[i].FromScaledVector4(v); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs index 3c562057a8..3d161c389c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs @@ -1,48 +1,48 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Collections.Generic; -using System.Text; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.PixelFormats.PixelBlenders; -using SixLabors.ImageSharp.Tests.TestUtilities; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public class PixelBlenderTests +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Text; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.PixelBlenders; +using SixLabors.ImageSharp.Tests.TestUtilities; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class PixelBlenderTests { - public static TheoryData BlenderMappings = new TheoryData() - { - { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOver), PixelColorBlendingMode.Normal }, - { new TestPixel(), typeof(DefaultPixelBlenders.ScreenSrcOver), PixelColorBlendingMode.Screen }, - { new TestPixel(), typeof(DefaultPixelBlenders.HardLightSrcOver), PixelColorBlendingMode.HardLight }, - { new TestPixel(), typeof(DefaultPixelBlenders.OverlaySrcOver), PixelColorBlendingMode.Overlay }, - { new TestPixel(), typeof(DefaultPixelBlenders.DarkenSrcOver), PixelColorBlendingMode.Darken }, - { new TestPixel(), typeof(DefaultPixelBlenders.LightenSrcOver), PixelColorBlendingMode.Lighten }, - { new TestPixel(), typeof(DefaultPixelBlenders.AddSrcOver), PixelColorBlendingMode.Add }, - { new TestPixel(), typeof(DefaultPixelBlenders.SubtractSrcOver), PixelColorBlendingMode.Subtract }, - { new TestPixel(), typeof(DefaultPixelBlenders.MultiplySrcOver), PixelColorBlendingMode.Multiply }, - - { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOver), PixelColorBlendingMode.Normal }, - { new TestPixel(), typeof(DefaultPixelBlenders.ScreenSrcOver), PixelColorBlendingMode.Screen }, - { new TestPixel(), typeof(DefaultPixelBlenders.HardLightSrcOver), PixelColorBlendingMode.HardLight }, - { new TestPixel(), typeof(DefaultPixelBlenders.OverlaySrcOver), PixelColorBlendingMode.Overlay }, - { new TestPixel(), typeof(DefaultPixelBlenders.DarkenSrcOver), PixelColorBlendingMode.Darken }, - { new TestPixel(), typeof(DefaultPixelBlenders.LightenSrcOver), PixelColorBlendingMode.Lighten }, - { new TestPixel(), typeof(DefaultPixelBlenders.AddSrcOver), PixelColorBlendingMode.Add }, - { new TestPixel(), typeof(DefaultPixelBlenders.SubtractSrcOver), PixelColorBlendingMode.Subtract }, - { new TestPixel(), typeof(DefaultPixelBlenders.MultiplySrcOver), PixelColorBlendingMode.Multiply }, - }; - - [Theory] - [MemberData(nameof(BlenderMappings))] - public void ReturnsCorrectBlender(TestPixel pixel, Type type, PixelColorBlendingMode mode) - where TPixel : struct, IPixel - { - PixelBlender blender = PixelOperations.Instance.GetPixelBlender(mode, PixelAlphaCompositionMode.SrcOver); - Assert.IsType(type, blender); + public static TheoryData BlenderMappings = new TheoryData() + { + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOver), PixelColorBlendingMode.Normal }, + { new TestPixel(), typeof(DefaultPixelBlenders.ScreenSrcOver), PixelColorBlendingMode.Screen }, + { new TestPixel(), typeof(DefaultPixelBlenders.HardLightSrcOver), PixelColorBlendingMode.HardLight }, + { new TestPixel(), typeof(DefaultPixelBlenders.OverlaySrcOver), PixelColorBlendingMode.Overlay }, + { new TestPixel(), typeof(DefaultPixelBlenders.DarkenSrcOver), PixelColorBlendingMode.Darken }, + { new TestPixel(), typeof(DefaultPixelBlenders.LightenSrcOver), PixelColorBlendingMode.Lighten }, + { new TestPixel(), typeof(DefaultPixelBlenders.AddSrcOver), PixelColorBlendingMode.Add }, + { new TestPixel(), typeof(DefaultPixelBlenders.SubtractSrcOver), PixelColorBlendingMode.Subtract }, + { new TestPixel(), typeof(DefaultPixelBlenders.MultiplySrcOver), PixelColorBlendingMode.Multiply }, + + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOver), PixelColorBlendingMode.Normal }, + { new TestPixel(), typeof(DefaultPixelBlenders.ScreenSrcOver), PixelColorBlendingMode.Screen }, + { new TestPixel(), typeof(DefaultPixelBlenders.HardLightSrcOver), PixelColorBlendingMode.HardLight }, + { new TestPixel(), typeof(DefaultPixelBlenders.OverlaySrcOver), PixelColorBlendingMode.Overlay }, + { new TestPixel(), typeof(DefaultPixelBlenders.DarkenSrcOver), PixelColorBlendingMode.Darken }, + { new TestPixel(), typeof(DefaultPixelBlenders.LightenSrcOver), PixelColorBlendingMode.Lighten }, + { new TestPixel(), typeof(DefaultPixelBlenders.AddSrcOver), PixelColorBlendingMode.Add }, + { new TestPixel(), typeof(DefaultPixelBlenders.SubtractSrcOver), PixelColorBlendingMode.Subtract }, + { new TestPixel(), typeof(DefaultPixelBlenders.MultiplySrcOver), PixelColorBlendingMode.Multiply }, + }; + + [Theory] + [MemberData(nameof(BlenderMappings))] + public void ReturnsCorrectBlender(TestPixel pixel, Type type, PixelColorBlendingMode mode) + where TPixel : struct, IPixel + { + PixelBlender blender = PixelOperations.Instance.GetPixelBlender(mode, PixelAlphaCompositionMode.SrcOver); + Assert.IsType(type, blender); } public static TheoryData ColorBlendingExpectedResults = new TheoryData() @@ -59,7 +59,7 @@ public void ReturnsCorrectBlender(TestPixel pixel, Type type, Pi }; - [Theory] + [Theory] [MemberData(nameof(ColorBlendingExpectedResults))] public void TestColorBlendingModes(Rgba32 backdrop, Rgba32 source, float opacity, PixelColorBlendingMode mode, Rgba32 expectedResult) { @@ -88,7 +88,7 @@ public void TestColorBlendingModes(Rgba32 backdrop, Rgba32 source, float opacity { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.SrcOver, Rgba32.MidnightBlue }, }; - [Theory] + [Theory] [MemberData(nameof(AlphaCompositionExpectedResults))] public void TestAlphaCompositionModes(Rgba32 backdrop, Rgba32 source, float opacity, PixelAlphaCompositionMode mode, Rgba32 expectedResult) { @@ -99,6 +99,6 @@ public void TestAlphaCompositionModes(Rgba32 backdrop, Rgba32 source, float opac // var str = actualResult.Rgba.ToString("X8"); // used to extract expectedResults Assert.Equal(actualResult.ToVector4(), expectedResult.ToVector4()); - } - } -} + } + } +} diff --git a/tests/Images/External b/tests/Images/External index c4098e463a..9d71985545 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit c4098e463ab0e7128ae196b7f963369271df8fd3 +Subproject commit 9d71985545bb827270ca34af3f78e4c220560ef1