From 7617b38fec1246c664c172cc3e5cd2468fd86535 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 07:39:28 +0300 Subject: [PATCH 01/25] Base implementation for new converters --- ...egColorConverter.Avx2JpegColorConverter.cs | 18 --- ...gColorConverter.BasicJpegColorConverter.cs | 18 --- ...2.cs => JpegColorConverter.FromCmykAvx.cs} | 28 ++--- ...s => JpegColorConverter.FromCmykScalar.cs} | 9 +- .../JpegColorConverter.FromCmykVector8.cs | 25 ++--- ...=> JpegColorConverter.FromGrayScaleAvx.cs} | 22 ++-- .../JpegColorConverter.FromGrayScaleBasic.cs | 53 --------- .../JpegColorConverter.FromGrayScaleScalar.cs | 34 ++++++ ...JpegColorConverter.FromGrayScaleVector8.cs | 38 +++++++ ...x2.cs => JpegColorConverter.FromRgbAvx.cs} | 28 ++--- .../JpegColorConverter.FromRgbBasic.cs | 32 ------ .../JpegColorConverter.FromRgbScalar.cs | 26 +++++ .../JpegColorConverter.FromRgbVector8.cs | 11 +- ....cs => JpegColorConverter.FromYCbCrAvx.cs} | 33 ++---- .../JpegColorConverter.FromYCbCrBasic.cs | 42 ------- .../JpegColorConverter.FromYCbCrScalar.cs | 50 +++++++++ .../JpegColorConverter.FromYCbCrVector4.cs | 88 --------------- .../JpegColorConverter.FromYCbCrVector8.cs | 22 ++-- ...2.cs => JpegColorConverter.FromYccKAvx.cs} | 30 ++--- ...s => JpegColorConverter.FromYccKScalar.cs} | 13 +-- .../JpegColorConverter.FromYccKVector8.cs | 28 +++-- ...olorConverter.Vector8JpegColorConverter.cs | 18 --- .../ColorConverters/JpegColorConverterAvx.cs | 32 ++++++ ...Converter.cs => JpegColorConverterBase.cs} | 104 +++++++++--------- .../JpegColorConverterScalar.cs | 22 ++++ ...nverter.cs => JpegColorConverterVector.cs} | 27 +++-- .../Components/Decoder/SpectralConverter.cs | 2 +- .../Decoder/SpectralConverter{TPixel}.cs | 4 +- .../Decompressors/RgbJpegSpectralConverter.cs | 2 +- .../ColorConversion/CmykColorConversion.cs | 12 +- .../GrayscaleColorConversion.cs | 8 +- .../ColorConversion/RgbColorConversion.cs | 12 +- .../ColorConversion/YCbCrColorConversion.cs | 16 +-- .../ColorConversion/YccKColorConverter.cs | 12 +- .../Formats/Jpg/JpegColorConverterTests.cs | 76 +++++-------- 35 files changed, 432 insertions(+), 563 deletions(-) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromCmykAvx2.cs => JpegColorConverter.FromCmykAvx.cs} (58%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromCmykBasic.cs => JpegColorConverter.FromCmykScalar.cs} (83%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromGrayScaleAvx2.cs => JpegColorConverter.FromGrayScaleAvx.cs} (62%) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromRgbAvx2.cs => JpegColorConverter.FromRgbAvx.cs} (56%) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYCbCrAvx2.cs => JpegColorConverter.FromYCbCrAvx.cs} (71%) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYccKAvx2.cs => JpegColorConverter.FromYccKAvx.cs} (79%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYccKBasic.cs => JpegColorConverter.FromYccKScalar.cs} (81%) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.cs => JpegColorConverterBase.cs} (67%) create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.VectorizedJpegColorConverter.cs => JpegColorConverterVector.cs} (64%) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs deleted file mode 100644 index 90ebce3b87..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal abstract class Avx2JpegColorConverter : VectorizedJpegColorConverter - { - protected Avx2JpegColorConverter(JpegColorSpace colorSpace, int precision) - : base(colorSpace, precision, 8) - { - } - - protected sealed override bool IsAvailable => SimdUtils.HasAvx2; - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs deleted file mode 100644 index ed2e2cd762..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal abstract class BasicJpegColorConverter : JpegColorConverter - { - protected BasicJpegColorConverter(JpegColorSpace colorSpace, int precision) - : base(colorSpace, precision) - { - } - - protected override bool IsAvailable => true; - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs similarity index 58% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index 216c12735f..2671dec700 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -1,38 +1,33 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; -#endif namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykAvx2 : Avx2JpegColorConverter + internal sealed class FromCmykAvx : AvxColorConverter { - public FromCmykAvx2(int precision) + public FromCmykAvx(int precision) : base(JpegColorSpace.Cmyk, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 c0Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector256 c1Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); ref Vector256 c2Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); ref Vector256 c3Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); @@ -50,11 +45,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters m = Avx.Multiply(Avx.Multiply(m, k), scale); y = Avx.Multiply(Avx.Multiply(y, k), scale); } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs similarity index 83% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs index b0ad50301b..057d7846a1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs @@ -1,16 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykBasic : BasicJpegColorConverter + internal sealed class FromCmykScalar : ScalarJpegColorConverter { - public FromCmykBasic(int precision) + public FromCmykScalar(int precision) : base(JpegColorSpace.Cmyk, precision) { } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs index 0da4c9ec23..685e25aad4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs @@ -1,17 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykVector8 : Vector8JpegColorConverter + internal sealed class FromCmykVector8 : VectorizedJpegColorConverter { public FromCmykVector8(int precision) : base(JpegColorSpace.Cmyk, precision) @@ -21,17 +19,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters protected override void ConvertCoreVectorizedInplace(in ComponentValues values) { ref Vector cBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector mBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); ref Vector yBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); ref Vector kBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); var scale = new Vector(1 / this.MaximumValue); - // Walking 8 elements at one step: nint n = values.Component0.Length / 8; for (nint i = 0; i < n; i++) { @@ -40,14 +37,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Vector y = ref Unsafe.Add(ref yBase, i); Vector k = Unsafe.Add(ref kBase, i) * scale; - c = (c * k) * scale; - m = (m * k) * scale; - y = (y * k) * scale; + c = c * k * scale; + m = m * k * scale; + y = y * k * scale; } } protected override void ConvertCoreInplace(in ComponentValues values) => - FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue); + FromCmykScalar.ConvertCoreInplace(values, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs similarity index 62% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs index eca6b62920..38b159bba7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs @@ -1,30 +1,25 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; -#endif namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayscaleAvx2 : Avx2JpegColorConverter + internal sealed class FromGrayscaleAvx : AvxColorConverter { - public FromGrayscaleAvx2(int precision) + public FromGrayscaleAvx(int precision) : base(JpegColorSpace.Grayscale, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -37,11 +32,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); c0 = Avx.Multiply(c0, scale); } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromGrayscaleBasic.ScaleValues(values.Component0, this.MaximumValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs deleted file mode 100644 index 76d57bf069..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal sealed class FromGrayscaleBasic : BasicJpegColorConverter - { - public FromGrayscaleBasic(int precision) - : base(JpegColorSpace.Grayscale, precision) - { - } - - public override void ConvertToRgbInplace(in ComponentValues values) => - ScaleValues(values.Component0, this.MaximumValue); - - internal static void ScaleValues(Span values, float maxValue) - { - Span vecValues = MemoryMarshal.Cast(values); - - var scaleVector = new Vector4(1 / maxValue); - - for (int i = 0; i < vecValues.Length; i++) - { - vecValues[i] *= scaleVector; - } - - values = values.Slice(vecValues.Length * 4); - if (!values.IsEmpty) - { - float scaleValue = 1f / maxValue; - values[0] *= scaleValue; - - if ((uint)values.Length > 1) - { - values[1] *= scaleValue; - - if ((uint)values.Length > 2) - { - values[2] *= scaleValue; - } - } - } - } - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs new file mode 100644 index 0000000000..18ac5ff991 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs @@ -0,0 +1,34 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + internal sealed class FromGrayscaleScalar : ScalarJpegColorConverter + { + public FromGrayscaleScalar(int precision) + : base(JpegColorSpace.Grayscale, precision) + { + } + + public override void ConvertToRgbInplace(in ComponentValues values) => + ConvertCoreInplace(values.Component0, this.MaximumValue); + + internal static void ConvertCoreInplace(Span values, float maxValue) + { + ref float valuesRef = ref MemoryMarshal.GetReference(values); + float scale = 1 / maxValue; + + for (nint i = 0; i < values.Length; i++) + { + Unsafe.Add(ref valuesRef, i) *= scale; + } + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs new file mode 100644 index 0000000000..6aa0b59a9e --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs @@ -0,0 +1,38 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + internal sealed class FromGrayScaleVector8 : VectorizedJpegColorConverter + { + public FromGrayScaleVector8(int precision) + : base(JpegColorSpace.Grayscale, precision) + { + } + + protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + { + ref Vector cBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + + var scale = new Vector(1 / this.MaximumValue); + + nint n = values.Component0.Length / 8; + for (nint i = 0; i < n; i++) + { + ref Vector c0 = ref Unsafe.Add(ref cBase, i); + c0 *= scale; + } + } + + protected override void ConvertCoreInplace(in ComponentValues values) => + FromGrayscaleScalar.ConvertCoreInplace(values.Component0, this.MaximumValue); + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs similarity index 56% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs index 557e4e4173..31c5739034 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs @@ -1,36 +1,31 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; -#endif namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbAvx2 : Avx2JpegColorConverter + internal sealed class FromRgbAvx : AvxColorConverter { - public FromRgbAvx2(int precision) + public FromRgbAvx(int precision) : base(JpegColorSpace.RGB, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 rBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector256 gBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); ref Vector256 bBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); @@ -44,11 +39,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters g = Avx.Multiply(g, scale); b = Avx.Multiply(b, scale); } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs deleted file mode 100644 index 1425e7b584..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal sealed class FromRgbBasic : BasicJpegColorConverter - { - public FromRgbBasic(int precision) - : base(JpegColorSpace.RGB, precision) - { - } - - public override void ConvertToRgbInplace(in ComponentValues values) - { - ConvertCoreInplace(values, this.MaximumValue); - } - - internal static void ConvertCoreInplace(ComponentValues values, float maxValue) - { - FromGrayscaleBasic.ScaleValues(values.Component0, maxValue); - FromGrayscaleBasic.ScaleValues(values.Component1, maxValue); - FromGrayscaleBasic.ScaleValues(values.Component2, maxValue); - } - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs new file mode 100644 index 0000000000..83861d1e26 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + internal sealed class FromRgbScalar : ScalarJpegColorConverter + { + public FromRgbScalar(int precision) + : base(JpegColorSpace.RGB, precision) + { + } + + public override void ConvertToRgbInplace(in ComponentValues values) => + ConvertCoreInplace(values, this.MaximumValue); + + internal static void ConvertCoreInplace(ComponentValues values, float maxValue) + { + FromGrayscaleScalar.ConvertCoreInplace(values.Component0, maxValue); + FromGrayscaleScalar.ConvertCoreInplace(values.Component1, maxValue); + FromGrayscaleScalar.ConvertCoreInplace(values.Component2, maxValue); + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs index a00361d970..0dc440b7dd 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs @@ -1,17 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbVector8 : Vector8JpegColorConverter + internal sealed class FromRgbVector8 : VectorizedJpegColorConverter { public FromRgbVector8(int precision) : base(JpegColorSpace.RGB, precision) @@ -29,7 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var scale = new Vector(1 / this.MaximumValue); - // Walking 8 elements at one step: nint n = values.Component0.Length / 8; for (nint i = 0; i < n; i++) { @@ -43,7 +40,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } protected override void ConvertCoreInplace(in ComponentValues values) => - FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue); + FromRgbScalar.ConvertCoreInplace(values, this.MaximumValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs similarity index 71% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs index 5aae1faa27..1bf1c44613 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs @@ -1,31 +1,27 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using static SixLabors.ImageSharp.SimdUtils; -#endif // ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrAvx2 : Avx2JpegColorConverter + internal sealed class FromYCbCrAvx : AvxColorConverter { - public FromYCbCrAvx2(int precision) + public FromYCbCrAvx(int precision) : base(JpegColorSpace.YCbCr, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector256 c1Base = @@ -36,15 +32,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Used for the color conversion var chromaOffset = Vector256.Create(-this.HalfValue); var scale = Vector256.Create(1 / this.MaximumValue); - var rCrMult = Vector256.Create(1.402F); - var gCbMult = Vector256.Create(-0.344136F); - var gCrMult = Vector256.Create(-0.714136F); - var bCbMult = Vector256.Create(1.772F); - - // Used for packing. - var va = Vector256.Create(1F); - ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32); - Vector256 vcontrol = Unsafe.As>(ref control); + var rCrMult = Vector256.Create(FromYCbCrScalar.RCrMult); + var gCbMult = Vector256.Create(-FromYCbCrScalar.GCbMult); + var gCrMult = Vector256.Create(-FromYCbCrScalar.GCrMult); + var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult); // Walking 8 elements at one step: nint n = values.Component0.Length / 8; @@ -64,7 +55,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - // Adding & multiplying 8 elements at one time: Vector256 r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult); Vector256 g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); Vector256 b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult); @@ -77,11 +67,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters c1 = g; c2 = b; } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs deleted file mode 100644 index 990d29aa01..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal sealed class FromYCbCrBasic : BasicJpegColorConverter - { - public FromYCbCrBasic(int precision) - : base(JpegColorSpace.YCbCr, precision) - { - } - - public override void ConvertToRgbInplace(in ComponentValues values) - => ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); - - internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue) - { - Span c0 = values.Component0; - Span c1 = values.Component1; - Span c2 = values.Component2; - - var scale = 1 / maxValue; - - for (int i = 0; i < c0.Length; i++) - { - float y = c0[i]; - float cb = c1[i] - halfValue; - float cr = c2[i] - halfValue; - - c0[i] = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero) * scale; - c1[i] = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero) * scale; - c2[i] = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero) * scale; - } - } - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs new file mode 100644 index 0000000000..73c73970d0 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs @@ -0,0 +1,50 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + internal sealed class FromYCbCrScalar : ScalarJpegColorConverter + { + // TODO: comments, derived from ITU-T Rec. T.871 + internal const float RCrMult = 1.402f; + internal const float GCbMult = (float)(0.114 * 1.772 / 0.587); + internal const float GCrMult = (float)(0.299 * 1.402 / 0.587); + internal const float BCbMult = 1.772f; + + public FromYCbCrScalar(int precision) + : base(JpegColorSpace.YCbCr, precision) + { + } + + public override void ConvertToRgbInplace(in ComponentValues values) + => ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); + + internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue) + { + Span c0 = values.Component0; + Span c1 = values.Component1; + Span c2 = values.Component2; + + float scale = 1 / maxValue; + + for (int i = 0; i < c0.Length; i++) + { + float y = c0[i]; + float cb = c1[i] - halfValue; + float cr = c2[i] - halfValue; + + // r = y + (1.402F * cr); + // g = y - (0.344136F * cb) - (0.714136F * cr); + // b = y + (1.772F * cb); + c0[i] = MathF.Round(y + (RCrMult * cr), MidpointRounding.AwayFromZero) * scale; + c1[i] = MathF.Round(y - (GCbMult * cb) - (GCrMult * cr), MidpointRounding.AwayFromZero) * scale; + c2[i] = MathF.Round(y + (BCbMult * cb), MidpointRounding.AwayFromZero) * scale; + } + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs deleted file mode 100644 index 1ebc3e879d..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal sealed class FromYCbCrVector4 : VectorizedJpegColorConverter - { - public FromYCbCrVector4(int precision) - : base(JpegColorSpace.YCbCr, precision, 8) - { - } - - protected override bool IsAvailable => SimdUtils.HasVector4; - - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) - { - DebugGuard.IsTrue(values.Component0.Length % 8 == 0, nameof(values), "Length should be divisible by 8!"); - - ref Vector4Pair c0Base = - ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector4Pair c1Base = - ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector4Pair c2Base = - ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component2)); - - var chromaOffset = new Vector4(-this.HalfValue); - var maxValue = this.MaximumValue; - - // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; - - for (nint i = 0; i < n; i++) - { - // y = yVals[i]; - ref Vector4Pair c0 = ref Unsafe.Add(ref c0Base, i); - - // cb = cbVals[i] - halfValue); - ref Vector4Pair c1 = ref Unsafe.Add(ref c1Base, i); - c1.AddInplace(chromaOffset); - - // cr = crVals[i] - halfValue; - ref Vector4Pair c2 = ref Unsafe.Add(ref c2Base, i); - c2.AddInplace(chromaOffset); - - // r = y + (1.402F * cr); - Vector4Pair r = c0; - Vector4Pair tmp = c2; - tmp.MultiplyInplace(1.402F); - r.AddInplace(ref tmp); - - // g = y - (0.344136F * cb) - (0.714136F * cr); - Vector4Pair g = c0; - tmp = c1; - tmp.MultiplyInplace(-0.344136F); - g.AddInplace(ref tmp); - tmp = c2; - tmp.MultiplyInplace(-0.714136F); - g.AddInplace(ref tmp); - - // b = y + (1.772F * cb); - Vector4Pair b = c0; - tmp = c1; - tmp.MultiplyInplace(1.772F); - b.AddInplace(ref tmp); - - r.RoundAndDownscalePreVector8(maxValue); - g.RoundAndDownscalePreVector8(maxValue); - b.RoundAndDownscalePreVector8(maxValue); - - c0 = r; - c1 = g; - c2 = b; - } - } - - protected override void ConvertCoreInplace(in ComponentValues values) - => FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs index a077b9ed82..da71e24666 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs @@ -1,18 +1,16 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; // ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrVector8 : Vector8JpegColorConverter + internal sealed class FromYCbCrVector8 : VectorizedJpegColorConverter { public FromYCbCrVector8(int precision) : base(JpegColorSpace.YCbCr, precision) @@ -30,10 +28,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var chromaOffset = new Vector(-this.HalfValue); - // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; var scale = new Vector(1 / this.MaximumValue); + var rCrMult = new Vector(FromYCbCrScalar.RCrMult); + var gCbMult = new Vector(-FromYCbCrScalar.GCbMult); + var gCrMult = new Vector(-FromYCbCrScalar.GCrMult); + var bCbMult = new Vector(FromYCbCrScalar.BCbMult); + nint n = values.Component0.Length / 8; for (nint i = 0; i < n; i++) { // y = yVals[i]; @@ -49,10 +50,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - // Adding & multiplying 8 elements at one time: - Vector r = y + (cr * new Vector(1.402F)); - Vector g = y - (cb * new Vector(0.344136F)) - (cr * new Vector(0.714136F)); - Vector b = y + (cb * new Vector(1.772F)); + Vector r = y + (cr * rCrMult); + Vector g = y + (cb * gCbMult) + (cr * gCrMult); + Vector b = y + (cb * bCbMult); r = r.FastRound(); g = g.FastRound(); @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } protected override void ConvertCoreInplace(in ComponentValues values) => - FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); + FromYCbCrScalar.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs similarity index 79% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs index a3500a096a..53912ee07c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs @@ -1,30 +1,26 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using static SixLabors.ImageSharp.SimdUtils; -#endif namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKAvx2 : Avx2JpegColorConverter + internal sealed class FromYccKAvx : AvxColorConverter { - public FromYccKAvx2(int precision) + public FromYccKAvx(int precision) : base(JpegColorSpace.Ycck, precision) { } - protected override void ConvertCoreVectorizedInplace(in ComponentValues values) + public override void ConvertToRgbInplace(in ComponentValues values) { -#if SUPPORTS_RUNTIME_INTRINSICS ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); ref Vector256 c1Base = @@ -38,10 +34,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var chromaOffset = Vector256.Create(-this.HalfValue); var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); var max = Vector256.Create(this.MaximumValue); - var rCrMult = Vector256.Create(1.402F); - var gCbMult = Vector256.Create(-0.344136F); - var gCrMult = Vector256.Create(-0.714136F); - var bCbMult = Vector256.Create(1.772F); + var rCrMult = Vector256.Create(FromYCbCrScalar.RCrMult); + var gCbMult = Vector256.Create(-FromYCbCrScalar.GCbMult); + var gCrMult = Vector256.Create(-FromYCbCrScalar.GCrMult); + var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult); // Walking 8 elements at one step: nint n = values.Component0.Length / 8; @@ -62,7 +58,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - // Adding & multiplying 8 elements at one time: Vector256 r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult); Vector256 g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); @@ -80,11 +75,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters c1 = g; c2 = b; } -#endif } - - protected override void ConvertCoreInplace(in ComponentValues values) => - FromYccKBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs similarity index 81% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs index 4833f48683..4657e50cf9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs @@ -1,16 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKBasic : BasicJpegColorConverter + internal sealed class FromYccKScalar : ScalarJpegColorConverter { - public FromYccKBasic(int precision) + public FromYccKScalar(int precision) : base(JpegColorSpace.Ycck, precision) { } @@ -25,9 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters Span c2 = values.Component2; Span c3 = values.Component3; - var v = new Vector4(0, 0, 0, 1F); - - var scale = 1 / (maxValue * maxValue); + float scale = 1 / (maxValue * maxValue); for (int i = 0; i < values.Component0.Length; i++) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs index f830e5042c..152a0793ce 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs @@ -1,17 +1,15 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKVector8 : Vector8JpegColorConverter + internal sealed class FromYccKVector8 : VectorizedJpegColorConverter { public FromYccKVector8(int precision) : base(JpegColorSpace.Ycck, precision) @@ -30,13 +28,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); var chromaOffset = new Vector(-this.HalfValue); - - // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; - + var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue)); var max = new Vector(this.MaximumValue); - var scale = new Vector(1f) / (max * max); + var rCrMult = new Vector(FromYCbCrScalar.RCrMult); + var gCbMult = new Vector(-FromYCbCrScalar.GCbMult); + var gCrMult = new Vector(-FromYCbCrScalar.GCrMult); + var bCbMult = new Vector(FromYCbCrScalar.BCbMult); + nint n = values.Component0.Length / 8; for (nint i = 0; i < n; i++) { // y = yVals[i]; @@ -55,10 +54,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - // Adding & multiplying 8 elements at one time: - Vector r = y + (cr * new Vector(1.402F)); - Vector g = y - (cb * new Vector(0.344136F)) - (cr * new Vector(0.714136F)); - Vector b = y + (cb * new Vector(1.772F)); + Vector r = y + (cr * rCrMult); + Vector g = y + (cb * gCbMult) + (cr * gCrMult); + Vector b = y + (cb * bCbMult); r = (max - r.FastRound()) * scaledK; g = (max - g.FastRound()) * scaledK; @@ -71,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } protected override void ConvertCoreInplace(in ComponentValues values) => - FromYccKBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); + FromYccKScalar.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs deleted file mode 100644 index 3e9b889db7..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters -{ - internal abstract partial class JpegColorConverter - { - internal abstract class Vector8JpegColorConverter : VectorizedJpegColorConverter - { - protected Vector8JpegColorConverter(JpegColorSpace colorSpace, int precision) - : base(colorSpace, precision, 8) - { - } - - protected sealed override bool IsAvailable => SimdUtils.HasVector8; - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs new file mode 100644 index 0000000000..ff82b36dc0 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + /// + /// abstract base for implementations + /// based on instructions. + /// + /// + /// Converters of this family would expect input buffers lengths to be + /// divisible by 8 without a remainder. + /// This is guaranteed by real-life data as jpeg stores pixels via 8x8 blocks. + /// DO NOT pass test data of invalid size to these converters as they + /// potentially won't do a bound check and return a false positive result. + /// + internal abstract class AvxColorConverter : JpegColorConverterBase + { + protected AvxColorConverter(JpegColorSpace colorSpace, int precision) + : base(colorSpace, precision) + { + } + + protected override bool IsAvailable => Avx.IsSupported; + } + } +} +#endif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs similarity index 67% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs index dad46861e2..8767f5efc3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs @@ -4,26 +4,24 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Numerics; using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { /// - /// Encapsulates the conversion of Jpeg channels to RGBA values packed in buffer. + /// Encapsulates the conversion of color channels from jpeg image to RGB channels. /// - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { /// /// The available converters /// - private static readonly JpegColorConverter[] Converters = CreateConverters(); + private static readonly JpegColorConverterBase[] Converters = CreateConverters(); /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - protected JpegColorConverter(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterBase(JpegColorSpace colorSpace, int precision) { this.ColorSpace = colorSpace; this.Precision = precision; @@ -32,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// Gets a value indicating whether this is available + /// Gets a value indicating whether this is available /// on the current runtime and CPU architecture. /// protected abstract bool IsAvailable { get; } @@ -58,11 +56,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters private float HalfValue { get; } /// - /// Returns the corresponding to the given + /// Returns the corresponding to the given /// - public static JpegColorConverter GetConverter(JpegColorSpace colorSpace, int precision) + public static JpegColorConverterBase GetConverter(JpegColorSpace colorSpace, int precision) { - JpegColorConverter converter = Array.Find( + JpegColorConverterBase converter = Array.Find( Converters, c => c.ColorSpace == colorSpace && c.Precision == precision); @@ -82,11 +80,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public abstract void ConvertToRgbInplace(in ComponentValues values); /// - /// Returns the s for all supported colorspaces and precisions. + /// Returns the s for all supported colorspaces and precisions. /// - private static JpegColorConverter[] CreateConverters() + private static JpegColorConverterBase[] CreateConverters() { - var converters = new List(); + var converters = new List(); // 8-bit converters converters.AddRange(GetYCbCrConverters(8)); @@ -106,63 +104,63 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// Returns the s for the YCbCr colorspace. + /// Returns the s for the YCbCr colorspace. /// - private static IEnumerable GetYCbCrConverters(int precision) + private static IEnumerable GetYCbCrConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromYCbCrAvx2(precision); + yield return new FromYCbCrAvx(precision); #endif yield return new FromYCbCrVector8(precision); - yield return new FromYCbCrVector4(precision); - yield return new FromYCbCrBasic(precision); + yield return new FromYCbCrScalar(precision); } /// - /// Returns the s for the YccK colorspace. + /// Returns the s for the YccK colorspace. /// - private static IEnumerable GetYccKConverters(int precision) + private static IEnumerable GetYccKConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromYccKAvx2(precision); + yield return new FromYccKAvx(precision); #endif yield return new FromYccKVector8(precision); - yield return new FromYccKBasic(precision); + yield return new FromYccKScalar(precision); } /// - /// Returns the s for the CMYK colorspace. + /// Returns the s for the CMYK colorspace. /// - private static IEnumerable GetCmykConverters(int precision) + private static IEnumerable GetCmykConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromCmykAvx2(precision); + yield return new FromCmykAvx(precision); #endif yield return new FromCmykVector8(precision); - yield return new FromCmykBasic(precision); + yield return new FromCmykScalar(precision); } /// - /// Returns the s for the gray scale colorspace. + /// Returns the s for the gray scale colorspace. /// - private static IEnumerable GetGrayScaleConverters(int precision) + private static IEnumerable GetGrayScaleConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromGrayscaleAvx2(precision); + yield return new FromGrayscaleAvx(precision); #endif - yield return new FromGrayscaleBasic(precision); + yield return new FromGrayScaleVector8(precision); + yield return new FromGrayscaleScalar(precision); } /// - /// Returns the s for the RGB colorspace. + /// Returns the s for the RGB colorspace. /// - private static IEnumerable GetRgbConverters(int precision) + private static IEnumerable GetRgbConverters(int precision) { #if SUPPORTS_RUNTIME_INTRINSICS - yield return new FromRgbAvx2(precision); + yield return new FromRgbAvx(precision); #endif yield return new FromRgbVector8(precision); - yield return new FromRgbBasic(precision); + yield return new FromRgbScalar(precision); } /// @@ -200,35 +198,39 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// /// Initializes a new instance of the struct. /// - /// The 1-4 sized list of component post processors. - /// The row to convert - public ComponentValues(IReadOnlyList componentProcessors, int row) + /// List of component buffers. + /// Row to convert + public ComponentValues(IReadOnlyList> componentBuffers, int row) { - this.ComponentCount = componentProcessors.Count; + DebugGuard.MustBeGreaterThan(componentBuffers.Count, 0, nameof(componentBuffers)); + + this.ComponentCount = componentBuffers.Count; - this.Component0 = componentProcessors[0].GetColorBufferRowSpan(row); + this.Component0 = componentBuffers[0].GetRowSpan(row); // In case of grayscale, Component1 and Component2 point to Component0 memory area - this.Component1 = this.ComponentCount > 1 ? componentProcessors[1].GetColorBufferRowSpan(row) : this.Component0; - this.Component2 = this.ComponentCount > 2 ? componentProcessors[2].GetColorBufferRowSpan(row) : this.Component0; - this.Component3 = this.ComponentCount > 3 ? componentProcessors[3].GetColorBufferRowSpan(row) : Span.Empty; + this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].GetRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].GetRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].GetRowSpan(row) : Span.Empty; } /// /// Initializes a new instance of the struct. /// - /// The 1-4 sized list of component buffers. - /// The row to convert - public ComponentValues(IReadOnlyList> componentBuffers, int row) + /// List of component color processors. + /// Row to convert + public ComponentValues(IReadOnlyList processors, int row) { - this.ComponentCount = componentBuffers.Count; + DebugGuard.MustBeGreaterThan(processors.Count, 0, nameof(processors)); - this.Component0 = componentBuffers[0].GetRowSpan(row); + this.ComponentCount = processors.Count; + + this.Component0 = processors[0].ColorBuffer.GetRowSpan(row); // In case of grayscale, Component1 and Component2 point to Component0 memory area - this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].GetRowSpan(row) : this.Component0; - this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].GetRowSpan(row) : this.Component0; - this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].GetRowSpan(row) : Span.Empty; + this.Component1 = this.ComponentCount > 1 ? processors[1].ColorBuffer.GetRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? processors[2].ColorBuffer.GetRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? processors[3].ColorBuffer.GetRowSpan(row) : Span.Empty; } internal ComponentValues( diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs new file mode 100644 index 0000000000..89d6c45443 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters +{ + internal abstract partial class JpegColorConverterBase + { + /// + /// abstract base for implementations + /// based on scalar instructions. + /// + internal abstract class ScalarJpegColorConverter : JpegColorConverterBase + { + protected ScalarJpegColorConverter(JpegColorSpace colorSpace, int precision) + : base(colorSpace, precision) + { + } + + protected override bool IsAvailable => true; + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs similarity index 64% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index fc4fb77860..3a40fad0cd 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -1,27 +1,36 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { - internal abstract partial class JpegColorConverter + internal abstract partial class JpegColorConverterBase { - internal abstract class VectorizedJpegColorConverter : JpegColorConverter + /// + /// abstract base for implementations + /// based on API. + /// + /// + /// Converters of this family can work with data of any size. + /// Even though real life data is guaranteed to be of size + /// divisible by 8 newer SIMD instructions like AVX512 won't work with + /// such data out of the box. These converters have fallback code + /// for 'remainder' data. + /// + internal abstract class VectorizedJpegColorConverter : JpegColorConverterBase { - private readonly int vectorSize; - - protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision, int vectorSize) + protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { - this.vectorSize = vectorSize; } + protected sealed override bool IsAvailable => SimdUtils.HasVector8; + public override void ConvertToRgbInplace(in ComponentValues values) { int length = values.Component0.Length; - int remainder = values.Component0.Length % this.vectorSize; + int remainder = values.Component0.Length % 8; int simdCount = length - remainder; if (simdCount > 0) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs index 1eb74ff80d..acd98bcfcd 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs @@ -57,6 +57,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// The jpeg frame with the color space to convert to. /// The raw JPEG data. /// The color converter. - protected virtual JpegColorConverter GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(jpegData.ColorSpace, frame.Precision); + protected virtual JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverterBase.GetConverter(jpegData.ColorSpace, frame.Precision); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 0003437e74..7137c52039 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Color converter from jpeg color space to target pixel color space. /// - private JpegColorConverter colorConverter; + private JpegColorConverterBase colorConverter; /// /// Intermediate buffer of RGB components used in color conversion. @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { int y = yy - this.pixelRowCounter; - var values = new JpegColorConverter.ComponentValues(this.componentProcessors, y); + var values = new JpegColorConverterBase.ComponentValues(this.componentProcessors, y); this.colorConverter.ConvertToRgbInplace(values); values = values.Slice(0, width); // slice away Jpeg padding diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs index 3b5833c102..001480542f 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/RgbJpegSpectralConverter.cs @@ -27,6 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors } /// - protected override JpegColorConverter GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverter.GetConverter(JpegColorSpace.RGB, frame.Precision); + protected override JpegColorConverterBase GetColorConverter(JpegFrame frame, IRawJpegData jpegData) => JpegColorConverterBase.GetConverter(JpegColorSpace.RGB, frame.Precision); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 490beec6fb..2642c21f12 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykBasic(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVector8() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykVector8(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromCmykAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs index 7b62e14340..1fc85e967a 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs @@ -17,17 +17,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromGrayscaleBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromGrayscaleBasic(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromGrayscaleAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromGrayscaleAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index af03b31e54..517630a500 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbBasic(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVector8() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbVector8(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromRgbAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 18daa364cf..3b142d9251 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -17,33 +17,33 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrBasic(8).ConvertToRgbInplace(values); } [Benchmark(Baseline = true)] public void SimdVector() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrVector4(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrVector4(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVector8() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrVector8(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYCbCrAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index 08e5e50d19..b26ac0622d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -17,25 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKBasic(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVector8() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKVector8(8).ConvertToRgbInplace(values); } [Benchmark] public void SimdVectorAvx2() { - var values = new JpegColorConverter.ComponentValues(this.Input, 0); + var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverter.FromYccKAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKAvx2(8).ConvertToRgbInplace(values); } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index d6dc57e834..fc3529513e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -45,25 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromYCbCrBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromYCbCrBasic(8), - 3, - inputBufferLength, - resultBufferLength, - seed); - } - - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCrVector4(int inputBufferLength, int resultBufferLength, int seed) - { - if (!SimdUtils.HasVector4) - { - this.Output.WriteLine("No SSE present, skipping test!"); - return; - } - - ValidateConversion( - new JpegColorConverter.FromYCbCrVector4(8), + new JpegColorConverterBase.FromYCbCrScalar(8), 3, inputBufferLength, resultBufferLength, @@ -81,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromYCbCrVector8(8), + new JpegColorConverterBase.FromYCbCrVector8(8), 3, inputBufferLength, resultBufferLength, @@ -99,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromYCbCrAvx2(8), + new JpegColorConverterBase.FromYCbCrAvx(8), 3, inputBufferLength, resultBufferLength, @@ -123,7 +105,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromCmykBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromCmykBasic(8), + new JpegColorConverterBase.FromCmykScalar(8), 4, inputBufferLength, resultBufferLength, @@ -141,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromCmykVector8(8), + new JpegColorConverterBase.FromCmykVector8(8), 4, inputBufferLength, resultBufferLength, @@ -159,7 +141,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromCmykAvx2(8), + new JpegColorConverterBase.FromCmykAvx(8), 4, inputBufferLength, resultBufferLength, @@ -183,7 +165,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromGrayscaleBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromGrayscaleBasic(8), + new JpegColorConverterBase.FromGrayscaleScalar(8), 1, inputBufferLength, resultBufferLength, @@ -201,7 +183,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromGrayscaleAvx2(8), + new JpegColorConverterBase.FromGrayscaleAvx(8), 1, inputBufferLength, resultBufferLength, @@ -225,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromRgbBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromRgbBasic(8), + new JpegColorConverterBase.FromRgbScalar(8), 3, inputBufferLength, resultBufferLength, @@ -243,7 +225,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromRgbVector8(8), + new JpegColorConverterBase.FromRgbVector8(8), 3, inputBufferLength, resultBufferLength, @@ -261,7 +243,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromRgbAvx2(8), + new JpegColorConverterBase.FromRgbAvx(8), 3, inputBufferLength, resultBufferLength, @@ -285,7 +267,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void FromYccKBasic(int inputBufferLength, int resultBufferLength, int seed) { ValidateConversion( - new JpegColorConverter.FromYccKBasic(8), + new JpegColorConverterBase.FromYccKScalar(8), 4, inputBufferLength, resultBufferLength, @@ -303,7 +285,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromYccKVector8(8), + new JpegColorConverterBase.FromYccKVector8(8), 4, inputBufferLength, resultBufferLength, @@ -321,7 +303,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverter.FromYccKAvx2(8), + new JpegColorConverterBase.FromYccKAvx(8), 4, inputBufferLength, resultBufferLength, @@ -340,7 +322,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } - private static JpegColorConverter.ComponentValues CreateRandomValues( + private static JpegColorConverterBase.ComponentValues CreateRandomValues( int componentCount, int inputBufferLength, int seed, @@ -365,7 +347,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg buffers[i] = new Buffer2D(source, values.Length, 1); } - return new JpegColorConverter.ComponentValues(buffers, 0); + return new JpegColorConverterBase.ComponentValues(buffers, 0); } private static void ValidateConversion( @@ -376,7 +358,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg int seed) { ValidateConversion( - JpegColorConverter.GetConverter(colorSpace, 8), + JpegColorConverterBase.GetConverter(colorSpace, 8), componentCount, inputBufferLength, resultBufferLength, @@ -384,14 +366,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } private static void ValidateConversion( - JpegColorConverter converter, + JpegColorConverterBase converter, int componentCount, int inputBufferLength, int resultBufferLength, int seed) { - JpegColorConverter.ComponentValues original = CreateRandomValues(componentCount, inputBufferLength, seed); - JpegColorConverter.ComponentValues values = Copy(original); + JpegColorConverterBase.ComponentValues original = CreateRandomValues(componentCount, inputBufferLength, seed); + JpegColorConverterBase.ComponentValues values = Copy(original); converter.ConvertToRgbInplace(values); @@ -400,20 +382,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Validate(converter.ColorSpace, original, values, i); } - static JpegColorConverter.ComponentValues Copy(JpegColorConverter.ComponentValues values) + static JpegColorConverterBase.ComponentValues Copy(JpegColorConverterBase.ComponentValues values) { Span c0 = values.Component0.ToArray(); Span c1 = values.ComponentCount > 1 ? values.Component1.ToArray().AsSpan() : c0; Span c2 = values.ComponentCount > 2 ? values.Component2.ToArray().AsSpan() : c0; Span c3 = values.ComponentCount > 3 ? values.Component3.ToArray().AsSpan() : Span.Empty; - return new JpegColorConverter.ComponentValues(values.ComponentCount, c0, c1, c2, c3); + return new JpegColorConverterBase.ComponentValues(values.ComponentCount, c0, c1, c2, c3); } } private static void Validate( JpegColorSpace colorSpace, - in JpegColorConverter.ComponentValues original, - in JpegColorConverter.ComponentValues result, + in JpegColorConverterBase.ComponentValues original, + in JpegColorConverterBase.ComponentValues result, int i) { switch (colorSpace) @@ -439,7 +421,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - private static void ValidateYCbCr(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateYCbCr(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float y = values.Component0[i]; float cb = values.Component1[i]; @@ -452,7 +434,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(expected, actual, ColorSpaceComparer); } - private static void ValidateCyyK(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { var v = new Vector4(0, 0, 0, 1F); var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); @@ -477,7 +459,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(expected, actual, ColorSpaceComparer); } - private static void ValidateRgb(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateRgb(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float r = values.Component0[i]; float g = values.Component1[i]; @@ -489,7 +471,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(expected, actual, ColorSpaceComparer); } - private static void ValidateGrayScale(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float y = values.Component0[i]; var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); @@ -498,7 +480,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(expected, actual, ColorSpaceComparer); } - private static void ValidateCmyk(in JpegColorConverter.ComponentValues values, in JpegColorConverter.ComponentValues result, int i) + private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { var v = new Vector4(0, 0, 0, 1F); var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); From 311748ef61bbe51efb17b6dfa43516c0eb14445c Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 08:11:55 +0300 Subject: [PATCH 02/25] Fixed compilation errors --- .../Jpeg/ColorConversion/CmykColorConversion.cs | 8 +++++--- .../ColorConversion/GrayscaleColorConversion.cs | 10 ++++++---- .../Jpeg/ColorConversion/RgbColorConversion.cs | 10 ++++++---- .../Jpeg/ColorConversion/YCbCrColorConversion.cs | 16 +++++----------- .../Jpeg/ColorConversion/YccKColorConverter.cs | 8 +++++--- .../Formats/Jpg/JpegColorConverterTests.cs | 10 ++++++++++ 6 files changed, 37 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 2642c21f12..36e6669578 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromCmykBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykScalar(8).ConvertToRgbInplace(values); } [Benchmark] @@ -30,12 +30,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg new JpegColorConverterBase.FromCmykVector8(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] - public void SimdVectorAvx2() + public void SimdVectorAvx() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromCmykAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs index 1fc85e967a..2fdb47077d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using BenchmarkDotNet.Attributes; @@ -19,15 +19,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromGrayscaleBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromGrayscaleScalar(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] - public void SimdVectorAvx2() + public void SimdVectorAvx() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromGrayscaleAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromGrayscaleAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index 517630a500..69c1a39741 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using BenchmarkDotNet.Attributes; @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromRgbBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbScalar(8).ConvertToRgbInplace(values); } [Benchmark] @@ -30,12 +30,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg new JpegColorConverterBase.FromRgbVector8(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] - public void SimdVectorAvx2() + public void SimdVectorAvx() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromRgbAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 3b142d9251..656cae1047 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -19,15 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYCbCrBasic(8).ConvertToRgbInplace(values); - } - - [Benchmark(Baseline = true)] - public void SimdVector() - { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - - new JpegColorConverterBase.FromYCbCrVector4(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrScalar(8).ConvertToRgbInplace(values); } [Benchmark] @@ -38,12 +30,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg new JpegColorConverterBase.FromYCbCrVector8(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] - public void SimdVectorAvx2() + public void SimdVectorAvx() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYCbCrAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index b26ac0622d..6c0583b623 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using BenchmarkDotNet.Attributes; @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYccKBasic(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKScalar(8).ConvertToRgbInplace(values); } [Benchmark] @@ -30,12 +30,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg new JpegColorConverterBase.FromYccKVector8(8).ConvertToRgbInplace(values); } +#if SUPPORTS_RUNTIME_INTRINSICS [Benchmark] public void SimdVectorAvx2() { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYccKAvx2(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKAvx(8).ConvertToRgbInplace(values); } +#endif } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index fc3529513e..41c9dd6a34 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -70,6 +70,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromYCbCrAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -87,6 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] @@ -130,6 +132,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromCmykAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -147,6 +150,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] @@ -172,6 +176,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromGrayscaleAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -189,6 +194,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] @@ -232,6 +238,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromRgbAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -249,6 +256,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] @@ -292,6 +300,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } +#if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] public void FromYccKAvx2(int inputBufferLength, int resultBufferLength, int seed) @@ -309,6 +318,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg resultBufferLength, seed); } +#endif [Theory] [MemberData(nameof(CommonConversionData))] From 231932f952f8084644e07174adc2d2c52e6e09a2 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 08:27:08 +0300 Subject: [PATCH 03/25] Fixed docs --- .../Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 7137c52039..a3e98125ea 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -14,11 +14,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// /// Color decoding scheme: - /// + /// /// - /// 1. Decode spectral data to Jpeg color space - /// 2. Convert from Jpeg color space to RGB - /// 3. Convert from RGB to target pixel space + /// Decode spectral data to Jpeg color space + /// Convert from Jpeg color space to RGB + /// Convert from RGB to target pixel space /// /// /// From be057f5a339d9b1e47be4c86558d98bc3abd5dcd Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 08:37:40 +0300 Subject: [PATCH 04/25] Use Vector256.Count instead of magic 8 --- .../Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index 2671dec700..4c89fc6fad 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { ref Vector256 c = ref Unsafe.Add(ref c0Base, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs index 38b159bba7..fcfcaa2a98 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs index 31c5739034..83fbc369bc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Used for the color conversion var scale = Vector256.Create(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { ref Vector256 r = ref Unsafe.Add(ref rBase, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs index 1bf1c44613..adf6e8e0f6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult); // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { // y = yVals[i]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs index 53912ee07c..86528c74d5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult); // Walking 8 elements at one step: - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) { // y = yVals[i]; From add85f899986218d57723d80b85bfba18dbacad6 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 1 Dec 2021 08:46:00 +0300 Subject: [PATCH 05/25] Removed HasAvx2 flag, reorganized test skipping --- src/ImageSharp/Common/Helpers/SimdUtils.cs | 12 ----- .../ColorConverters/JpegColorConverterAvx.cs | 2 +- .../ColorConverters/JpegColorConverterBase.cs | 2 +- .../JpegColorConverterScalar.cs | 2 +- .../JpegColorConverterVector.cs | 2 +- .../Formats/Jpg/JpegColorConverterTests.cs | 45 ++++++++++++------- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 6d82cfad01..29068a82c9 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -33,18 +33,6 @@ namespace SixLabors.ImageSharp public static bool HasVector4 { get; } = Vector.IsHardwareAccelerated && Vector.Count == 4; - public static bool HasAvx2 - { - get - { -#if SUPPORTS_RUNTIME_INTRINSICS - return Avx2.IsSupported; -#else - return false; -#endif - } - } - /// /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs index ff82b36dc0..559422273e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - protected override bool IsAvailable => Avx.IsSupported; + public override bool IsAvailable => Avx.IsSupported; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs index 8767f5efc3..b8fd169e97 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// Gets a value indicating whether this is available /// on the current runtime and CPU architecture. /// - protected abstract bool IsAvailable { get; } + public abstract bool IsAvailable { get; } /// /// Gets the of this converter. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs index 89d6c45443..76134d490c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - protected override bool IsAvailable => true; + public override bool IsAvailable => true; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index 3a40fad0cd..3cd295f0b4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - protected sealed override bool IsAvailable => SimdUtils.HasVector8; + public sealed override bool IsAvailable => SimdUtils.HasVector8; public override void ConvertToRgbInplace(in ComponentValues values) { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 41c9dd6a34..7b91e1a8af 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -75,14 +75,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromYCbCrAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromYCbCrAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromYCbCrAvx(8), + converter, 3, inputBufferLength, resultBufferLength, @@ -137,14 +140,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromCmykAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromCmykAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromCmykAvx(8), + converter, 4, inputBufferLength, resultBufferLength, @@ -181,14 +187,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromGrayscaleAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromGrayscaleAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromGrayscaleAvx(8), + converter, 1, inputBufferLength, resultBufferLength, @@ -243,14 +252,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromRgbAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromRgbAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromRgbAvx(8), + converter, 3, inputBufferLength, resultBufferLength, @@ -305,14 +317,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromYccKAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasAvx2) + var converter = new JpegColorConverterBase.FromYccKAvx(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromYccKAvx(8), + converter, 4, inputBufferLength, resultBufferLength, From 45e4768b91416a07ab9ada37c389697d89e7bd7b Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 09:13:06 +0300 Subject: [PATCH 06/25] Vector color converters can work with any available vector size instead of 8 --- ...s => JpegColorConverter.FromCmykVector.cs} | 6 ++-- ...JpegColorConverter.FromGrayScaleVector.cs} | 6 ++-- ...cs => JpegColorConverter.FromRgbVector.cs} | 6 ++-- ... => JpegColorConverter.FromYCbCrVector.cs} | 6 ++-- ...s => JpegColorConverter.FromYccKVector.cs} | 6 ++-- .../ColorConverters/JpegColorConverterBase.cs | 10 +++---- .../JpegColorConverterVector.cs | 30 +++++++++---------- .../ColorConversion/CmykColorConversion.cs | 2 +- .../ColorConversion/RgbColorConversion.cs | 2 +- .../ColorConversion/YCbCrColorConversion.cs | 2 +- .../ColorConversion/YccKColorConverter.cs | 2 +- .../Formats/Jpg/JpegColorConverterTests.cs | 8 ++--- 12 files changed, 43 insertions(+), 43 deletions(-) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromCmykVector8.cs => JpegColorConverter.FromCmykVector.cs} (90%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromGrayScaleVector8.cs => JpegColorConverter.FromGrayScaleVector.cs} (84%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromRgbVector8.cs => JpegColorConverter.FromRgbVector.cs} (89%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYCbCrVector8.cs => JpegColorConverter.FromYCbCrVector.cs} (93%) rename src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/{JpegColorConverter.FromYccKVector8.cs => JpegColorConverter.FromYccKVector.cs} (94%) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs similarity index 90% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs index 685e25aad4..9b123547b9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykVector8 : VectorizedJpegColorConverter + internal sealed class FromCmykVector : VectorizedJpegColorConverter { - public FromCmykVector8(int precision) + public FromCmykVector(int precision) : base(JpegColorSpace.Cmyk, precision) { } @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var scale = new Vector(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { ref Vector c = ref Unsafe.Add(ref cBase, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs similarity index 84% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs index 6aa0b59a9e..1ca329a12e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayScaleVector8 : VectorizedJpegColorConverter + internal sealed class FromGrayScaleVector : VectorizedJpegColorConverter { - public FromGrayScaleVector8(int precision) + public FromGrayScaleVector(int precision) : base(JpegColorSpace.Grayscale, precision) { } @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var scale = new Vector(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { ref Vector c0 = ref Unsafe.Add(ref cBase, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs similarity index 89% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs index 0dc440b7dd..b2b059cdc1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbVector8 : VectorizedJpegColorConverter + internal sealed class FromRgbVector : VectorizedJpegColorConverter { - public FromRgbVector8(int precision) + public FromRgbVector(int precision) : base(JpegColorSpace.RGB, precision) { } @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var scale = new Vector(1 / this.MaximumValue); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { ref Vector r = ref Unsafe.Add(ref rBase, i); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs similarity index 93% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs index da71e24666..f340143321 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs @@ -10,9 +10,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrVector8 : VectorizedJpegColorConverter + internal sealed class FromYCbCrVector : VectorizedJpegColorConverter { - public FromYCbCrVector8(int precision) + public FromYCbCrVector(int precision) : base(JpegColorSpace.YCbCr, precision) { } @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var gCrMult = new Vector(-FromYCbCrScalar.GCrMult); var bCbMult = new Vector(FromYCbCrScalar.BCbMult); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { // y = yVals[i]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs similarity index 94% rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs index 152a0793ce..1e826c2c08 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKVector8 : VectorizedJpegColorConverter + internal sealed class FromYccKVector : VectorizedJpegColorConverter { - public FromYccKVector8(int precision) + public FromYccKVector(int precision) : base(JpegColorSpace.Ycck, precision) { } @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters var gCrMult = new Vector(-FromYCbCrScalar.GCrMult); var bCbMult = new Vector(FromYCbCrScalar.BCbMult); - nint n = values.Component0.Length / 8; + nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) { // y = yVals[i]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs index b8fd169e97..0ab7a108fb 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromYCbCrAvx(precision); #endif - yield return new FromYCbCrVector8(precision); + yield return new FromYCbCrVector(precision); yield return new FromYCbCrScalar(precision); } @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromYccKAvx(precision); #endif - yield return new FromYccKVector8(precision); + yield return new FromYccKVector(precision); yield return new FromYccKScalar(precision); } @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromCmykAvx(precision); #endif - yield return new FromCmykVector8(precision); + yield return new FromCmykVector(precision); yield return new FromCmykScalar(precision); } @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromGrayscaleAvx(precision); #endif - yield return new FromGrayScaleVector8(precision); + yield return new FromGrayScaleVector(precision); yield return new FromGrayscaleScalar(precision); } @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters #if SUPPORTS_RUNTIME_INTRINSICS yield return new FromRgbAvx(precision); #endif - yield return new FromRgbVector8(precision); + yield return new FromRgbVector(precision); yield return new FromRgbScalar(precision); } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index 3cd295f0b4..42f6cab5ca 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Numerics; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { @@ -9,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { /// /// abstract base for implementations - /// based on API. + /// based on API. /// /// /// Converters of this family can work with data of any size. @@ -25,27 +26,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public sealed override bool IsAvailable => SimdUtils.HasVector8; + public sealed override bool IsAvailable => Vector.Count % 4 == 0; public override void ConvertToRgbInplace(in ComponentValues values) { + DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware"); + int length = values.Component0.Length; - int remainder = values.Component0.Length % 8; + int remainder = values.Component0.Length % Vector.Count; + + // Jpeg images are guaranteed to have pixel strides at least 8 pixels wide + // Thus there's no need to check whether simdCount is greater than zero int simdCount = length - remainder; - if (simdCount > 0) + this.ConvertCoreVectorizedInplace(values.Slice(0, simdCount)); + + // There's actually a lot of image/photo resolutions which won't have + // a remainder so it's better to check here than spend useless virtual call + if (remainder > 0) { - // This implementation is actually AVX specific. - // An AVX register is capable of storing 8 float-s. - if (!this.IsAvailable) - { - throw new InvalidOperationException( - "This converter can be used only on architecture having 256 byte floating point SIMD registers!"); - } - - this.ConvertCoreVectorizedInplace(values.Slice(0, simdCount)); + this.ConvertCoreInplace(values.Slice(simdCount, remainder)); } - - this.ConvertCoreInplace(values.Slice(simdCount, remainder)); } protected virtual void ConvertCoreVectorizedInplace(in ComponentValues values) => throw new NotImplementedException(); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 36e6669578..0f791ed8ea 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromCmykVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromCmykVector(8).ConvertToRgbInplace(values); } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index 69c1a39741..987a931948 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromRgbVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromRgbVector(8).ConvertToRgbInplace(values); } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 656cae1047..8d68460334 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYCbCrVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYCbCrVector(8).ConvertToRgbInplace(values); } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index 6c0583b623..7e9edc918e 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); - new JpegColorConverterBase.FromYccKVector8(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.FromYccKVector(8).ConvertToRgbInplace(values); } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 7b91e1a8af..fbbb73b15b 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverterBase.FromYCbCrVector8(8), + new JpegColorConverterBase.FromYCbCrVector(8), 3, inputBufferLength, resultBufferLength, @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverterBase.FromCmykVector8(8), + new JpegColorConverterBase.FromCmykVector(8), 4, inputBufferLength, resultBufferLength, @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverterBase.FromRgbVector8(8), + new JpegColorConverterBase.FromRgbVector(8), 3, inputBufferLength, resultBufferLength, @@ -305,7 +305,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } ValidateConversion( - new JpegColorConverterBase.FromYccKVector8(8), + new JpegColorConverterBase.FromYccKVector(8), 4, inputBufferLength, resultBufferLength, From aa2422453126365b96f2c80e632e3c55c49e6d32 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 10:54:46 +0300 Subject: [PATCH 07/25] CMYK to RGB converter performance tweaks --- .../ColorConverters/JpegColorConverter.FromCmykAvx.cs | 8 ++++---- .../JpegColorConverter.FromCmykScalar.cs | 11 ++++++----- .../JpegColorConverter.FromCmykVector.cs | 11 ++++++----- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index 4c89fc6fad..d627f7eafd 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); // Used for the color conversion - var scale = Vector256.Create(1 / this.MaximumValue); + var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); nint n = values.Component0.Length / Vector256.Count; for (nint i = 0; i < n; i++) @@ -41,9 +41,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters Vector256 k = Unsafe.Add(ref c3Base, i); k = Avx.Multiply(k, scale); - c = Avx.Multiply(Avx.Multiply(c, k), scale); - m = Avx.Multiply(Avx.Multiply(m, k), scale); - y = Avx.Multiply(Avx.Multiply(y, k), scale); + c = Avx.Multiply(c, k); + m = Avx.Multiply(m, k); + y = Avx.Multiply(y, k); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs index 057d7846a1..e70aa7cb47 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs @@ -24,17 +24,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters Span c2 = values.Component2; Span c3 = values.Component3; - float scale = 1 / maxValue; + float scale = 1 / (maxValue * maxValue); for (int i = 0; i < c0.Length; i++) { float c = c0[i]; float m = c1[i]; float y = c2[i]; - float k = c3[i] / maxValue; + float k = c3[i]; - c0[i] = c * k * scale; - c1[i] = m * k * scale; - c2[i] = y * k * scale; + k *= scale; + c0[i] = c * k; + c1[i] = m * k; + c2[i] = y * k; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs index 9b123547b9..8fd9181409 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Vector kBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - var scale = new Vector(1 / this.MaximumValue); + var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue)); nint n = values.Component0.Length / Vector.Count; for (nint i = 0; i < n; i++) @@ -35,11 +35,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters ref Vector c = ref Unsafe.Add(ref cBase, i); ref Vector m = ref Unsafe.Add(ref mBase, i); ref Vector y = ref Unsafe.Add(ref yBase, i); - Vector k = Unsafe.Add(ref kBase, i) * scale; + Vector k = Unsafe.Add(ref kBase, i); - c = c * k * scale; - m = m * k * scale; - y = y * k * scale; + k *= scale; + c *= k; + m *= k; + y *= k; } } From 5605de5b19c8462848e91b22c23b3ae04bb51d2b Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 11:13:00 +0300 Subject: [PATCH 08/25] Fixed existing tests, added grayscale vector test and fixed tests naming --- .../Formats/Jpg/JpegColorConverterTests.cs | 65 ++++++++++++++----- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index fbbb73b15b..75d12710d2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -54,16 +54,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(CommonConversionData))] - public void FromYCbCrVector8(int inputBufferLength, int resultBufferLength, int seed) + public void FromYCbCrVector(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasVector8) + var converter = new JpegColorConverterBase.FromYCbCrVector(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromYCbCrVector(8), + converter, 3, inputBufferLength, resultBufferLength, @@ -119,16 +122,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(CommonConversionData))] - public void FromCmykVector8(int inputBufferLength, int resultBufferLength, int seed) + public void FromCmykVector(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasVector8) + var converter = new JpegColorConverterBase.FromCmykVector(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromCmykVector(8), + converter, 4, inputBufferLength, resultBufferLength, @@ -182,6 +188,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } + [Theory] + [MemberData(nameof(CommonConversionData))] + public void FromGrayscaleVector(int inputBufferLength, int resultBufferLength, int seed) + { + var converter = new JpegColorConverterBase.FromGrayScaleVector(8); + + if (!converter.IsAvailable) + { + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); + return; + } + + ValidateConversion( + converter, + 1, + inputBufferLength, + resultBufferLength, + seed); + } + #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(CommonConversionData))] @@ -231,16 +258,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(CommonConversionData))] - public void FromRgbVector8(int inputBufferLength, int resultBufferLength, int seed) + public void FromRgbVector(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasVector8) + var converter = new JpegColorConverterBase.FromRgbVector(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromRgbVector(8), + converter, 3, inputBufferLength, resultBufferLength, @@ -296,16 +326,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(CommonConversionData))] - public void FromYccKVector8(int inputBufferLength, int resultBufferLength, int seed) + public void FromYccKVector(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.HasVector8) + var converter = new JpegColorConverterBase.FromYccKVector(8); + + if (!converter.IsAvailable) { - this.Output.WriteLine("No AVX2 present, skipping test!"); + this.Output.WriteLine( + $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); return; } ValidateConversion( - new JpegColorConverterBase.FromYccKVector(8), + converter, 4, inputBufferLength, resultBufferLength, From f10fe55844f8fe9c6cabca11b412013e6a396118 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 11:44:00 +0300 Subject: [PATCH 09/25] Added tests, removed duplicated tests --- .../Jpeg/Components/Decoder/JpegColorSpace.cs | 15 +++ .../Formats/Jpg/JpegColorConverterTests.cs | 109 ++++++++---------- 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs index 90162aba36..7ef2809323 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs @@ -10,14 +10,29 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { Undefined = 0, + /// + /// Color space with 1 component. + /// Grayscale, + /// + /// Color space with 4 components. + /// Ycck, + /// + /// Color space with 4 components. + /// Cmyk, + /// + /// Color space with 3 components. + /// RGB, + /// + /// Color space with 3 components. + /// YCbCr } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 75d12710d2..5c2f453076 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -40,6 +40,55 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private ITestOutputHelper Output { get; } + [Fact] + public void GetConverterThrowsExceptionOnInvalidColorSpace() + { + Assert.Throws(() => JpegColorConverterBase.GetConverter(JpegColorSpace.Undefined, 8)); + } + + [Fact] + public void GetConverterThrowsExceptionOnInvalidPrecision() + { + // Valid precisions: 8 & 12 bit + Assert.Throws(() => JpegColorConverterBase.GetConverter(JpegColorSpace.YCbCr, 9)); + } + + [Theory] + [InlineData(JpegColorSpace.Grayscale, 8)] + [InlineData(JpegColorSpace.Grayscale, 12)] + [InlineData(JpegColorSpace.Ycck, 8)] + [InlineData(JpegColorSpace.Ycck, 12)] + [InlineData(JpegColorSpace.Cmyk, 8)] + [InlineData(JpegColorSpace.Cmyk, 12)] + [InlineData(JpegColorSpace.RGB, 8)] + [InlineData(JpegColorSpace.RGB, 12)] + [InlineData(JpegColorSpace.YCbCr, 8)] + [InlineData(JpegColorSpace.YCbCr, 12)] + internal void GetConverterReturnsValidConverter(JpegColorSpace colorSpace, int precision) + { + var converter = JpegColorConverterBase.GetConverter(colorSpace, precision); + + Assert.NotNull(converter); + Assert.Equal(colorSpace, converter.ColorSpace); + Assert.Equal(precision, converter.Precision); + } + + [Theory] + [InlineData(JpegColorSpace.Grayscale, 1)] + [InlineData(JpegColorSpace.Ycck, 4)] + [InlineData(JpegColorSpace.Cmyk, 4)] + [InlineData(JpegColorSpace.RGB, 3)] + [InlineData(JpegColorSpace.YCbCr, 3)] + internal void ConvertWithSelectedConverter(JpegColorSpace colorSpace, int componentCount) + { + ValidateConversion( + colorSpace, + componentCount, + 40, + 40, + 1); + } + [Theory] [MemberData(nameof(CommonConversionData))] public void FromYCbCrBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -96,18 +145,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCr_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.YCbCr, - 3, - inputBufferLength, - resultBufferLength, - seed); - } - [Theory] [MemberData(nameof(CommonConversionData))] public void FromCmykBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -164,18 +201,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromCmyk_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.Cmyk, - 4, - inputBufferLength, - resultBufferLength, - seed); - } - [Theory] [MemberData(nameof(CommonConversionData))] public void FromGrayscaleBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -232,18 +257,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromGraysacle_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.Grayscale, - 1, - inputBufferLength, - resultBufferLength, - seed); - } - [Theory] [MemberData(nameof(CommonConversionData))] public void FromRgbBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -300,18 +313,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromRgb_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.RGB, - 3, - inputBufferLength, - resultBufferLength, - seed); - } - [Theory] [MemberData(nameof(CommonConversionData))] public void FromYccKBasic(int inputBufferLength, int resultBufferLength, int seed) @@ -368,18 +369,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #endif - [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYcck_WithDefaultConverter(int inputBufferLength, int resultBufferLength, int seed) - { - ValidateConversion( - JpegColorSpace.Ycck, - 4, - inputBufferLength, - resultBufferLength, - seed); - } - private static JpegColorConverterBase.ComponentValues CreateRandomValues( int componentCount, int inputBufferLength, From 854b22e8f1d6ce61f9b23de5606ee24bd881dc55 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 12:04:00 +0300 Subject: [PATCH 10/25] Fixed tests --- .../Formats/Jpg/JpegColorConverterTests.cs | 130 ++++++------------ 1 file changed, 44 insertions(+), 86 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 5c2f453076..b34c8e9970 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -20,18 +20,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { private const float Precision = 0.1F / 255; - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(Precision); + private const int TestBufferLength = 40; - // int inputBufferLength, int resultBufferLength, int seed - public static readonly TheoryData CommonConversionData = - new TheoryData - { - { 40, 40, 1 }, - { 42, 40, 2 }, - { 42, 39, 3 } - }; + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(Precision); + + public static readonly TheoryData Seeds = new() { 1, 2, 3 }; - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorSpaceConverter ColorSpaceConverter = new(); public JpegColorConverterTests(ITestOutputHelper output) { @@ -84,26 +79,22 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( colorSpace, componentCount, - 40, - 40, 1); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCrBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYCbCrBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromYCbCrScalar(8), 3, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCrVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYCbCrVector(int seed) { var converter = new JpegColorConverterBase.FromYCbCrVector(8); @@ -117,15 +108,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 3, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYCbCrAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYCbCrAvx2(int seed) { var converter = new JpegColorConverterBase.FromYCbCrAvx(8); @@ -139,27 +128,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 3, - inputBufferLength, - resultBufferLength, seed); } #endif [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromCmykBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromCmykBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromCmykScalar(8), 4, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromCmykVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromCmykVector(int seed) { var converter = new JpegColorConverterBase.FromCmykVector(8); @@ -173,15 +158,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 4, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromCmykAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromCmykAvx2(int seed) { var converter = new JpegColorConverterBase.FromCmykAvx(8); @@ -195,27 +178,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 4, - inputBufferLength, - resultBufferLength, seed); } #endif [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromGrayscaleBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromGrayscaleBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromGrayscaleScalar(8), 1, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromGrayscaleVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromGrayscaleVector(int seed) { var converter = new JpegColorConverterBase.FromGrayScaleVector(8); @@ -229,15 +208,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 1, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromGrayscaleAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromGrayscaleAvx2(int seed) { var converter = new JpegColorConverterBase.FromGrayscaleAvx(8); @@ -251,27 +228,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 1, - inputBufferLength, - resultBufferLength, seed); } #endif [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromRgbBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromRgbBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromRgbScalar(8), 3, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromRgbVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromRgbVector(int seed) { var converter = new JpegColorConverterBase.FromRgbVector(8); @@ -285,15 +258,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 3, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromRgbAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromRgbAvx2(int seed) { var converter = new JpegColorConverterBase.FromRgbAvx(8); @@ -307,27 +278,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 3, - inputBufferLength, - resultBufferLength, seed); } #endif [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYccKBasic(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYccKBasic(int seed) { ValidateConversion( new JpegColorConverterBase.FromYccKScalar(8), 4, - inputBufferLength, - resultBufferLength, seed); } [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYccKVector(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYccKVector(int seed) { var converter = new JpegColorConverterBase.FromYccKVector(8); @@ -341,15 +308,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 4, - inputBufferLength, - resultBufferLength, seed); } #if SUPPORTS_RUNTIME_INTRINSICS [Theory] - [MemberData(nameof(CommonConversionData))] - public void FromYccKAvx2(int inputBufferLength, int resultBufferLength, int seed) + [MemberData(nameof(Seeds))] + public void FromYccKAvx2(int seed) { var converter = new JpegColorConverterBase.FromYccKAvx(8); @@ -363,27 +328,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, 4, - inputBufferLength, - resultBufferLength, seed); } #endif private static JpegColorConverterBase.ComponentValues CreateRandomValues( + int length, int componentCount, - int inputBufferLength, - int seed, - float minVal = 0f, - float maxVal = 255f) + int seed) { + const float minVal = 0f; + const float maxVal = Precision; + var rnd = new Random(seed); var buffers = new Buffer2D[componentCount]; for (int i = 0; i < componentCount; i++) { - var values = new float[inputBufferLength]; + float[] values = new float[length]; - for (int j = 0; j < inputBufferLength; j++) + for (int j = 0; j < values.Length; j++) { values[j] = ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; } @@ -400,31 +364,25 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateConversion( JpegColorSpace colorSpace, int componentCount, - int inputBufferLength, - int resultBufferLength, int seed) { ValidateConversion( JpegColorConverterBase.GetConverter(colorSpace, 8), componentCount, - inputBufferLength, - resultBufferLength, seed); } private static void ValidateConversion( JpegColorConverterBase converter, int componentCount, - int inputBufferLength, - int resultBufferLength, int seed) { - JpegColorConverterBase.ComponentValues original = CreateRandomValues(componentCount, inputBufferLength, seed); + JpegColorConverterBase.ComponentValues original = CreateRandomValues(TestBufferLength, componentCount, seed); JpegColorConverterBase.ComponentValues values = Copy(original); converter.ConvertToRgbInplace(values); - for (int i = 0; i < resultBufferLength; i++) + for (int i = 0; i < TestBufferLength; i++) { Validate(converter.ColorSpace, original, values, i); } From 9ec9b5a9876a3860286b48e0426c314014c988e5 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 12:26:28 +0300 Subject: [PATCH 11/25] Added avx/no-avx runs to every Vector API based test --- .../Formats/Jpg/JpegColorConverterTests.cs | 87 ++++++++++++------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index b34c8e9970..067f59aebf 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; using Xunit.Abstractions; @@ -64,6 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var converter = JpegColorConverterBase.GetConverter(colorSpace, precision); Assert.NotNull(converter); + Assert.True(converter.IsAvailable); Assert.Equal(colorSpace, converter.ColorSpace); Assert.Equal(precision, converter.Precision); } @@ -76,8 +77,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(JpegColorSpace.YCbCr, 3)] internal void ConvertWithSelectedConverter(JpegColorSpace colorSpace, int componentCount) { + var converter = JpegColorConverterBase.GetConverter(colorSpace, 8); ValidateConversion( - colorSpace, + converter, componentCount, 1); } @@ -105,10 +107,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 3, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromYCbCrVector(8), + 3, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -155,10 +163,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 4, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromCmykVector(8), + 4, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -205,10 +219,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 1, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromGrayScaleVector(8), + 1, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -255,10 +275,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 3, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromRgbVector(8), + 3, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -305,10 +331,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - ValidateConversion( - converter, - 4, - seed); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + seed, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + + static void RunTest(string arg) => + ValidateConversion( + new JpegColorConverterBase.FromYccKVector(8), + 4, + FeatureTestRunner.Deserialize(arg)); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -361,17 +393,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return new JpegColorConverterBase.ComponentValues(buffers, 0); } - private static void ValidateConversion( - JpegColorSpace colorSpace, - int componentCount, - int seed) - { - ValidateConversion( - JpegColorConverterBase.GetConverter(colorSpace, 8), - componentCount, - seed); - } - private static void ValidateConversion( JpegColorConverterBase converter, int componentCount, From ffd1ea8a3532c23ca63ec307ae0b4ef9f01dfaa2 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 2 Dec 2021 12:32:04 +0300 Subject: [PATCH 12/25] Fixed comments --- .../Decoder/ColorConverters/JpegColorConverterVector.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index 42f6cab5ca..c04591a289 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -40,8 +40,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters int simdCount = length - remainder; this.ConvertCoreVectorizedInplace(values.Slice(0, simdCount)); - // There's actually a lot of image/photo resolutions which won't have - // a remainder so it's better to check here than spend useless virtual call + // Jpeg images width is always divisible by 8 without a remainder + // so it's safe to say SSE/AVX implementations would never have + // 'remainder' pixels + // But some exotic simd implementations e.g. AVX-512 can have + // remainder pixels if (remainder > 0) { this.ConvertCoreInplace(values.Slice(simdCount, remainder)); From a26a758011713da068a24251111486808ba18050 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 07:24:24 +0300 Subject: [PATCH 13/25] Removed redundant allocations, fixed assertion & switch-case --- .../Formats/Jpg/JpegColorConverterTests.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 067f59aebf..3ebc137fad 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -399,7 +399,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg int seed) { JpegColorConverterBase.ComponentValues original = CreateRandomValues(TestBufferLength, componentCount, seed); - JpegColorConverterBase.ComponentValues values = Copy(original); + JpegColorConverterBase.ComponentValues values = new( + original.ComponentCount, + original.Component0, + original.Component1, + original.Component2, + original.Component3); converter.ConvertToRgbInplace(values); @@ -407,15 +412,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { Validate(converter.ColorSpace, original, values, i); } - - static JpegColorConverterBase.ComponentValues Copy(JpegColorConverterBase.ComponentValues values) - { - Span c0 = values.Component0.ToArray(); - Span c1 = values.ComponentCount > 1 ? values.Component1.ToArray().AsSpan() : c0; - Span c2 = values.ComponentCount > 2 ? values.Component2.ToArray().AsSpan() : c0; - Span c3 = values.ComponentCount > 3 ? values.Component3.ToArray().AsSpan() : Span.Empty; - return new JpegColorConverterBase.ComponentValues(values.ComponentCount, c0, c1, c2, c3); - } } private static void Validate( @@ -441,8 +437,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg case JpegColorSpace.YCbCr: ValidateYCbCr(original, result, i); break; + case JpegColorSpace.Undefined: default: - Assert.True(false, $"Colorspace {colorSpace} not supported!"); + Assert.True(false, $"Invalid Colorspace enum value: {colorSpace}."); break; } } From 5b62e94b26450fe5ad08813c61904f63a7681830 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 08:11:09 +0300 Subject: [PATCH 14/25] Minor fixes --- .../Decoder/ColorConverters/JpegColorConverterVector.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index c04591a289..523ac88960 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -26,14 +26,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public sealed override bool IsAvailable => Vector.Count % 4 == 0; + public sealed override bool IsAvailable => Vector.IsHardwareAccelerated && Vector.Count % 4 == 0; public override void ConvertToRgbInplace(in ComponentValues values) { - DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware"); + DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware."); int length = values.Component0.Length; - int remainder = values.Component0.Length % Vector.Count; + int remainder = length % Vector.Count; // Jpeg images are guaranteed to have pixel strides at least 8 pixels wide // Thus there's no need to check whether simdCount is greater than zero From 09b2e54c7184124c37bc5a70657002b7e97f7f07 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 08:34:54 +0300 Subject: [PATCH 15/25] More robust test failure output --- .../Formats/Jpg/JpegColorConverterTests.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 3ebc137fad..086ae30f3d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -454,7 +454,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = ColorSpaceConverter.ToRgb(ycbcr); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) @@ -479,7 +480,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(v.X, v.Y, v.Z); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } private static void ValidateRgb(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) @@ -491,7 +493,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(r / 255F, g / 255F, b / 255F); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) @@ -500,7 +503,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); var expected = new Rgb(y / 255F, y / 255F, y / 255F); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) @@ -523,7 +527,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); var expected = new Rgb(v.X, v.Y, v.Z); - Assert.Equal(expected, actual, ColorSpaceComparer); + bool equal = ColorSpaceComparer.Equals(expected, actual); + Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); } } } From 09d056e42b2b56d65a2a2bc80e4adb94d1d80341 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 15:42:18 +0300 Subject: [PATCH 16/25] Fixed test bug introduced in one of previous commits, code cleanup --- .../Formats/Jpg/JpegColorConverterTests.cs | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 086ae30f3d..2c6b293821 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -18,11 +18,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Trait("Format", "Jpg")] public class JpegColorConverterTests { + private static readonly float MaxColorChannelValue = 255f; + private const float Precision = 0.1F / 255; private const int TestBufferLength = 40; - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(Precision); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(epsilon: Precision); public static readonly TheoryData Seeds = new() { 1, 2, 3 }; @@ -369,9 +371,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg int componentCount, int seed) { - const float minVal = 0f; - const float maxVal = Precision; - var rnd = new Random(seed); var buffers = new Buffer2D[componentCount]; @@ -381,7 +380,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg for (int j = 0; j < values.Length; j++) { - values[j] = ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; + values[j] = (float)rnd.NextDouble() * MaxColorChannelValue; } // no need to dispose when buffer is not array owner @@ -401,10 +400,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg JpegColorConverterBase.ComponentValues original = CreateRandomValues(TestBufferLength, componentCount, seed); JpegColorConverterBase.ComponentValues values = new( original.ComponentCount, - original.Component0, - original.Component1, - original.Component2, - original.Component3); + original.Component0.ToArray(), + original.Component1.ToArray(), + original.Component2.ToArray(), + original.Component3.ToArray()); converter.ConvertToRgbInplace(values); @@ -449,10 +448,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg float y = values.Component0[i]; float cb = values.Component1[i]; float cr = values.Component2[i]; - var ycbcr = new YCbCr(y, cb, cr); - + var expected = ColorSpaceConverter.ToRgb(new YCbCr(y, cb, cr)); var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); - var expected = ColorSpaceConverter.ToRgb(ycbcr); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -460,8 +457,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - var v = new Vector4(0, 0, 0, 1F); - var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); + Vector4 v = Vector4.Zero; float y = values.Component0[i]; float cb = values.Component1[i] - 128F; @@ -475,10 +471,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg v.Z = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; v.W = 1F; - v *= scale; - - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + v /= new Vector4(MaxColorChannelValue, MaxColorChannelValue, MaxColorChannelValue, 1f); var expected = new Rgb(v.X, v.Y, v.Z); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -489,9 +484,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg float r = values.Component0[i]; float g = values.Component1[i]; float b = values.Component2[i]; - + var expected = new Rgb(new Vector3(r, g, b) / new Vector3(MaxColorChannelValue)); var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); - var expected = new Rgb(r / 255F, g / 255F, b / 255F); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -500,8 +494,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float y = values.Component0[i]; + var expected = new Rgb(new Vector3(y) / new Vector3(MaxColorChannelValue)); var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); - var expected = new Rgb(y / 255F, y / 255F, y / 255F); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -509,8 +503,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - var v = new Vector4(0, 0, 0, 1F); - var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); + Vector4 v = Vector4.Zero; float c = values.Component0[i]; float m = values.Component1[i]; @@ -522,10 +515,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg v.Z = y * k; v.W = 1F; - v *= scale; - - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + v /= new Vector4(MaxColorChannelValue, MaxColorChannelValue, MaxColorChannelValue, 1f); var expected = new Rgb(v.X, v.Y, v.Z); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); From f3b35e8acba740cec6687da4ba806507337d63e1 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 3 Dec 2021 16:42:21 +0300 Subject: [PATCH 17/25] Yet another 'fix' --- .../Formats/Jpg/JpegColorConverterTests.cs | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 2c6b293821..22af745251 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -449,6 +449,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg float cb = values.Component1[i]; float cr = values.Component2[i]; var expected = ColorSpaceConverter.ToRgb(new YCbCr(y, cb, cr)); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); @@ -469,10 +470,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero)) * k; v.Z = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; - v.W = 1F; - v /= new Vector4(MaxColorChannelValue, MaxColorChannelValue, MaxColorChannelValue, 1f); - var expected = new Rgb(v.X, v.Y, v.Z); + float r = v.X / MaxColorChannelValue; + float g = v.Y / MaxColorChannelValue; + float b = v.Z / MaxColorChannelValue; + var expected = new Rgb(r, g, b); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); @@ -481,10 +484,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateRgb(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - float r = values.Component0[i]; - float g = values.Component1[i]; - float b = values.Component2[i]; - var expected = new Rgb(new Vector3(r, g, b) / new Vector3(MaxColorChannelValue)); + float r = values.Component0[i] / MaxColorChannelValue; + float g = values.Component1[i] / MaxColorChannelValue; + float b = values.Component2[i] / MaxColorChannelValue; + var expected = new Rgb(r, g, b); + var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); @@ -493,8 +497,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - float y = values.Component0[i]; - var expected = new Rgb(new Vector3(y) / new Vector3(MaxColorChannelValue)); + float y = values.Component0[i] / MaxColorChannelValue; + var expected = new Rgb(y, y, y); + var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); @@ -510,13 +515,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg float y = values.Component2[i]; float k = values.Component3[i] / 255F; - v.X = c * k; - v.Y = m * k; - v.Z = y * k; - v.W = 1F; + float r = c * k / MaxColorChannelValue; + float g = m * k / MaxColorChannelValue; + float b = y * k / MaxColorChannelValue; + var expected = new Rgb(r, g, b); - v /= new Vector4(MaxColorChannelValue, MaxColorChannelValue, MaxColorChannelValue, 1f); - var expected = new Rgb(v.X, v.Y, v.Z); var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); bool equal = ColorSpaceComparer.Equals(expected, actual); From ca9ad91c020009a70ec4659c363a22f254f72b79 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 4 Dec 2021 16:04:16 +0300 Subject: [PATCH 18/25] Removed duplicated code, removed unused variables --- .../Formats/Jpg/JpegColorConverterTests.cs | 149 ++++-------------- 1 file changed, 34 insertions(+), 115 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 22af745251..f1e3684de4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -88,13 +88,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [MemberData(nameof(Seeds))] - public void FromYCbCrBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromYCbCrScalar(8), - 3, - seed); - } + public void FromYCbCrBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYCbCrScalar(8), 3, seed); [Theory] [MemberData(nameof(Seeds))] @@ -124,33 +119,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromYCbCrAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromYCbCrAvx(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - ValidateConversion( - converter, - 3, - seed); - } + public void FromYCbCrAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYCbCrAvx(8), 3, seed); #endif [Theory] [MemberData(nameof(Seeds))] - public void FromCmykBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromCmykScalar(8), - 4, - seed); - } + public void FromCmykBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromCmykScalar(8), 4, seed); [Theory] [MemberData(nameof(Seeds))] @@ -180,33 +156,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromCmykAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromCmykAvx(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - ValidateConversion( - converter, - 4, - seed); - } + public void FromCmykAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromCmykAvx(8), 4, seed); #endif [Theory] [MemberData(nameof(Seeds))] - public void FromGrayscaleBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromGrayscaleScalar(8), - 1, - seed); - } + public void FromGrayscaleBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromGrayscaleScalar(8), 1, seed); [Theory] [MemberData(nameof(Seeds))] @@ -236,33 +193,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromGrayscaleAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromGrayscaleAvx(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - ValidateConversion( - converter, - 1, - seed); - } + public void FromGrayscaleAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromGrayscaleAvx(8), 1, seed); #endif [Theory] [MemberData(nameof(Seeds))] - public void FromRgbBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromRgbScalar(8), - 3, - seed); - } + public void FromRgbBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromRgbScalar(8), 3, seed); [Theory] [MemberData(nameof(Seeds))] @@ -292,33 +230,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromRgbAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromRgbAvx(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - ValidateConversion( - converter, - 3, - seed); - } + public void FromRgbAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromRgbAvx(8), 3, seed); #endif [Theory] [MemberData(nameof(Seeds))] - public void FromYccKBasic(int seed) - { - ValidateConversion( - new JpegColorConverterBase.FromYccKScalar(8), - 4, - seed); - } + public void FromYccKBasic(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYccKScalar(8), 4, seed); [Theory] [MemberData(nameof(Seeds))] @@ -348,10 +267,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg #if SUPPORTS_RUNTIME_INTRINSICS [Theory] [MemberData(nameof(Seeds))] - public void FromYccKAvx2(int seed) - { - var converter = new JpegColorConverterBase.FromYccKAvx(8); + public void FromYccKAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYccKAvx(8), 4, seed); +#endif + private void TestConverter( + JpegColorConverterBase converter, + int componentCount, + int seed) + { if (!converter.IsAvailable) { this.Output.WriteLine( @@ -361,10 +285,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg ValidateConversion( converter, - 4, + componentCount, seed); } -#endif private static JpegColorConverterBase.ComponentValues CreateRandomValues( int length, @@ -458,22 +381,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateCyyK(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - Vector4 v = Vector4.Zero; - float y = values.Component0[i]; float cb = values.Component1[i] - 128F; float cr = values.Component2[i] - 128F; float k = values.Component3[i] / 255F; - v.X = (255F - (float)Math.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k; - v.Y = (255F - (float)Math.Round( + float r = (255F - (float)Math.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k; + float g = (255F - (float)Math.Round( y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero)) * k; - v.Z = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; + float b = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k; - float r = v.X / MaxColorChannelValue; - float g = v.Y / MaxColorChannelValue; - float b = v.Z / MaxColorChannelValue; + r /= MaxColorChannelValue; + g /= MaxColorChannelValue; + b /= MaxColorChannelValue; var expected = new Rgb(r, g, b); var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); @@ -508,12 +429,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private static void ValidateCmyk(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { - Vector4 v = Vector4.Zero; - float c = values.Component0[i]; float m = values.Component1[i]; float y = values.Component2[i]; - float k = values.Component3[i] / 255F; + float k = values.Component3[i] / MaxColorChannelValue; float r = c * k / MaxColorChannelValue; float g = m * k / MaxColorChannelValue; From ea2f5894eeae7afaf10a4c41ff734ac8dde7d587 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 4 Dec 2021 16:13:32 +0300 Subject: [PATCH 19/25] Renamings --- .../ColorConverters/JpegColorConverter.FromCmykAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromCmykScalar.cs | 2 +- .../ColorConverters/JpegColorConverter.FromCmykVector.cs | 2 +- .../ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs | 2 +- .../JpegColorConverter.FromGrayScaleScalar.cs | 2 +- .../JpegColorConverter.FromGrayScaleVector.cs | 2 +- .../ColorConverters/JpegColorConverter.FromRgbAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromRgbScalar.cs | 2 +- .../ColorConverters/JpegColorConverter.FromRgbVector.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrScalar.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrVector.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYccKAvx.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYccKScalar.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYccKVector.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverterAvx.cs | 4 ++-- .../Decoder/ColorConverters/JpegColorConverterScalar.cs | 4 ++-- .../Decoder/ColorConverters/JpegColorConverterVector.cs | 6 +++--- 18 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index d627f7eafd..7366ee30a9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykAvx : AvxColorConverter + internal sealed class FromCmykAvx : JpegColorConverterAvx { public FromCmykAvx(int precision) : base(JpegColorSpace.Cmyk, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs index e70aa7cb47..68dfa9bfba 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykScalar : ScalarJpegColorConverter + internal sealed class FromCmykScalar : JpegColorConverterScalar { public FromCmykScalar(int precision) : base(JpegColorSpace.Cmyk, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs index 8fd9181409..6b7ed169e3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromCmykVector : VectorizedJpegColorConverter + internal sealed class FromCmykVector : JpegColorConverterVector { public FromCmykVector(int precision) : base(JpegColorSpace.Cmyk, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs index fcfcaa2a98..963543ad44 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayscaleAvx : AvxColorConverter + internal sealed class FromGrayscaleAvx : JpegColorConverterAvx { public FromGrayscaleAvx(int precision) : base(JpegColorSpace.Grayscale, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs index 18ac5ff991..3f6a6caa45 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayscaleScalar : ScalarJpegColorConverter + internal sealed class FromGrayscaleScalar : JpegColorConverterScalar { public FromGrayscaleScalar(int precision) : base(JpegColorSpace.Grayscale, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs index 1ca329a12e..c484aac28d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromGrayScaleVector : VectorizedJpegColorConverter + internal sealed class FromGrayScaleVector : JpegColorConverterVector { public FromGrayScaleVector(int precision) : base(JpegColorSpace.Grayscale, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs index 83fbc369bc..f017716e3f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbAvx : AvxColorConverter + internal sealed class FromRgbAvx : JpegColorConverterAvx { public FromRgbAvx(int precision) : base(JpegColorSpace.RGB, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs index 83861d1e26..24c59206d8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs @@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbScalar : ScalarJpegColorConverter + internal sealed class FromRgbScalar : JpegColorConverterScalar { public FromRgbScalar(int precision) : base(JpegColorSpace.RGB, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs index b2b059cdc1..ff3a2bee19 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromRgbVector : VectorizedJpegColorConverter + internal sealed class FromRgbVector : JpegColorConverterVector { public FromRgbVector(int precision) : base(JpegColorSpace.RGB, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs index adf6e8e0f6..892bcc79e1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrAvx : AvxColorConverter + internal sealed class FromYCbCrAvx : JpegColorConverterAvx { public FromYCbCrAvx(int precision) : base(JpegColorSpace.YCbCr, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs index 73c73970d0..4b6d88f725 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrScalar : ScalarJpegColorConverter + internal sealed class FromYCbCrScalar : JpegColorConverterScalar { // TODO: comments, derived from ITU-T Rec. T.871 internal const float RCrMult = 1.402f; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs index f340143321..48e311d995 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYCbCrVector : VectorizedJpegColorConverter + internal sealed class FromYCbCrVector : JpegColorConverterVector { public FromYCbCrVector(int precision) : base(JpegColorSpace.YCbCr, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs index 86528c74d5..1f18d5324d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKAvx : AvxColorConverter + internal sealed class FromYccKAvx : JpegColorConverterAvx { public FromYccKAvx(int precision) : base(JpegColorSpace.Ycck, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs index 4657e50cf9..d6387ae714 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKScalar : ScalarJpegColorConverter + internal sealed class FromYccKScalar : JpegColorConverterScalar { public FromYccKScalar(int precision) : base(JpegColorSpace.Ycck, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs index 1e826c2c08..66c79ae7c8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverterBase { - internal sealed class FromYccKVector : VectorizedJpegColorConverter + internal sealed class FromYccKVector : JpegColorConverterVector { public FromYccKVector(int precision) : base(JpegColorSpace.Ycck, precision) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs index 559422273e..81c7c0764d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs @@ -18,9 +18,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// DO NOT pass test data of invalid size to these converters as they /// potentially won't do a bound check and return a false positive result. /// - internal abstract class AvxColorConverter : JpegColorConverterBase + internal abstract class JpegColorConverterAvx : JpegColorConverterBase { - protected AvxColorConverter(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterAvx(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs index 76134d490c..ff88ab969f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterScalar.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// abstract base for implementations /// based on scalar instructions. /// - internal abstract class ScalarJpegColorConverter : JpegColorConverterBase + internal abstract class JpegColorConverterScalar : JpegColorConverterBase { - protected ScalarJpegColorConverter(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterScalar(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs index 523ac88960..ca482d78df 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterVector.cs @@ -19,9 +19,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// such data out of the box. These converters have fallback code /// for 'remainder' data. /// - internal abstract class VectorizedJpegColorConverter : JpegColorConverterBase + internal abstract class JpegColorConverterVector : JpegColorConverterBase { - protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterVector(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { } @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware."); int length = values.Component0.Length; - int remainder = length % Vector.Count; + int remainder = (int)((uint)length % (uint)Vector.Count); // Jpeg images are guaranteed to have pixel strides at least 8 pixels wide // Thus there's no need to check whether simdCount is greater than zero From 364bbbb5f79038848d78b13b07ee7e56d6619c36 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 11 Dec 2021 09:33:37 +0300 Subject: [PATCH 20/25] Fixed old runtimes remote executor tests --- shared-infrastructure | 2 +- .../Formats/Jpg/JpegColorConverterTests.cs | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/shared-infrastructure b/shared-infrastructure index a042aba176..59ce17f5a4 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 +Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836 diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index f1e3684de4..a5414ba1d2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -24,12 +24,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private const int TestBufferLength = 40; - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(epsilon: Precision); +#if SUPPORTS_RUNTIME_INTRINSICS + private static readonly HwIntrinsics IntrinsicsConfig = HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX; +#else + private static readonly HwIntrinsics IntrinsicsConfig = HwIntrinsics.AllowAll; +#endif - public static readonly TheoryData Seeds = new() { 1, 2, 3 }; + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(epsilon: Precision); private static readonly ColorSpaceConverter ColorSpaceConverter = new(); + public static readonly TheoryData Seeds = new() { 1, 2, 3 }; + public JpegColorConverterTests(ITestOutputHelper output) { this.Output = output; @@ -107,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( @@ -144,7 +150,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( @@ -181,7 +187,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( @@ -218,7 +224,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( @@ -255,7 +261,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); + IntrinsicsConfig); static void RunTest(string arg) => ValidateConversion( From 7a9357c1166d401377293d905c5a5a9e02d3269c Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 11 Dec 2021 09:36:51 +0300 Subject: [PATCH 21/25] Small qol fixes --- .../Formats/Jpg/JpegColorConverterTests.cs | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index a5414ba1d2..91f87610e2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Trait("Format", "Jpg")] public class JpegColorConverterTests { - private static readonly float MaxColorChannelValue = 255f; + private const float MaxColorChannelValue = 255f; private const float Precision = 0.1F / 255; @@ -122,13 +122,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.Deserialize(arg)); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Theory] - [MemberData(nameof(Seeds))] - public void FromYCbCrAvx2(int seed) => - this.TestConverter(new JpegColorConverterBase.FromYCbCrAvx(8), 3, seed); -#endif - [Theory] [MemberData(nameof(Seeds))] public void FromCmykBasic(int seed) => @@ -159,13 +152,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.Deserialize(arg)); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Theory] - [MemberData(nameof(Seeds))] - public void FromCmykAvx2(int seed) => - this.TestConverter(new JpegColorConverterBase.FromCmykAvx(8), 4, seed); -#endif - [Theory] [MemberData(nameof(Seeds))] public void FromGrayscaleBasic(int seed) => @@ -196,13 +182,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.Deserialize(arg)); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Theory] - [MemberData(nameof(Seeds))] - public void FromGrayscaleAvx2(int seed) => - this.TestConverter(new JpegColorConverterBase.FromGrayscaleAvx(8), 1, seed); -#endif - [Theory] [MemberData(nameof(Seeds))] public void FromRgbBasic(int seed) => @@ -233,13 +212,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FeatureTestRunner.Deserialize(arg)); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Theory] - [MemberData(nameof(Seeds))] - public void FromRgbAvx2(int seed) => - this.TestConverter(new JpegColorConverterBase.FromRgbAvx(8), 3, seed); -#endif - [Theory] [MemberData(nameof(Seeds))] public void FromYccKBasic(int seed) => @@ -271,6 +243,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } #if SUPPORTS_RUNTIME_INTRINSICS + [Theory] + [MemberData(nameof(Seeds))] + public void FromYCbCrAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromYCbCrAvx(8), 3, seed); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromCmykAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromCmykAvx(8), 4, seed); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromGrayscaleAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromGrayscaleAvx(8), 1, seed); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromRgbAvx2(int seed) => + this.TestConverter(new JpegColorConverterBase.FromRgbAvx(8), 3, seed); + [Theory] [MemberData(nameof(Seeds))] public void FromYccKAvx2(int seed) => From 816c754657acfea4d6f8a381da0a714819d82716 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 11 Dec 2021 09:38:00 +0300 Subject: [PATCH 22/25] Removed obsolete Vector4Pair --- src/ImageSharp/Common/Tuples/Vector4Pair.cs | 82 --------------------- 1 file changed, 82 deletions(-) delete mode 100644 src/ImageSharp/Common/Tuples/Vector4Pair.cs diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs deleted file mode 100644 index 6294a61775..0000000000 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Tuples -{ - /// - /// Its faster to process multiple Vector4-s together, so let's pair them! - /// On AVX2 this pair should be convertible to of ! - /// TODO: Investigate defining this as union with an Octet.OfSingle type. - /// - [StructLayout(LayoutKind.Sequential)] - internal struct Vector4Pair - { - public Vector4 A; - - public Vector4 B; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void MultiplyInplace(float value) - { - this.A *= value; - this.B *= value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddInplace(Vector4 value) - { - this.A += value; - this.B += value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddInplace(ref Vector4Pair other) - { - this.A += other.A; - this.B += other.B; - } - - /// . - /// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4! /// TODO: Move it somewhere else. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void RoundAndDownscalePreVector8(float downscaleFactor) - { - ref Vector a = ref Unsafe.As>(ref this.A); - a = a.FastRound(); - - ref Vector b = ref Unsafe.As>(ref this.B); - b = b.FastRound(); - - // Downscale by 1/factor - var scale = new Vector4(1 / downscaleFactor); - this.A *= scale; - this.B *= scale; - } - - /// - /// AVX2-only Downscale method, specific to Jpeg color conversion. - /// TODO: Move it somewhere else. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void RoundAndDownscaleVector8(float downscaleFactor) - { - ref Vector self = ref Unsafe.As>(ref this); - Vector v = self; - v = v.FastRound(); - - // Downscale by 1/factor - v *= new Vector(1 / downscaleFactor); - self = v; - } - - public override string ToString() - { - return $"{nameof(Vector4Pair)}({this.A}, {this.B})"; - } - } -} From 21cf5b42c17e59147db51abeaa7b90672d69d339 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 11 Dec 2021 09:56:49 +0300 Subject: [PATCH 23/25] Fixed merging errors --- .../ColorConverters/JpegColorConverterBase.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs index 5537113a35..808ca687b4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs @@ -206,12 +206,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters this.ComponentCount = componentBuffers.Count; - this.Component0 = componentBuffers[0].GetRowSpan(row); + this.Component0 = componentBuffers[0].DangerousGetRowSpan(row); // In case of grayscale, Component1 and Component2 point to Component0 memory area - this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].GetRowSpan(row) : this.Component0; - this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].GetRowSpan(row) : this.Component0; - this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].GetRowSpan(row) : Span.Empty; + this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].DangerousGetRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].DangerousGetRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].DangerousGetRowSpan(row) : Span.Empty; } /// @@ -223,12 +223,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { DebugGuard.MustBeGreaterThan(processors.Count, 0, nameof(processors)); - this.Component0 = componentBuffers[0].DangerousGetRowSpan(row); + this.ComponentCount = processors.Count; + + this.Component0 = processors[0].GetColorBufferRowSpan(row); // In case of grayscale, Component1 and Component2 point to Component0 memory area - this.Component1 = this.ComponentCount > 1 ? componentBuffers[1].DangerousGetRowSpan(row) : this.Component0; - this.Component2 = this.ComponentCount > 2 ? componentBuffers[2].DangerousGetRowSpan(row) : this.Component0; - this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].DangerousGetRowSpan(row) : Span.Empty; + this.Component1 = this.ComponentCount > 1 ? processors[1].GetColorBufferRowSpan(row) : this.Component0; + this.Component2 = this.ComponentCount > 2 ? processors[2].GetColorBufferRowSpan(row) : this.Component0; + this.Component3 = this.ComponentCount > 3 ? processors[3].GetColorBufferRowSpan(row) : Span.Empty; } internal ComponentValues( From d7ff98b19b08640c3c4e8dccc858ce397c4d3f26 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 12 Dec 2021 14:29:12 +0100 Subject: [PATCH 24/25] Add ActiveIssue attribute to AllocateMemoryGroup_Finalization_ReturnsToPool test --- .../Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index c4bb03d020..13bf98b502 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -253,6 +253,7 @@ namespace SixLabors.ImageSharp.Tests.Memory.Allocators } } + [ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1887", TestPlatforms.OSX)] [Theory] [InlineData(300)] // Group of single SharedArrayPoolBuffer [InlineData(600)] // Group of single UniformUnmanagedMemoryPool buffer From bae4feef1b915a65bec3fb8542a349c9bced454b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 12 Dec 2021 14:51:31 +0100 Subject: [PATCH 25/25] Change skipping tests on OSX --- .../UniformUnmanagedPoolMemoryAllocatorTests.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index 13bf98b502..45a7cc278e 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -253,13 +253,18 @@ namespace SixLabors.ImageSharp.Tests.Memory.Allocators } } - [ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1887", TestPlatforms.OSX)] [Theory] [InlineData(300)] // Group of single SharedArrayPoolBuffer [InlineData(600)] // Group of single UniformUnmanagedMemoryPool buffer [InlineData(1200)] // Group of two UniformUnmanagedMemoryPool buffers public void AllocateMemoryGroup_Finalization_ReturnsToPool(int length) { + if (TestEnvironment.IsOSX) + { + // Skip on OSX: https://github.com/SixLabors/ImageSharp/issues/1887 + return; + } + if (!TestEnvironment.RunsOnCI) { // This may fail in local runs resulting in high memory load. @@ -311,12 +316,17 @@ namespace SixLabors.ImageSharp.Tests.Memory.Allocators } } - [ActiveIssue("https://github.com/SixLabors/ImageSharp/issues/1887", TestPlatforms.OSX)] [Theory] [InlineData(300)] // Group of single SharedArrayPoolBuffer [InlineData(600)] // Group of single UniformUnmanagedMemoryPool buffer public void AllocateSingleMemoryOwner_Finalization_ReturnsToPool(int length) { + if (TestEnvironment.IsOSX) + { + // Skip on OSX: https://github.com/SixLabors/ImageSharp/issues/1887 + return; + } + if (!TestEnvironment.RunsOnCI) { // This may fail in local runs resulting in high memory load.