diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 17ccb396d..a0733b660 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -616,35 +616,7 @@ internal static partial class SimdUtils return Fma.MultiplyAdd(vm1, vm0, va); } - return Avx.Add(Avx.Multiply(vm0, vm1), va); - } - - /// - /// Performs a multiplication and an addition of the . - /// TODO: Fix. The arguments are in a different order to the FMA intrinsic. - /// - /// ret = (vm0 * vm1) + va - /// The vector to add to the intermediate result. - /// The first vector to multiply. - /// The second vector to multiply. - /// The . - [MethodImpl(InliningOptions.AlwaysInline)] - public static Vector128 MultiplyAdd( - Vector128 va, - Vector128 vm0, - Vector128 vm1) - { - if (Fma.IsSupported) - { - return Fma.MultiplyAdd(vm1, vm0, va); - } - - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(AdvSimd.Multiply(vm0, vm1), va); - } - - return Sse.Add(Sse.Multiply(vm0, vm1), va); + return va + (vm0 * vm1); } /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 0279e57cc..7f98c8375 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -1,11 +1,11 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp; @@ -36,30 +36,39 @@ internal static partial class SimdUtils /// /// Rounds all values in 'v' to the nearest integer following semantics. - /// Source: - /// - /// https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110 - /// /// /// The vector [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector FastRound(this Vector v) { - if (Avx2.IsSupported) + // .NET9+ has a built-in method for this Vector.Round + if (Avx2.IsSupported && Vector.Count == Vector256.Count) { ref Vector256 v256 = ref Unsafe.As, Vector256>(ref v); Vector256 vRound = Avx.RoundToNearestInteger(v256); return Unsafe.As, Vector>(ref vRound); } - else + + if (Sse41.IsSupported && Vector.Count == Vector128.Count) + { + ref Vector128 v128 = ref Unsafe.As, Vector128>(ref v); + Vector128 vRound = Sse41.RoundToNearestInteger(v128); + return Unsafe.As, Vector>(ref vRound); + } + + if (AdvSimd.IsSupported && Vector.Count == Vector128.Count) { - var magic0 = new Vector(int.MinValue); // 0x80000000 - var sgn0 = Vector.AsVectorSingle(magic0); - var and0 = Vector.BitwiseAnd(sgn0, v); - var or0 = Vector.BitwiseOr(and0, new Vector(8388608.0f)); - var add0 = Vector.Add(v, or0); - return Vector.Subtract(add0, or0); + ref Vector128 v128 = ref Unsafe.As, Vector128>(ref v); + Vector128 vRound = AdvSimd.RoundToNearest(v128); + return Unsafe.As, Vector>(ref vRound); } + + // https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L11 + Vector sign = v & new Vector(-0F); + Vector val_2p23_f32 = sign | new Vector(8388608F); + + val_2p23_f32 = (v + val_2p23_f32) - val_2p23_f32; + return val_2p23_f32 | sign; } [Conditional("DEBUG")] diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs index b6dd319f0..765737906 100644 --- a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -193,13 +193,65 @@ internal static class Vector128Utilities return AdvSimd.ConvertToInt32RoundToEven(vector); } - Vector128 sign = vector & Vector128.Create(-0.0f); - Vector128 val_2p23_f32 = sign | Vector128.Create(8388608.0f); + Vector128 sign = vector & Vector128.Create(-0F); + Vector128 val_2p23_f32 = sign | Vector128.Create(8388608F); val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; return Vector128.ConvertToInt32(val_2p23_f32 | sign); } + /// + /// Rounds all values in to the nearest integer + /// following semantics. + /// + /// The vector + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 RoundToNearestInteger(Vector128 vector) + { + if (Sse41.IsSupported) + { + return Sse41.RoundToNearestInteger(vector); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.RoundToNearest(vector); + } + + Vector128 sign = vector & Vector128.Create(-0F); + Vector128 val_2p23_f32 = sign | Vector128.Create(8388608F); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return val_2p23_f32 | sign; + } + + /// + /// Performs a multiplication and an addition of the . + /// + /// ret = (vm0 * vm1) + va + /// The vector to add to the intermediate result. + /// The first vector to multiply. + /// The second vector to multiply. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MultiplyAdd( + Vector128 va, + Vector128 vm0, + Vector128 vm1) + { + if (Fma.IsSupported) + { + return Fma.MultiplyAdd(vm1, vm0, va); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.FusedMultiplyAdd(va, vm0, vm1); + } + + return va + (vm0 * vm1); + } + /// /// Packs signed 16-bit integers to unsigned 8-bit integers and saturates. /// diff --git a/src/ImageSharp/Common/Helpers/Vector256Utilities.cs b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs index 6e8c0d1de..4c12cb272 100644 --- a/src/ImageSharp/Common/Helpers/Vector256Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs @@ -103,13 +103,55 @@ internal static class Vector256Utilities return Vector256.Create(lower, upper); } - Vector256 sign = vector & Vector256.Create(-0.0f); - Vector256 val_2p23_f32 = sign | Vector256.Create(8388608.0f); + Vector256 sign = vector & Vector256.Create(-0F); + Vector256 val_2p23_f32 = sign | Vector256.Create(8388608F); val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; return Vector256.ConvertToInt32(val_2p23_f32 | sign); } + /// + /// Rounds all values in to the nearest integer + /// following semantics. + /// + /// The vector + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 RoundToNearestInteger(Vector256 vector) + { + if (Avx.IsSupported) + { + return Avx.RoundToNearestInteger(vector); + } + + Vector256 sign = vector & Vector256.Create(-0F); + Vector256 val_2p23_f32 = sign | Vector256.Create(8388608F); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return val_2p23_f32 | sign; + } + + /// + /// Performs a multiplication and an addition of the . + /// + /// ret = (vm0 * vm1) + va + /// The vector to add to the intermediate result. + /// The first vector to multiply. + /// The second vector to multiply. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MultiplyAdd( + Vector256 va, + Vector256 vm0, + Vector256 vm1) + { + if (Fma.IsSupported) + { + return Fma.MultiplyAdd(vm0, vm1, va); + } + + return va + (vm0 * vm1); + } + [DoesNotReturn] private static void ThrowUnreachableException() => throw new UnreachableException(); } diff --git a/src/ImageSharp/Common/Helpers/Vector512Utilities.cs b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs index 0165af90e..40e8ac344 100644 --- a/src/ImageSharp/Common/Helpers/Vector512Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs @@ -110,6 +110,51 @@ internal static class Vector512Utilities return Vector512.ConvertToInt32(val_2p23_f32 | sign); } + /// + /// Rounds all values in to the nearest integer + /// following semantics. + /// + /// The vector + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 RoundToNearestInteger(Vector512 vector) + { + if (Avx512F.IsSupported) + { + // imm8 = 0b1000: + // imm8[7:4] = 0b0000 -> preserve 0 fractional bits (round to whole numbers) + // imm8[3:0] = 0b1000 -> _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC (round to nearest even, suppress exceptions) + return Avx512F.RoundScale(vector, 0b0000_1000); + } + + Vector512 sign = vector & Vector512.Create(-0F); + Vector512 val_2p23_f32 = sign | Vector512.Create(8388608F); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return val_2p23_f32 | sign; + } + + /// + /// Performs a multiplication and an addition of the . + /// + /// ret = (vm0 * vm1) + va + /// The vector to add to the intermediate result. + /// The first vector to multiply. + /// The second vector to multiply. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MultiplyAdd( + Vector512 va, + Vector512 vm0, + Vector512 vm1) + { + if (Avx512F.IsSupported) + { + return Avx512F.FusedMultiplyAdd(vm0, vm1, va); + } + + return va + (vm0 * vm1); + } + [DoesNotReturn] private static void ThrowUnreachableException() => throw new UnreachableException(); } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykScalar.cs index 6d0013b88..380d3d6cc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykScalar.cs @@ -13,14 +13,14 @@ internal abstract partial class JpegColorConverterBase } /// - public override void ConvertToRgbInplace(in ComponentValues values) => - ConvertToRgbInplace(values, this.MaximumValue); + public override void ConvertToRgbInPlace(in ComponentValues values) => + ConvertToRgbInPlace(values, this.MaximumValue); /// - public override void ConvertFromRgb(in ComponentValues values, Span r, Span g, Span b) - => ConvertFromRgb(values, this.MaximumValue, r, g, b); + public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => ConvertFromRgb(values, this.MaximumValue, rLane, gLane, bLane); - public static void ConvertToRgbInplace(in ComponentValues values, float maxValue) + public static void ConvertToRgbInPlace(in ComponentValues values, float maxValue) { Span c0 = values.Component0; Span c1 = values.Component1; @@ -42,7 +42,7 @@ internal abstract partial class JpegColorConverterBase } } - public static void ConvertFromRgb(in ComponentValues values, float maxValue, Span r, Span g, Span b) + public static void ConvertFromRgb(in ComponentValues values, float maxValue, Span rLane, Span gLane, Span bLane) { Span c = values.Component0; Span m = values.Component1; @@ -51,9 +51,9 @@ internal abstract partial class JpegColorConverterBase for (int i = 0; i < c.Length; i++) { - float ctmp = 255f - r[i]; - float mtmp = 255f - g[i]; - float ytmp = 255f - b[i]; + float ctmp = 255f - rLane[i]; + float mtmp = 255f - gLane[i]; + float ytmp = 255f - bLane[i]; float ktmp = MathF.Min(MathF.Min(ctmp, mtmp), ytmp); if (ktmp >= 255f) diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector.cs deleted file mode 100644 index a59be009b..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components; - -internal abstract partial class JpegColorConverterBase -{ - internal sealed class CmykVector : JpegColorConverterVector - { - public CmykVector(int precision) - : base(JpegColorSpace.Cmyk, precision) - { - } - - /// - protected override void ConvertToRgbInplaceVectorized(in ComponentValues values) - { - ref Vector cBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector mBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector yBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector kBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - - var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue)); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - 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); - - k *= scale; - c *= k; - m *= k; - y *= k; - } - } - - /// - protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values) - => CmykScalar.ConvertToRgbInplace(values, this.MaximumValue); - - /// - protected override void ConvertFromRgbVectorized(in ComponentValues values, Span r, Span g, Span b) - => ConvertFromRgbInplaceVectorized(in values, this.MaximumValue, r, g, b); - - /// - protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span r, Span g, Span b) - => ConvertFromRgbInplaceRemainder(values, this.MaximumValue, r, g, b); - - public static void ConvertFromRgbInplaceVectorized(in ComponentValues values, float maxValue, Span r, Span g, Span b) - { - ref Vector destC = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector destM = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector destY = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector destK = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - - ref Vector srcR = - ref Unsafe.As>(ref MemoryMarshal.GetReference(r)); - ref Vector srcG = - ref Unsafe.As>(ref MemoryMarshal.GetReference(g)); - ref Vector srcB = - ref Unsafe.As>(ref MemoryMarshal.GetReference(b)); - - // Used for the color conversion - var scale = new Vector(maxValue); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - Vector ctmp = scale - Unsafe.Add(ref srcR, i); - Vector mtmp = scale - Unsafe.Add(ref srcG, i); - Vector ytmp = scale - Unsafe.Add(ref srcB, i); - Vector ktmp = Vector.Min(ctmp, Vector.Min(mtmp, ytmp)); - - var kMask = Vector.Equals(ktmp, scale); - ctmp = Vector.AndNot((ctmp - ktmp) / (scale - ktmp), kMask.As()); - mtmp = Vector.AndNot((mtmp - ktmp) / (scale - ktmp), kMask.As()); - ytmp = Vector.AndNot((ytmp - ktmp) / (scale - ktmp), kMask.As()); - - Unsafe.Add(ref destC, i) = scale - (ctmp * scale); - Unsafe.Add(ref destM, i) = scale - (mtmp * scale); - Unsafe.Add(ref destY, i) = scale - (ytmp * scale); - Unsafe.Add(ref destK, i) = scale - ktmp; - } - } - - public static void ConvertFromRgbInplaceRemainder(in ComponentValues values, float maxValue, Span r, Span g, Span b) - => CmykScalar.ConvertFromRgb(values, maxValue, r, g, b); - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykArm64.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector128.cs similarity index 58% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykArm64.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector128.cs index 11122d3b8..0a935cca4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykArm64.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector128.cs @@ -1,24 +1,23 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class CmykArm64 : JpegColorConverterArm64 + internal sealed class CmykVector128 : JpegColorConverterVector128 { - public CmykArm64(int precision) + public CmykVector128(int precision) : base(JpegColorSpace.Cmyk, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector128 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -30,20 +29,20 @@ internal abstract partial class JpegColorConverterBase ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); // Used for the color conversion - var scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue)); + Vector128 scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue)); - nint n = (nint)(uint)values.Component0.Length / Vector128.Count; - for (nint i = 0; i < n; i++) + nuint n = values.Component0.Vector128Count(); + for (nuint i = 0; i < n; i++) { ref Vector128 c = ref Unsafe.Add(ref c0Base, i); ref Vector128 m = ref Unsafe.Add(ref c1Base, i); ref Vector128 y = ref Unsafe.Add(ref c2Base, i); Vector128 k = Unsafe.Add(ref c3Base, i); - k = AdvSimd.Multiply(k, scale); - c = AdvSimd.Multiply(c, k); - m = AdvSimd.Multiply(m, k); - y = AdvSimd.Multiply(y, k); + k *= scale; + c *= k; + m *= k; + y *= k; } } @@ -69,26 +68,27 @@ internal abstract partial class JpegColorConverterBase ref Vector128 srcB = ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); - var scale = Vector128.Create(maxValue); + Vector128 scale = Vector128.Create(maxValue); - nint n = (nint)(uint)values.Component0.Length / Vector128.Count; - for (nint i = 0; i < n; i++) + nuint n = values.Component0.Vector128Count(); + for (nuint i = 0; i < n; i++) { - Vector128 ctmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcR, i)); - Vector128 mtmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcG, i)); - Vector128 ytmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcB, i)); - Vector128 ktmp = AdvSimd.Min(ctmp, AdvSimd.Min(mtmp, ytmp)); + Vector128 ctmp = scale - Unsafe.Add(ref srcR, i); + Vector128 mtmp = scale - Unsafe.Add(ref srcG, i); + Vector128 ytmp = scale - Unsafe.Add(ref srcB, i); + Vector128 ktmp = Vector128.Min(ctmp, Vector128.Min(mtmp, ytmp)); - Vector128 kMask = AdvSimd.Not(AdvSimd.CompareEqual(ktmp, scale)); + Vector128 kMask = ~Vector128.Equals(ktmp, scale); + Vector128 divisor = scale - ktmp; - ctmp = AdvSimd.And(AdvSimd.Arm64.Divide(AdvSimd.Subtract(ctmp, ktmp), AdvSimd.Subtract(scale, ktmp)), kMask); - mtmp = AdvSimd.And(AdvSimd.Arm64.Divide(AdvSimd.Subtract(mtmp, ktmp), AdvSimd.Subtract(scale, ktmp)), kMask); - ytmp = AdvSimd.And(AdvSimd.Arm64.Divide(AdvSimd.Subtract(ytmp, ktmp), AdvSimd.Subtract(scale, ktmp)), kMask); + ctmp = ((ctmp - ktmp) / divisor) & kMask; + mtmp = ((mtmp - ktmp) / divisor) & kMask; + ytmp = ((ytmp - ktmp) / divisor) & kMask; - Unsafe.Add(ref destC, i) = AdvSimd.Subtract(scale, AdvSimd.Multiply(ctmp, scale)); - Unsafe.Add(ref destM, i) = AdvSimd.Subtract(scale, AdvSimd.Multiply(mtmp, scale)); - Unsafe.Add(ref destY, i) = AdvSimd.Subtract(scale, AdvSimd.Multiply(ytmp, scale)); - Unsafe.Add(ref destK, i) = AdvSimd.Subtract(scale, ktmp); + Unsafe.Add(ref destC, i) = scale - (ctmp * scale); + Unsafe.Add(ref destM, i) = scale - (mtmp * scale); + Unsafe.Add(ref destY, i) = scale - (ytmp * scale); + Unsafe.Add(ref destK, i) = scale - ktmp; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector256.cs similarity index 65% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykAvx.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector256.cs index 76d188f45..3cef262ec 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector256.cs @@ -1,24 +1,23 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class CmykAvx : JpegColorConverterAvx + internal sealed class CmykVector256 : JpegColorConverterVector256 { - public CmykAvx(int precision) + public CmykVector256(int precision) : base(JpegColorSpace.Cmyk, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -30,7 +29,7 @@ internal abstract partial class JpegColorConverterBase ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); // Used for the color conversion - var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); + Vector256 scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); nuint n = values.Component0.Vector256Count(); for (nuint i = 0; i < n; i++) @@ -40,10 +39,10 @@ internal abstract partial class JpegColorConverterBase ref Vector256 y = ref Unsafe.Add(ref c2Base, i); Vector256 k = Unsafe.Add(ref c3Base, i); - k = Avx.Multiply(k, scale); - c = Avx.Multiply(c, k); - m = Avx.Multiply(m, k); - y = Avx.Multiply(y, k); + k *= scale; + c *= k; + m *= k; + y *= k; } } @@ -69,26 +68,27 @@ internal abstract partial class JpegColorConverterBase ref Vector256 srcB = ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); - var scale = Vector256.Create(maxValue); + Vector256 scale = Vector256.Create(maxValue); nuint n = values.Component0.Vector256Count(); for (nuint i = 0; i < n; i++) { - Vector256 ctmp = Avx.Subtract(scale, Unsafe.Add(ref srcR, i)); - Vector256 mtmp = Avx.Subtract(scale, Unsafe.Add(ref srcG, i)); - Vector256 ytmp = Avx.Subtract(scale, Unsafe.Add(ref srcB, i)); - Vector256 ktmp = Avx.Min(ctmp, Avx.Min(mtmp, ytmp)); + Vector256 ctmp = scale - Unsafe.Add(ref srcR, i); + Vector256 mtmp = scale - Unsafe.Add(ref srcG, i); + Vector256 ytmp = scale - Unsafe.Add(ref srcB, i); + Vector256 ktmp = Vector256.Min(ctmp, Vector256.Min(mtmp, ytmp)); - Vector256 kMask = Avx.CompareNotEqual(ktmp, scale); + Vector256 kMask = ~Vector256.Equals(ktmp, scale); + Vector256 divisor = scale - ktmp; - ctmp = Avx.And(Avx.Divide(Avx.Subtract(ctmp, ktmp), Avx.Subtract(scale, ktmp)), kMask); - mtmp = Avx.And(Avx.Divide(Avx.Subtract(mtmp, ktmp), Avx.Subtract(scale, ktmp)), kMask); - ytmp = Avx.And(Avx.Divide(Avx.Subtract(ytmp, ktmp), Avx.Subtract(scale, ktmp)), kMask); + ctmp = ((ctmp - ktmp) / divisor) & kMask; + mtmp = ((mtmp - ktmp) / divisor) & kMask; + ytmp = ((ytmp - ktmp) / divisor) & kMask; - Unsafe.Add(ref destC, i) = Avx.Subtract(scale, Avx.Multiply(ctmp, scale)); - Unsafe.Add(ref destM, i) = Avx.Subtract(scale, Avx.Multiply(mtmp, scale)); - Unsafe.Add(ref destY, i) = Avx.Subtract(scale, Avx.Multiply(ytmp, scale)); - Unsafe.Add(ref destK, i) = Avx.Subtract(scale, ktmp); + Unsafe.Add(ref destC, i) = scale - (ctmp * scale); + Unsafe.Add(ref destM, i) = scale - (mtmp * scale); + Unsafe.Add(ref destY, i) = scale - (ytmp * scale); + Unsafe.Add(ref destK, i) = scale - ktmp; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector512.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector512.cs new file mode 100644 index 000000000..f57ad4352 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector512.cs @@ -0,0 +1,103 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components; + +internal abstract partial class JpegColorConverterBase +{ + internal sealed class CmykVector512 : JpegColorConverterVector512 + { + public CmykVector512(int precision) + : base(JpegColorSpace.Cmyk, precision) + { + } + + /// + protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values) + { + ref Vector512 c0Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector512 c1Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector512 c2Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Vector512 c3Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + + // Used for the color conversion + Vector512 scale = Vector512.Create(1 / (this.MaximumValue * this.MaximumValue)); + + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + ref Vector512 c = ref Unsafe.Add(ref c0Base, i); + ref Vector512 m = ref Unsafe.Add(ref c1Base, i); + ref Vector512 y = ref Unsafe.Add(ref c2Base, i); + Vector512 k = Unsafe.Add(ref c3Base, i); + + k *= scale; + c *= k; + m *= k; + y *= k; + } + } + + /// + protected override void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => ConvertFromRgbVectorized(in values, this.MaximumValue, rLane, gLane, bLane); + + /// + protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values) + => CmykScalar.ConvertToRgbInPlace(values, this.MaximumValue); + + /// + protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => CmykScalar.ConvertFromRgb(values, this.MaximumValue, rLane, gLane, bLane); + + internal static void ConvertFromRgbVectorized(in ComponentValues values, float maxValue, Span rLane, Span gLane, Span bLane) + { + ref Vector512 destC = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector512 destM = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector512 destY = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Vector512 destK = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + + ref Vector512 srcR = + ref Unsafe.As>(ref MemoryMarshal.GetReference(rLane)); + ref Vector512 srcG = + ref Unsafe.As>(ref MemoryMarshal.GetReference(gLane)); + ref Vector512 srcB = + ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); + + Vector512 scale = Vector512.Create(maxValue); + + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + Vector512 ctmp = scale - Unsafe.Add(ref srcR, i); + Vector512 mtmp = scale - Unsafe.Add(ref srcG, i); + Vector512 ytmp = scale - Unsafe.Add(ref srcB, i); + Vector512 ktmp = Vector512.Min(ctmp, Vector512.Min(mtmp, ytmp)); + + Vector512 kMask = ~Vector512.Equals(ktmp, scale); + Vector512 divisor = scale - ktmp; + + ctmp = ((ctmp - ktmp) / divisor) & kMask; + mtmp = ((mtmp - ktmp) / divisor) & kMask; + ytmp = ((ytmp - ktmp) / divisor) & kMask; + + Unsafe.Add(ref destC, i) = scale - (ctmp * scale); + Unsafe.Add(ref destM, i) = scale - (mtmp * scale); + Unsafe.Add(ref destY, i) = scale - (ytmp * scale); + Unsafe.Add(ref destK, i) = scale - ktmp; + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs index 4d3b5c60b..f710b7365 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs @@ -8,22 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class GrayscaleScalar : JpegColorConverterScalar + internal sealed class GrayScaleScalar : JpegColorConverterScalar { - public GrayscaleScalar(int precision) + public GrayScaleScalar(int precision) : base(JpegColorSpace.Grayscale, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) - => ConvertToRgbInplace(values.Component0, this.MaximumValue); + public override void ConvertToRgbInPlace(in ComponentValues values) + => ConvertToRgbInPlace(values.Component0, this.MaximumValue); /// - public override void ConvertFromRgb(in ComponentValues values, Span r, Span g, Span b) - => ConvertCoreInplaceFromRgb(values, r, g, b); + public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => ConvertFromRgbScalar(values, rLane, gLane, bLane); - internal static void ConvertToRgbInplace(Span values, float maxValue) + internal static void ConvertToRgbInPlace(Span values, float maxValue) { ref float valuesRef = ref MemoryMarshal.GetReference(values); float scale = 1 / maxValue; @@ -34,15 +34,14 @@ internal abstract partial class JpegColorConverterBase } } - internal static void ConvertCoreInplaceFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) + internal static void ConvertFromRgbScalar(in ComponentValues values, Span rLane, Span gLane, Span bLane) { Span c0 = values.Component0; for (int i = 0; i < c0.Length; i++) { - // luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b) - float luma = (0.299f * rLane[i]) + (0.587f * gLane[i]) + (0.114f * bLane[i]); - c0[i] = luma; + // luminosity = (0.299 * r) + (0.587 * g) + (0.114 * b) + c0[i] = (float)((0.299f * rLane[i]) + (0.587f * gLane[i]) + (0.114f * bLane[i])); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector.cs deleted file mode 100644 index cac10636f..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components; - -internal abstract partial class JpegColorConverterBase -{ - internal sealed class GrayScaleVector : JpegColorConverterVector - { - public GrayScaleVector(int precision) - : base(JpegColorSpace.Grayscale, precision) - { - } - - /// - protected override void ConvertToRgbInplaceVectorized(in ComponentValues values) - { - ref Vector cBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - - var scale = new Vector(1 / this.MaximumValue); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - ref Vector c0 = ref Unsafe.Add(ref cBase, i); - c0 *= scale; - } - } - - /// - protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values) - => GrayscaleScalar.ConvertToRgbInplace(values.Component0, this.MaximumValue); - - /// - protected override void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane) - { - ref Vector destLuma = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - - ref Vector srcR = - ref Unsafe.As>(ref MemoryMarshal.GetReference(rLane)); - ref Vector srcG = - ref Unsafe.As>(ref MemoryMarshal.GetReference(gLane)); - ref Vector srcB = - ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); - - var rMult = new Vector(0.299f); - var gMult = new Vector(0.587f); - var bMult = new Vector(0.114f); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - Vector r = Unsafe.Add(ref srcR, i); - Vector g = Unsafe.Add(ref srcR, i); - Vector b = Unsafe.Add(ref srcR, i); - - // luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b) - Unsafe.Add(ref destLuma, i) = (rMult * r) + (gMult * g) + (bMult * b); - } - } - - /// - protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span r, Span g, Span b) - => GrayscaleScalar.ConvertCoreInplaceFromRgb(values, r, g, b); - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleArm.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector128.cs similarity index 72% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleArm.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector128.cs index 6bb8fd7aa..f3a6f7d37 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleArm.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector128.cs @@ -1,37 +1,36 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using static SixLabors.ImageSharp.SimdUtils; +using SixLabors.ImageSharp.Common.Helpers; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class GrayscaleArm : JpegColorConverterArm + internal sealed class GrayScaleVector128 : JpegColorConverterVector128 { - public GrayscaleArm(int precision) + public GrayScaleVector128(int precision) : base(JpegColorSpace.Grayscale, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector128 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); // Used for the color conversion - var scale = Vector128.Create(1 / this.MaximumValue); + Vector128 scale = Vector128.Create(1 / this.MaximumValue); nuint n = values.Component0.Vector128Count(); for (nuint i = 0; i < n; i++) { ref Vector128 c0 = ref Unsafe.Add(ref c0Base, i); - c0 = AdvSimd.Multiply(c0, scale); + c0 *= scale; } } @@ -49,9 +48,9 @@ internal abstract partial class JpegColorConverterBase ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); // Used for the color conversion - var f0299 = Vector128.Create(0.299f); - var f0587 = Vector128.Create(0.587f); - var f0114 = Vector128.Create(0.114f); + Vector128 f0299 = Vector128.Create(0.299f); + Vector128 f0587 = Vector128.Create(0.587f); + Vector128 f0114 = Vector128.Create(0.114f); nuint n = values.Component0.Vector128Count(); for (nuint i = 0; i < n; i++) @@ -60,8 +59,8 @@ internal abstract partial class JpegColorConverterBase ref Vector128 g = ref Unsafe.Add(ref srcGreen, i); ref Vector128 b = ref Unsafe.Add(ref srcBlue, i); - // luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b) - Unsafe.Add(ref destLuminance, i) = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r); + // luminosity = (0.299 * r) + (0.587 * g) + (0.114 * b) + Unsafe.Add(ref destLuminance, i) = Vector128Utilities.MultiplyAdd(Vector128Utilities.MultiplyAdd(f0114 * b, f0587, g), f0299, r); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector256.cs similarity index 71% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleAvx.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector256.cs index a9e1c5d13..139ffc549 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector256.cs @@ -1,37 +1,36 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; +using Vector256_ = SixLabors.ImageSharp.Common.Helpers.Vector256Utilities; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class GrayscaleAvx : JpegColorConverterAvx + internal sealed class GrayScaleVector256 : JpegColorConverterVector256 { - public GrayscaleAvx(int precision) + public GrayScaleVector256(int precision) : base(JpegColorSpace.Grayscale, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); // Used for the color conversion - var scale = Vector256.Create(1 / this.MaximumValue); + Vector256 scale = Vector256.Create(1 / this.MaximumValue); nuint n = values.Component0.Vector256Count(); for (nuint i = 0; i < n; i++) { ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); - c0 = Avx.Multiply(c0, scale); + c0 *= scale; } } @@ -49,9 +48,9 @@ internal abstract partial class JpegColorConverterBase ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); // Used for the color conversion - var f0299 = Vector256.Create(0.299f); - var f0587 = Vector256.Create(0.587f); - var f0114 = Vector256.Create(0.114f); + Vector256 f0299 = Vector256.Create(0.299f); + Vector256 f0587 = Vector256.Create(0.587f); + Vector256 f0114 = Vector256.Create(0.114f); nuint n = values.Component0.Vector256Count(); for (nuint i = 0; i < n; i++) @@ -60,8 +59,8 @@ internal abstract partial class JpegColorConverterBase ref Vector256 g = ref Unsafe.Add(ref srcGreen, i); ref Vector256 b = ref Unsafe.Add(ref srcBlue, i); - // luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b) - Unsafe.Add(ref destLuminance, i) = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f0114, b), f0587, g), f0299, r); + // luminosity = (0.299 * r) + (0.587 * g) + (0.114 * b) + Unsafe.Add(ref destLuminance, i) = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f0114 * b, f0587, g), f0299, r); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector512.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector512.cs new file mode 100644 index 000000000..21d5eaa6f --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector512.cs @@ -0,0 +1,75 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using Vector512_ = SixLabors.ImageSharp.Common.Helpers.Vector512Utilities; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components; + +internal abstract partial class JpegColorConverterBase +{ + internal sealed class GrayScaleVector512 : JpegColorConverterVector512 + { + public GrayScaleVector512(int precision) + : base(JpegColorSpace.Grayscale, precision) + { + } + + /// + protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values) + { + ref Vector512 c0Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + + // Used for the color conversion + Vector512 scale = Vector512.Create(1 / this.MaximumValue); + + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + ref Vector512 c0 = ref Unsafe.Add(ref c0Base, i); + c0 *= scale; + } + } + + /// + protected override void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane) + { + ref Vector512 destLuminance = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + + ref Vector512 srcRed = + ref Unsafe.As>(ref MemoryMarshal.GetReference(rLane)); + ref Vector512 srcGreen = + ref Unsafe.As>(ref MemoryMarshal.GetReference(gLane)); + ref Vector512 srcBlue = + ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); + + // Used for the color conversion + Vector512 f0299 = Vector512.Create(0.299f); + Vector512 f0587 = Vector512.Create(0.587f); + Vector512 f0114 = Vector512.Create(0.114f); + + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + ref Vector512 r = ref Unsafe.Add(ref srcRed, i); + ref Vector512 g = ref Unsafe.Add(ref srcGreen, i); + ref Vector512 b = ref Unsafe.Add(ref srcBlue, i); + + // luminosity = (0.299 * r) + (0.587 * g) + (0.114 * b) + Unsafe.Add(ref destLuminance, i) = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f0114 * b, f0587, g), f0299, r); + } + } + + /// + protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values) + => GrayScaleScalar.ConvertToRgbInPlace(values.Component0, this.MaximumValue); + + /// + protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => GrayScaleScalar.ConvertFromRgbScalar(values, rLane, gLane, bLane); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbScalar.cs index a43b7ef84..23825b06e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbScalar.cs @@ -13,25 +13,25 @@ internal abstract partial class JpegColorConverterBase } /// - public override void ConvertToRgbInplace(in ComponentValues values) - => ConvertToRgbInplace(values, this.MaximumValue); + public override void ConvertToRgbInPlace(in ComponentValues values) + => ConvertToRgbInPlace(values, this.MaximumValue); /// - public override void ConvertFromRgb(in ComponentValues values, Span r, Span g, Span b) - => ConvertFromRgb(values, r, g, b); + public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => ConvertFromRgb(values, rLane, gLane, bLane); - internal static void ConvertToRgbInplace(ComponentValues values, float maxValue) + internal static void ConvertToRgbInPlace(ComponentValues values, float maxValue) { - GrayscaleScalar.ConvertToRgbInplace(values.Component0, maxValue); - GrayscaleScalar.ConvertToRgbInplace(values.Component1, maxValue); - GrayscaleScalar.ConvertToRgbInplace(values.Component2, maxValue); + GrayScaleScalar.ConvertToRgbInPlace(values.Component0, maxValue); + GrayScaleScalar.ConvertToRgbInPlace(values.Component1, maxValue); + GrayScaleScalar.ConvertToRgbInPlace(values.Component2, maxValue); } - internal static void ConvertFromRgb(ComponentValues values, Span r, Span g, Span b) + internal static void ConvertFromRgb(ComponentValues values, Span rLane, Span gLane, Span bLane) { - r.CopyTo(values.Component0); - g.CopyTo(values.Component1); - b.CopyTo(values.Component2); + rLane.CopyTo(values.Component0); + gLane.CopyTo(values.Component1); + bLane.CopyTo(values.Component2); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector.cs deleted file mode 100644 index bd3142fa1..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components; - -internal abstract partial class JpegColorConverterBase -{ - internal sealed class RgbVector : JpegColorConverterVector - { - public RgbVector(int precision) - : base(JpegColorSpace.RGB, precision) - { - } - - /// - protected override void ConvertToRgbInplaceVectorized(in ComponentValues values) - { - ref Vector rBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector gBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector bBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - - var scale = new Vector(1 / this.MaximumValue); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - ref Vector r = ref Unsafe.Add(ref rBase, i); - ref Vector g = ref Unsafe.Add(ref gBase, i); - ref Vector b = ref Unsafe.Add(ref bBase, i); - r *= scale; - g *= scale; - b *= scale; - } - } - - /// - protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values) - => RgbScalar.ConvertToRgbInplace(values, this.MaximumValue); - - /// - protected override void ConvertFromRgbVectorized(in ComponentValues values, Span r, Span g, Span b) - { - r.CopyTo(values.Component0); - g.CopyTo(values.Component1); - b.CopyTo(values.Component2); - } - - /// - protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span r, Span g, Span b) - => RgbScalar.ConvertFromRgb(values, r, g, b); - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbArm.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector128.cs similarity index 76% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbArm.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector128.cs index 75eeb17dd..47aa4281b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbArm.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector128.cs @@ -1,25 +1,23 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class RgbArm : JpegColorConverterArm + internal sealed class RgbVector128 : JpegColorConverterVector128 { - public RgbArm(int precision) + public RgbVector128(int precision) : base(JpegColorSpace.RGB, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector128 rBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -29,16 +27,16 @@ internal abstract partial class JpegColorConverterBase ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); // Used for the color conversion - var scale = Vector128.Create(1 / this.MaximumValue); + Vector128 scale = Vector128.Create(1 / this.MaximumValue); nuint n = values.Component0.Vector128Count(); for (nuint i = 0; i < n; i++) { ref Vector128 r = ref Unsafe.Add(ref rBase, i); ref Vector128 g = ref Unsafe.Add(ref gBase, i); ref Vector128 b = ref Unsafe.Add(ref bBase, i); - r = AdvSimd.Multiply(r, scale); - g = AdvSimd.Multiply(g, scale); - b = AdvSimd.Multiply(b, scale); + r *= scale; + g *= scale; + b *= scale; } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector256.cs similarity index 78% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbAvx.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector256.cs index b56728fa7..02448d724 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector256.cs @@ -1,24 +1,23 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class RgbAvx : JpegColorConverterAvx + internal sealed class RgbVector256 : JpegColorConverterVector256 { - public RgbAvx(int precision) + public RgbVector256(int precision) : base(JpegColorSpace.RGB, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector256 rBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -28,16 +27,16 @@ internal abstract partial class JpegColorConverterBase ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); // Used for the color conversion - var scale = Vector256.Create(1 / this.MaximumValue); + Vector256 scale = Vector256.Create(1 / this.MaximumValue); nuint n = values.Component0.Vector256Count(); for (nuint i = 0; i < n; i++) { ref Vector256 r = ref Unsafe.Add(ref rBase, i); ref Vector256 g = ref Unsafe.Add(ref gBase, i); ref Vector256 b = ref Unsafe.Add(ref bBase, i); - r = Avx.Multiply(r, scale); - g = Avx.Multiply(g, scale); - b = Avx.Multiply(b, scale); + r *= scale; + g *= scale; + b *= scale; } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector512.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector512.cs new file mode 100644 index 000000000..76745f665 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector512.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components; + +internal abstract partial class JpegColorConverterBase +{ + internal sealed class RgbVector512 : JpegColorConverterVector512 + { + public RgbVector512(int precision) + : base(JpegColorSpace.RGB, precision) + { + } + + /// + protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values) + { + ref Vector512 rBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector512 gBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector512 bBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + + // Used for the color conversion + Vector512 scale = Vector512.Create(1 / this.MaximumValue); + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + ref Vector512 r = ref Unsafe.Add(ref rBase, i); + ref Vector512 g = ref Unsafe.Add(ref gBase, i); + ref Vector512 b = ref Unsafe.Add(ref bBase, i); + r *= scale; + g *= scale; + b *= scale; + } + } + + /// + protected override void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane) + { + rLane.CopyTo(values.Component0); + gLane.CopyTo(values.Component1); + bLane.CopyTo(values.Component2); + } + + /// + protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values) + => RgbScalar.ConvertToRgbInPlace(values, this.MaximumValue); + + /// + protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => RgbScalar.ConvertFromRgb(values, rLane, gLane, bLane); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrScalar.cs index e3e5a452a..e514a0166 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrScalar.cs @@ -19,14 +19,14 @@ internal abstract partial class JpegColorConverterBase } /// - public override void ConvertToRgbInplace(in ComponentValues values) - => ConvertToRgbInplace(values, this.MaximumValue, this.HalfValue); + public override void ConvertToRgbInPlace(in ComponentValues values) + => ConvertToRgbInPlace(values, this.MaximumValue, this.HalfValue); /// - public override void ConvertFromRgb(in ComponentValues values, Span r, Span g, Span b) - => ConvertFromRgb(values, this.HalfValue, r, g, b); + public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => ConvertFromRgb(values, this.HalfValue, rLane, gLane, bLane); - public static void ConvertToRgbInplace(in ComponentValues values, float maxValue, float halfValue) + public static void ConvertToRgbInPlace(in ComponentValues values, float maxValue, float halfValue) { Span c0 = values.Component0; Span c1 = values.Component1; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector.cs deleted file mode 100644 index a5d0c889e..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector.cs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// ReSharper disable ImpureMethodCallOnReadonlyValueField -namespace SixLabors.ImageSharp.Formats.Jpeg.Components; - -internal abstract partial class JpegColorConverterBase -{ - internal sealed class YCbCrVector : JpegColorConverterVector - { - public YCbCrVector(int precision) - : base(JpegColorSpace.YCbCr, precision) - { - } - - /// - protected override void ConvertToRgbInplaceVectorized(in ComponentValues values) - { - ref Vector c0Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector c1Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector c2Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - - var chromaOffset = new Vector(-this.HalfValue); - - var scale = new Vector(1 / this.MaximumValue); - var rCrMult = new Vector(YCbCrScalar.RCrMult); - var gCbMult = new Vector(-YCbCrScalar.GCbMult); - var gCrMult = new Vector(-YCbCrScalar.GCrMult); - var bCbMult = new Vector(YCbCrScalar.BCbMult); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - // y = yVals[i]; - // cb = cbVals[i] - 128F; - // cr = crVals[i] - 128F; - ref Vector c0 = ref Unsafe.Add(ref c0Base, i); - ref Vector c1 = ref Unsafe.Add(ref c1Base, i); - ref Vector c2 = ref Unsafe.Add(ref c2Base, i); - Vector y = Unsafe.Add(ref c0Base, i); - Vector cb = Unsafe.Add(ref c1Base, i) + chromaOffset; - Vector cr = Unsafe.Add(ref c2Base, i) + chromaOffset; - - // r = y + (1.402F * cr); - // g = y - (0.344136F * cb) - (0.714136F * cr); - // b = y + (1.772F * cb); - Vector r = y + (cr * rCrMult); - Vector g = y + (cb * gCbMult) + (cr * gCrMult); - Vector b = y + (cb * bCbMult); - - r = r.FastRound(); - g = g.FastRound(); - b = b.FastRound(); - r *= scale; - g *= scale; - b *= scale; - - c0 = r; - c1 = g; - c2 = b; - } - } - - /// - protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values) - => YCbCrScalar.ConvertToRgbInplace(values, this.MaximumValue, this.HalfValue); - - /// - protected override void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane) - { - ref Vector destY = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector destCb = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector destCr = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - - ref Vector srcR = - ref Unsafe.As>(ref MemoryMarshal.GetReference(rLane)); - ref Vector srcG = - ref Unsafe.As>(ref MemoryMarshal.GetReference(gLane)); - ref Vector srcB = - ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); - - var chromaOffset = new Vector(this.HalfValue); - - var rYMult = new Vector(0.299f); - var gYMult = new Vector(0.587f); - var bYMult = new Vector(0.114f); - - var rCbMult = new Vector(0.168736f); - var gCbMult = new Vector(0.331264f); - var bCbMult = new Vector(0.5f); - - var rCrMult = new Vector(0.5f); - var gCrMult = new Vector(0.418688f); - var bCrMult = new Vector(0.081312f); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - Vector r = Unsafe.Add(ref srcR, i); - Vector g = Unsafe.Add(ref srcG, i); - Vector b = Unsafe.Add(ref srcB, i); - - // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) - // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) - // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) - Unsafe.Add(ref destY, i) = (rYMult * r) + (gYMult * g) + (bYMult * b); - Unsafe.Add(ref destCb, i) = chromaOffset - (rCbMult * r) - (gCbMult * g) + (bCbMult * b); - Unsafe.Add(ref destCr, i) = chromaOffset + (rCrMult * r) - (gCrMult * g) - (bCrMult * b); - } - } - - /// - protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span r, Span g, Span b) - => YCbCrScalar.ConvertFromRgb(values, this.HalfValue, r, g, b); - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrArm.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector128.cs similarity index 55% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrArm.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector128.cs index 4f7cf1ed6..8cecd3956 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrArm.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector128.cs @@ -1,27 +1,24 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; +using Vector128_ = SixLabors.ImageSharp.Common.Helpers.Vector128Utilities; -// ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class YCbCrArm : JpegColorConverterArm + internal sealed class YCbCrVector128 : JpegColorConverterVector128 { - public YCbCrArm(int precision) + public YCbCrVector128(int precision) : base(JpegColorSpace.YCbCr, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector128 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -30,16 +27,15 @@ internal abstract partial class JpegColorConverterBase ref Vector128 c2Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - // Used for the color conversion - var chromaOffset = Vector128.Create(-this.HalfValue); - var scale = Vector128.Create(1 / this.MaximumValue); - var rCrMult = Vector128.Create(YCbCrScalar.RCrMult); - var gCbMult = Vector128.Create(-YCbCrScalar.GCbMult); - var gCrMult = Vector128.Create(-YCbCrScalar.GCrMult); - var bCbMult = Vector128.Create(YCbCrScalar.BCbMult); + Vector128 chromaOffset = Vector128.Create(-this.HalfValue); + Vector128 scale = Vector128.Create(1 / this.MaximumValue); + Vector128 rCrMult = Vector128.Create(YCbCrScalar.RCrMult); + Vector128 gCbMult = Vector128.Create(-YCbCrScalar.GCbMult); + Vector128 gCrMult = Vector128.Create(-YCbCrScalar.GCrMult); + Vector128 bCbMult = Vector128.Create(YCbCrScalar.BCbMult); // Walking 8 elements at one step: - nuint n = (uint)values.Component0.Length / (uint)Vector128.Count; + nuint n = values.Component0.Vector128Count(); for (nuint i = 0; i < n; i++) { // y = yVals[i]; @@ -50,19 +46,19 @@ internal abstract partial class JpegColorConverterBase ref Vector128 c2 = ref Unsafe.Add(ref c2Base, i); Vector128 y = c0; - Vector128 cb = AdvSimd.Add(c1, chromaOffset); - Vector128 cr = AdvSimd.Add(c2, chromaOffset); + Vector128 cb = c1 + chromaOffset; + Vector128 cr = c2 + chromaOffset; // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - Vector128 r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult); - Vector128 g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); - Vector128 b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult); + Vector128 r = Vector128_.MultiplyAdd(y, cr, rCrMult); + Vector128 g = Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); + Vector128 b = Vector128_.MultiplyAdd(y, cb, bCbMult); - r = AdvSimd.Multiply(AdvSimd.RoundToNearest(r), scale); - g = AdvSimd.Multiply(AdvSimd.RoundToNearest(g), scale); - b = AdvSimd.Multiply(AdvSimd.RoundToNearest(b), scale); + r = Vector128_.RoundToNearestInteger(r) * scale; + g = Vector128_.RoundToNearestInteger(g) * scale; + b = Vector128_.RoundToNearestInteger(b) * scale; c0 = r; c1 = g; @@ -87,19 +83,17 @@ internal abstract partial class JpegColorConverterBase ref Vector128 srcB = ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); - // Used for the color conversion - var chromaOffset = Vector128.Create(this.HalfValue); - - var f0299 = Vector128.Create(0.299f); - var f0587 = Vector128.Create(0.587f); - var f0114 = Vector128.Create(0.114f); - var fn0168736 = Vector128.Create(-0.168736f); - var fn0331264 = Vector128.Create(-0.331264f); - var fn0418688 = Vector128.Create(-0.418688f); - var fn0081312F = Vector128.Create(-0.081312F); - var f05 = Vector128.Create(0.5f); - - nuint n = (uint)values.Component0.Length / (uint)Vector128.Count; + Vector128 chromaOffset = Vector128.Create(this.HalfValue); + Vector128 f0299 = Vector128.Create(0.299f); + Vector128 f0587 = Vector128.Create(0.587f); + Vector128 f0114 = Vector128.Create(0.114f); + Vector128 fn0168736 = Vector128.Create(-0.168736f); + Vector128 fn0331264 = Vector128.Create(-0.331264f); + Vector128 fn0418688 = Vector128.Create(-0.418688f); + Vector128 fn0081312F = Vector128.Create(-0.081312F); + Vector128 f05 = Vector128.Create(0.5f); + + nuint n = values.Component0.Vector128Count(); for (nuint i = 0; i < n; i++) { Vector128 r = Unsafe.Add(ref srcR, i); @@ -109,9 +103,9 @@ internal abstract partial class JpegColorConverterBase // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) - Vector128 y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r); - Vector128 cb = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f05, b), fn0331264, g), fn0168736, r)); - Vector128 cr = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(fn0081312F, b), fn0418688, g), f05, r)); + Vector128 y = Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(f0114 * b, f0587, g), f0299, r); + Vector128 cb = chromaOffset + Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r); + Vector128 cr = chromaOffset + Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r); Unsafe.Add(ref destY, i) = y; Unsafe.Add(ref destCb, i) = cb; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector256.cs similarity index 58% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrAvx.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector256.cs index c5fa786e2..f8517e086 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector256.cs @@ -1,26 +1,24 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; +using Vector256_ = SixLabors.ImageSharp.Common.Helpers.Vector256Utilities; -// ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class YCbCrAvx : JpegColorConverterAvx + internal sealed class YCbCrVector256 : JpegColorConverterVector256 { - public YCbCrAvx(int precision) + public YCbCrVector256(int precision) : base(JpegColorSpace.YCbCr, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -29,13 +27,12 @@ internal abstract partial class JpegColorConverterBase ref Vector256 c2Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - // Used for the color conversion - var chromaOffset = Vector256.Create(-this.HalfValue); - var scale = Vector256.Create(1 / this.MaximumValue); - var rCrMult = Vector256.Create(YCbCrScalar.RCrMult); - var gCbMult = Vector256.Create(-YCbCrScalar.GCbMult); - var gCrMult = Vector256.Create(-YCbCrScalar.GCrMult); - var bCbMult = Vector256.Create(YCbCrScalar.BCbMult); + Vector256 chromaOffset = Vector256.Create(-this.HalfValue); + Vector256 scale = Vector256.Create(1 / this.MaximumValue); + Vector256 rCrMult = Vector256.Create(YCbCrScalar.RCrMult); + Vector256 gCbMult = Vector256.Create(-YCbCrScalar.GCbMult); + Vector256 gCrMult = Vector256.Create(-YCbCrScalar.GCrMult); + Vector256 bCbMult = Vector256.Create(YCbCrScalar.BCbMult); // Walking 8 elements at one step: nuint n = values.Component0.Vector256Count(); @@ -49,19 +46,19 @@ internal abstract partial class JpegColorConverterBase ref Vector256 c2 = ref Unsafe.Add(ref c2Base, i); Vector256 y = c0; - Vector256 cb = Avx.Add(c1, chromaOffset); - Vector256 cr = Avx.Add(c2, chromaOffset); + Vector256 cb = c1 + chromaOffset; + Vector256 cr = c2 + chromaOffset; // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - 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); + Vector256 r = Vector256_.MultiplyAdd(y, cr, rCrMult); + Vector256 g = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); + Vector256 b = Vector256_.MultiplyAdd(y, cb, bCbMult); - r = Avx.Multiply(Avx.RoundToNearestInteger(r), scale); - g = Avx.Multiply(Avx.RoundToNearestInteger(g), scale); - b = Avx.Multiply(Avx.RoundToNearestInteger(b), scale); + r = Vector256_.RoundToNearestInteger(r) * scale; + g = Vector256_.RoundToNearestInteger(g) * scale; + b = Vector256_.RoundToNearestInteger(b) * scale; c0 = r; c1 = g; @@ -86,17 +83,15 @@ internal abstract partial class JpegColorConverterBase ref Vector256 srcB = ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); - // Used for the color conversion - var chromaOffset = Vector256.Create(this.HalfValue); - - var f0299 = Vector256.Create(0.299f); - var f0587 = Vector256.Create(0.587f); - var f0114 = Vector256.Create(0.114f); - var fn0168736 = Vector256.Create(-0.168736f); - var fn0331264 = Vector256.Create(-0.331264f); - var fn0418688 = Vector256.Create(-0.418688f); - var fn0081312F = Vector256.Create(-0.081312F); - var f05 = Vector256.Create(0.5f); + Vector256 chromaOffset = Vector256.Create(this.HalfValue); + Vector256 f0299 = Vector256.Create(0.299f); + Vector256 f0587 = Vector256.Create(0.587f); + Vector256 f0114 = Vector256.Create(0.114f); + Vector256 fn0168736 = Vector256.Create(-0.168736f); + Vector256 fn0331264 = Vector256.Create(-0.331264f); + Vector256 fn0418688 = Vector256.Create(-0.418688f); + Vector256 fn0081312F = Vector256.Create(-0.081312F); + Vector256 f05 = Vector256.Create(0.5f); nuint n = values.Component0.Vector256Count(); for (nuint i = 0; i < n; i++) @@ -108,9 +103,9 @@ internal abstract partial class JpegColorConverterBase // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) - Vector256 y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f0114, b), f0587, g), f0299, r); - Vector256 cb = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f05, b), fn0331264, g), fn0168736, r)); - Vector256 cr = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(fn0081312F, b), fn0418688, g), f05, r)); + Vector256 y = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f0114 * b, f0587, g), f0299, r); + Vector256 cb = chromaOffset + Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r); + Vector256 cr = chromaOffset + Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r); Unsafe.Add(ref destY, i) = y; Unsafe.Add(ref destCb, i) = cb; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector512.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector512.cs new file mode 100644 index 000000000..7598a64b2 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector512.cs @@ -0,0 +1,123 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using Vector512_ = SixLabors.ImageSharp.Common.Helpers.Vector512Utilities; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components; + +internal abstract partial class JpegColorConverterBase +{ + internal sealed class YCbCrVector512 : JpegColorConverterVector512 + { + public YCbCrVector512(int precision) + : base(JpegColorSpace.YCbCr, precision) + { + } + + /// + protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values) + { + ref Vector512 c0Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector512 c1Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector512 c2Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + + Vector512 chromaOffset = Vector512.Create(-this.HalfValue); + Vector512 scale = Vector512.Create(1 / this.MaximumValue); + Vector512 rCrMult = Vector512.Create(YCbCrScalar.RCrMult); + Vector512 gCbMult = Vector512.Create(-YCbCrScalar.GCbMult); + Vector512 gCrMult = Vector512.Create(-YCbCrScalar.GCrMult); + Vector512 bCbMult = Vector512.Create(YCbCrScalar.BCbMult); + + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + // y = yVals[i]; + // cb = cbVals[i] - 128F; + // cr = crVals[i] - 128F; + ref Vector512 c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector512 c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector512 c2 = ref Unsafe.Add(ref c2Base, i); + + Vector512 y = c0; + Vector512 cb = c1 + chromaOffset; + Vector512 cr = c2 + chromaOffset; + + // r = y + (1.402F * cr); + // g = y - (0.344136F * cb) - (0.714136F * cr); + // b = y + (1.772F * cb); + Vector512 r = Vector512_.MultiplyAdd(y, cr, rCrMult); + Vector512 g = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); + Vector512 b = Vector512_.MultiplyAdd(y, cb, bCbMult); + + r = Vector512_.RoundToNearestInteger(r) * scale; + g = Vector512_.RoundToNearestInteger(g) * scale; + b = Vector512_.RoundToNearestInteger(b) * scale; + + c0 = r; + c1 = g; + c2 = b; + } + } + + /// + protected override void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane) + { + ref Vector512 destY = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector512 destCb = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector512 destCr = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + + ref Vector512 srcR = + ref Unsafe.As>(ref MemoryMarshal.GetReference(rLane)); + ref Vector512 srcG = + ref Unsafe.As>(ref MemoryMarshal.GetReference(gLane)); + ref Vector512 srcB = + ref Unsafe.As>(ref MemoryMarshal.GetReference(bLane)); + + Vector512 chromaOffset = Vector512.Create(this.HalfValue); + Vector512 f0299 = Vector512.Create(0.299f); + Vector512 f0587 = Vector512.Create(0.587f); + Vector512 f0114 = Vector512.Create(0.114f); + Vector512 fn0168736 = Vector512.Create(-0.168736f); + Vector512 fn0331264 = Vector512.Create(-0.331264f); + Vector512 fn0418688 = Vector512.Create(-0.418688f); + Vector512 fn0081312F = Vector512.Create(-0.081312F); + Vector512 f05 = Vector512.Create(0.5f); + + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + Vector512 r = Unsafe.Add(ref srcR, i); + Vector512 g = Unsafe.Add(ref srcG, i); + Vector512 b = Unsafe.Add(ref srcB, i); + + // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) + // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) + // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) + Vector512 y = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f0114 * b, f0587, g), f0299, r); + Vector512 cb = chromaOffset + Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r); + Vector512 cr = chromaOffset + Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r); + + Unsafe.Add(ref destY, i) = y; + Unsafe.Add(ref destCb, i) = cb; + Unsafe.Add(ref destCr, i) = cr; + } + } + + /// + protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values) + => YCbCrScalar.ConvertToRgbInPlace(values, this.MaximumValue, this.HalfValue); + + /// + protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => YCbCrScalar.ConvertFromRgb(values, this.HalfValue, rLane, gLane, bLane); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKArm64.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKArm64.cs deleted file mode 100644 index 285ba62cf..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKArm64.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components; - -internal abstract partial class JpegColorConverterBase -{ - internal sealed class YccKArm64 : JpegColorConverterArm64 - { - public YccKArm64(int precision) - : base(JpegColorSpace.Ycck, precision) - { - } - - /// - public override void ConvertToRgbInplace(in ComponentValues values) - { - ref Vector128 c0Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector128 c1Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector128 c2Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector128 kBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - - // Used for the color conversion - var chromaOffset = Vector128.Create(-this.HalfValue); - var scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue)); - var max = Vector128.Create(this.MaximumValue); - var rCrMult = Vector128.Create(YCbCrScalar.RCrMult); - var gCbMult = Vector128.Create(-YCbCrScalar.GCbMult); - var gCrMult = Vector128.Create(-YCbCrScalar.GCrMult); - var bCbMult = Vector128.Create(YCbCrScalar.BCbMult); - - // Walking 8 elements at one step: - nuint n = (uint)values.Component0.Length / (uint)Vector128.Count; - for (nuint i = 0; i < n; i++) - { - // y = yVals[i]; - // cb = cbVals[i] - 128F; - // cr = crVals[i] - 128F; - // k = kVals[i] / 256F; - ref Vector128 c0 = ref Unsafe.Add(ref c0Base, i); - ref Vector128 c1 = ref Unsafe.Add(ref c1Base, i); - ref Vector128 c2 = ref Unsafe.Add(ref c2Base, i); - Vector128 y = c0; - Vector128 cb = AdvSimd.Add(c1, chromaOffset); - Vector128 cr = AdvSimd.Add(c2, chromaOffset); - Vector128 scaledK = AdvSimd.Multiply(Unsafe.Add(ref kBase, i), scale); - - // r = y + (1.402F * cr); - // g = y - (0.344136F * cb) - (0.714136F * cr); - // b = y + (1.772F * cb); - Vector128 r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult); - Vector128 g = - HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); - Vector128 b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult); - - r = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(r)); - g = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(g)); - b = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(b)); - - r = AdvSimd.Multiply(r, scaledK); - g = AdvSimd.Multiply(g, scaledK); - b = AdvSimd.Multiply(b, scaledK); - - c0 = r; - c1 = g; - c2 = b; - } - } - - /// - public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) - { - // rgb -> cmyk - CmykArm64.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane); - - // cmyk -> ycck - ref Vector128 destY = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector128 destCb = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector128 destCr = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - - ref Vector128 srcR = ref destY; - ref Vector128 srcG = ref destCb; - ref Vector128 srcB = ref destCr; - - // Used for the color conversion - var maxSampleValue = Vector128.Create(this.MaximumValue); - - var chromaOffset = Vector128.Create(this.HalfValue); - - var f0299 = Vector128.Create(0.299f); - var f0587 = Vector128.Create(0.587f); - var f0114 = Vector128.Create(0.114f); - var fn0168736 = Vector128.Create(-0.168736f); - var fn0331264 = Vector128.Create(-0.331264f); - var fn0418688 = Vector128.Create(-0.418688f); - var fn0081312F = Vector128.Create(-0.081312F); - var f05 = Vector128.Create(0.5f); - - nuint n = (uint)values.Component0.Length / (uint)Vector128.Count; - for (nuint i = 0; i < n; i++) - { - Vector128 r = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcR, i)); - Vector128 g = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcG, i)); - Vector128 b = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcB, i)); - - // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) - // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) - // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) - Vector128 y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r); - Vector128 cb = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f05, b), fn0331264, g), fn0168736, r)); - Vector128 cr = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(fn0081312F, b), fn0418688, g), f05, r)); - - Unsafe.Add(ref destY, i) = y; - Unsafe.Add(ref destCb, i) = cb; - Unsafe.Add(ref destCr, i) = cr; - } - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKScalar.cs index e47572b02..bb545ec76 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKScalar.cs @@ -19,14 +19,14 @@ internal abstract partial class JpegColorConverterBase } /// - public override void ConvertToRgbInplace(in ComponentValues values) - => ConvertToRgpInplace(values, this.MaximumValue, this.HalfValue); + public override void ConvertToRgbInPlace(in ComponentValues values) + => ConvertToRgpInPlace(values, this.MaximumValue, this.HalfValue); /// - public override void ConvertFromRgb(in ComponentValues values, Span r, Span g, Span b) - => ConvertFromRgb(values, this.HalfValue, this.MaximumValue, r, g, b); + public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) + => ConvertFromRgb(values, this.HalfValue, this.MaximumValue, rLane, gLane, bLane); - public static void ConvertToRgpInplace(in ComponentValues values, float maxValue, float halfValue) + public static void ConvertToRgpInPlace(in ComponentValues values, float maxValue, float halfValue) { Span c0 = values.Component0; Span c1 = values.Component1; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector.cs deleted file mode 100644 index 570a401ad..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components; - -internal abstract partial class JpegColorConverterBase -{ - internal sealed class YccKVector : JpegColorConverterVector - { - public YccKVector(int precision) - : base(JpegColorSpace.Ycck, precision) - { - } - - /// - protected override void ConvertToRgbInplaceVectorized(in ComponentValues values) - { - ref Vector c0Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector c1Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector c2Base = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - ref Vector kBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); - - var chromaOffset = new Vector(-this.HalfValue); - var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue)); - var max = new Vector(this.MaximumValue); - var rCrMult = new Vector(YCbCrScalar.RCrMult); - var gCbMult = new Vector(-YCbCrScalar.GCbMult); - var gCrMult = new Vector(-YCbCrScalar.GCrMult); - var bCbMult = new Vector(YCbCrScalar.BCbMult); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - // y = yVals[i]; - // cb = cbVals[i] - 128F; - // cr = crVals[i] - 128F; - // k = kVals[i] / 256F; - ref Vector c0 = ref Unsafe.Add(ref c0Base, i); - ref Vector c1 = ref Unsafe.Add(ref c1Base, i); - ref Vector c2 = ref Unsafe.Add(ref c2Base, i); - - Vector y = c0; - Vector cb = c1 + chromaOffset; - Vector cr = c2 + chromaOffset; - Vector scaledK = Unsafe.Add(ref kBase, i) * scale; - - // r = y + (1.402F * cr); - // g = y - (0.344136F * cb) - (0.714136F * cr); - // b = y + (1.772F * cb); - 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; - b = (max - b.FastRound()) * scaledK; - - c0 = r; - c1 = g; - c2 = b; - } - } - - /// - protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values) - => YccKScalar.ConvertToRgpInplace(values, this.MaximumValue, this.HalfValue); - - /// - protected override void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane) - { - // rgb -> cmyk - CmykVector.ConvertFromRgbInplaceVectorized(in values, this.MaximumValue, rLane, gLane, bLane); - - // cmyk -> ycck - ref Vector destY = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); - ref Vector destCb = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); - ref Vector destCr = - ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); - - ref Vector srcR = ref destY; - ref Vector srcG = ref destCb; - ref Vector srcB = ref destCr; - - var maxSampleValue = new Vector(this.MaximumValue); - - var chromaOffset = new Vector(this.HalfValue); - - var rYMult = new Vector(0.299f); - var gYMult = new Vector(0.587f); - var bYMult = new Vector(0.114f); - - var rCbMult = new Vector(0.168736f); - var gCbMult = new Vector(0.331264f); - var bCbMult = new Vector(0.5f); - - var rCrMult = new Vector(0.5f); - var gCrMult = new Vector(0.418688f); - var bCrMult = new Vector(0.081312f); - - nuint n = values.Component0.VectorCount(); - for (nuint i = 0; i < n; i++) - { - Vector r = maxSampleValue - Unsafe.Add(ref srcR, i); - Vector g = maxSampleValue - Unsafe.Add(ref srcG, i); - Vector b = maxSampleValue - Unsafe.Add(ref srcB, i); - - // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) - // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) - // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) - Unsafe.Add(ref destY, i) = (rYMult * r) + (gYMult * g) + (bYMult * b); - Unsafe.Add(ref destCb, i) = chromaOffset - (rCbMult * r) - (gCbMult * g) + (bCbMult * b); - Unsafe.Add(ref destCr, i) = chromaOffset + (rCrMult * r) - (gCrMult * g) - (bCrMult * b); - } - } - - /// - protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span r, Span g, Span b) - { - // rgb -> cmyk - CmykScalar.ConvertFromRgb(in values, this.MaximumValue, r, g, b); - - // cmyk -> ycck - YccKScalar.ConvertFromRgb(in values, this.HalfValue, this.MaximumValue, r, g, b); - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector128.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector128.cs new file mode 100644 index 000000000..5bb2c5e5b --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector128.cs @@ -0,0 +1,130 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using Vector128_ = SixLabors.ImageSharp.Common.Helpers.Vector128Utilities; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components; + +internal abstract partial class JpegColorConverterBase +{ + internal sealed class YccKVector128 : JpegColorConverterVector128 + { + public YccKVector128(int precision) + : base(JpegColorSpace.Ycck, precision) + { + } + + /// + public override void ConvertToRgbInPlace(in ComponentValues values) + { + ref Vector128 c0Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector128 c1Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector128 c2Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Vector128 kBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + + // Used for the color conversion + Vector128 chromaOffset = Vector128.Create(-this.HalfValue); + Vector128 scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue)); + Vector128 max = Vector128.Create(this.MaximumValue); + Vector128 rCrMult = Vector128.Create(YCbCrScalar.RCrMult); + Vector128 gCbMult = Vector128.Create(-YCbCrScalar.GCbMult); + Vector128 gCrMult = Vector128.Create(-YCbCrScalar.GCrMult); + Vector128 bCbMult = Vector128.Create(YCbCrScalar.BCbMult); + + // Walking 8 elements at one step: + nuint n = values.Component0.Vector128Count(); + for (nuint i = 0; i < n; i++) + { + // y = yVals[i]; + // cb = cbVals[i] - 128F; + // cr = crVals[i] - 128F; + // k = kVals[i] / 256F; + ref Vector128 c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector128 c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector128 c2 = ref Unsafe.Add(ref c2Base, i); + Vector128 y = c0; + Vector128 cb = c1 + chromaOffset; + Vector128 cr = c2 + chromaOffset; + Vector128 scaledK = Unsafe.Add(ref kBase, i) * scale; + + // r = y + (1.402F * cr); + // g = y - (0.344136F * cb) - (0.714136F * cr); + // b = y + (1.772F * cb); + Vector128 r = Vector128_.MultiplyAdd(y, cr, rCrMult); + Vector128 g = Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); + Vector128 b = Vector128_.MultiplyAdd(y, cb, bCbMult); + + r = max - Vector128_.RoundToNearestInteger(r); + g = max - Vector128_.RoundToNearestInteger(g); + b = max - Vector128_.RoundToNearestInteger(b); + + r *= scaledK; + g *= scaledK; + b *= scaledK; + + c0 = r; + c1 = g; + c2 = b; + } + } + + /// + public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) + { + // rgb -> cmyk + CmykVector128.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane); + + // cmyk -> ycck + ref Vector128 destY = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector128 destCb = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector128 destCr = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + + ref Vector128 srcR = ref destY; + ref Vector128 srcG = ref destCb; + ref Vector128 srcB = ref destCr; + + // Used for the color conversion + Vector128 maxSampleValue = Vector128.Create(this.MaximumValue); + + Vector128 chromaOffset = Vector128.Create(this.HalfValue); + + Vector128 f0299 = Vector128.Create(0.299f); + Vector128 f0587 = Vector128.Create(0.587f); + Vector128 f0114 = Vector128.Create(0.114f); + Vector128 fn0168736 = Vector128.Create(-0.168736f); + Vector128 fn0331264 = Vector128.Create(-0.331264f); + Vector128 fn0418688 = Vector128.Create(-0.418688f); + Vector128 fn0081312F = Vector128.Create(-0.081312F); + Vector128 f05 = Vector128.Create(0.5f); + + nuint n = values.Component0.Vector128Count(); + for (nuint i = 0; i < n; i++) + { + Vector128 r = maxSampleValue - Unsafe.Add(ref srcR, i); + Vector128 g = maxSampleValue - Unsafe.Add(ref srcG, i); + Vector128 b = maxSampleValue - Unsafe.Add(ref srcB, i); + + // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) + // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) + // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) + Vector128 y = Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(f0114 * b, f0587, g), f0299, r); + Vector128 cb = chromaOffset + Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r); + Vector128 cr = chromaOffset + Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r); + + Unsafe.Add(ref destY, i) = y; + Unsafe.Add(ref destCb, i) = cb; + Unsafe.Add(ref destCr, i) = cr; + } + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector256.cs similarity index 52% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKAvx.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector256.cs index efe40ba08..27f2ce035 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector256.cs @@ -1,25 +1,24 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using static SixLabors.ImageSharp.SimdUtils; +using Vector256_ = SixLabors.ImageSharp.Common.Helpers.Vector256Utilities; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; internal abstract partial class JpegColorConverterBase { - internal sealed class YccKAvx : JpegColorConverterAvx + internal sealed class YccKVector256 : JpegColorConverterVector256 { - public YccKAvx(int precision) + public YccKVector256(int precision) : base(JpegColorSpace.Ycck, precision) { } /// - public override void ConvertToRgbInplace(in ComponentValues values) + public override void ConvertToRgbInPlace(in ComponentValues values) { ref Vector256 c0Base = ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); @@ -31,13 +30,13 @@ internal abstract partial class JpegColorConverterBase ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); // Used for the color conversion - 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(YCbCrScalar.RCrMult); - var gCbMult = Vector256.Create(-YCbCrScalar.GCbMult); - var gCrMult = Vector256.Create(-YCbCrScalar.GCrMult); - var bCbMult = Vector256.Create(YCbCrScalar.BCbMult); + Vector256 chromaOffset = Vector256.Create(-this.HalfValue); + Vector256 scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); + Vector256 max = Vector256.Create(this.MaximumValue); + Vector256 rCrMult = Vector256.Create(YCbCrScalar.RCrMult); + Vector256 gCbMult = Vector256.Create(-YCbCrScalar.GCbMult); + Vector256 gCrMult = Vector256.Create(-YCbCrScalar.GCrMult); + Vector256 bCbMult = Vector256.Create(YCbCrScalar.BCbMult); // Walking 8 elements at one step: nuint n = values.Component0.Vector256Count(); @@ -51,25 +50,24 @@ internal abstract partial class JpegColorConverterBase ref Vector256 c1 = ref Unsafe.Add(ref c1Base, i); ref Vector256 c2 = ref Unsafe.Add(ref c2Base, i); Vector256 y = c0; - Vector256 cb = Avx.Add(c1, chromaOffset); - Vector256 cr = Avx.Add(c2, chromaOffset); - Vector256 scaledK = Avx.Multiply(Unsafe.Add(ref kBase, i), scale); + Vector256 cb = c1 + chromaOffset; + Vector256 cr = c2 + chromaOffset; + Vector256 scaledK = Unsafe.Add(ref kBase, i) * scale; // r = y + (1.402F * cr); // g = y - (0.344136F * cb) - (0.714136F * cr); // b = y + (1.772F * cb); - 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); + Vector256 r = Vector256_.MultiplyAdd(y, cr, rCrMult); + Vector256 g = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); + Vector256 b = Vector256_.MultiplyAdd(y, cb, bCbMult); - r = Avx.Subtract(max, Avx.RoundToNearestInteger(r)); - g = Avx.Subtract(max, Avx.RoundToNearestInteger(g)); - b = Avx.Subtract(max, Avx.RoundToNearestInteger(b)); + r = max - Vector256_.RoundToNearestInteger(r); + g = max - Vector256_.RoundToNearestInteger(g); + b = max - Vector256_.RoundToNearestInteger(b); - r = Avx.Multiply(r, scaledK); - g = Avx.Multiply(g, scaledK); - b = Avx.Multiply(b, scaledK); + r *= scaledK; + g *= scaledK; + b *= scaledK; c0 = r; c1 = g; @@ -81,7 +79,7 @@ internal abstract partial class JpegColorConverterBase public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) { // rgb -> cmyk - CmykAvx.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane); + CmykVector256.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane); // cmyk -> ycck ref Vector256 destY = @@ -96,32 +94,32 @@ internal abstract partial class JpegColorConverterBase ref Vector256 srcB = ref destCr; // Used for the color conversion - var maxSampleValue = Vector256.Create(this.MaximumValue); + Vector256 maxSampleValue = Vector256.Create(this.MaximumValue); - var chromaOffset = Vector256.Create(this.HalfValue); + Vector256 chromaOffset = Vector256.Create(this.HalfValue); - var f0299 = Vector256.Create(0.299f); - var f0587 = Vector256.Create(0.587f); - var f0114 = Vector256.Create(0.114f); - var fn0168736 = Vector256.Create(-0.168736f); - var fn0331264 = Vector256.Create(-0.331264f); - var fn0418688 = Vector256.Create(-0.418688f); - var fn0081312F = Vector256.Create(-0.081312F); - var f05 = Vector256.Create(0.5f); + Vector256 f0299 = Vector256.Create(0.299f); + Vector256 f0587 = Vector256.Create(0.587f); + Vector256 f0114 = Vector256.Create(0.114f); + Vector256 fn0168736 = Vector256.Create(-0.168736f); + Vector256 fn0331264 = Vector256.Create(-0.331264f); + Vector256 fn0418688 = Vector256.Create(-0.418688f); + Vector256 fn0081312F = Vector256.Create(-0.081312F); + Vector256 f05 = Vector256.Create(0.5f); nuint n = values.Component0.Vector256Count(); for (nuint i = 0; i < n; i++) { - Vector256 r = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcR, i)); - Vector256 g = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcG, i)); - Vector256 b = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcB, i)); + Vector256 r = maxSampleValue - Unsafe.Add(ref srcR, i); + Vector256 g = maxSampleValue - Unsafe.Add(ref srcG, i); + Vector256 b = maxSampleValue - Unsafe.Add(ref srcB, i); // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) - Vector256 y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f0114, b), f0587, g), f0299, r); - Vector256 cb = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f05, b), fn0331264, g), fn0168736, r)); - Vector256 cr = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(fn0081312F, b), fn0418688, g), f05, r)); + Vector256 y = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f0114 * b, f0587, g), f0299, r); + Vector256 cb = chromaOffset + Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r); + Vector256 cr = chromaOffset + Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r); Unsafe.Add(ref destY, i) = y; Unsafe.Add(ref destCb, i) = cb; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector512.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector512.cs new file mode 100644 index 000000000..42d89a231 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector512.cs @@ -0,0 +1,144 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using Vector512_ = SixLabors.ImageSharp.Common.Helpers.Vector512Utilities; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components; + +internal abstract partial class JpegColorConverterBase +{ + internal sealed class YccKVector512 : JpegColorConverterVector512 + { + public YccKVector512(int precision) + : base(JpegColorSpace.Ycck, precision) + { + } + + /// + protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values) + { + ref Vector512 c0Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector512 c1Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector512 c2Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Vector512 kBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + + // Used for the color conversion + Vector512 chromaOffset = Vector512.Create(-this.HalfValue); + Vector512 scale = Vector512.Create(1 / (this.MaximumValue * this.MaximumValue)); + Vector512 max = Vector512.Create(this.MaximumValue); + Vector512 rCrMult = Vector512.Create(YCbCrScalar.RCrMult); + Vector512 gCbMult = Vector512.Create(-YCbCrScalar.GCbMult); + Vector512 gCrMult = Vector512.Create(-YCbCrScalar.GCrMult); + Vector512 bCbMult = Vector512.Create(YCbCrScalar.BCbMult); + + // Walking 8 elements at one step: + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + // y = yVals[i]; + // cb = cbVals[i] - 128F; + // cr = crVals[i] - 128F; + // k = kVals[i] / 256F; + ref Vector512 c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector512 c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector512 c2 = ref Unsafe.Add(ref c2Base, i); + Vector512 y = c0; + Vector512 cb = c1 + chromaOffset; + Vector512 cr = c2 + chromaOffset; + Vector512 scaledK = Unsafe.Add(ref kBase, i) * scale; + + // r = y + (1.402F * cr); + // g = y - (0.344136F * cb) - (0.714136F * cr); + // b = y + (1.772F * cb); + Vector512 r = Vector512_.MultiplyAdd(y, cr, rCrMult); + Vector512 g = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); + Vector512 b = Vector512_.MultiplyAdd(y, cb, bCbMult); + + r = max - Vector512_.RoundToNearestInteger(r); + g = max - Vector512_.RoundToNearestInteger(g); + b = max - Vector512_.RoundToNearestInteger(b); + + r *= scaledK; + g *= scaledK; + b *= scaledK; + + c0 = r; + c1 = g; + c2 = b; + } + } + + /// + protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values) + => YccKScalar.ConvertToRgpInPlace(values, this.MaximumValue, this.HalfValue); + + /// + protected override void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane) + { + // rgb -> cmyk + CmykVector512.ConvertFromRgbVectorized(in values, this.MaximumValue, rLane, gLane, bLane); + + // cmyk -> ycck + ref Vector512 destY = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector512 destCb = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector512 destCr = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + + ref Vector512 srcR = ref destY; + ref Vector512 srcG = ref destCb; + ref Vector512 srcB = ref destCr; + + // Used for the color conversion + Vector512 maxSampleValue = Vector512.Create(this.MaximumValue); + + Vector512 chromaOffset = Vector512.Create(this.HalfValue); + + Vector512 f0299 = Vector512.Create(0.299f); + Vector512 f0587 = Vector512.Create(0.587f); + Vector512 f0114 = Vector512.Create(0.114f); + Vector512 fn0168736 = Vector512.Create(-0.168736f); + Vector512 fn0331264 = Vector512.Create(-0.331264f); + Vector512 fn0418688 = Vector512.Create(-0.418688f); + Vector512 fn0081312F = Vector512.Create(-0.081312F); + Vector512 f05 = Vector512.Create(0.5f); + + nuint n = values.Component0.Vector512Count(); + for (nuint i = 0; i < n; i++) + { + Vector512 r = maxSampleValue - Unsafe.Add(ref srcR, i); + Vector512 g = maxSampleValue - Unsafe.Add(ref srcG, i); + Vector512 b = maxSampleValue - Unsafe.Add(ref srcB, i); + + // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) + // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) + // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) + Vector512 y = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f0114 * b, f0587, g), f0299, r); + Vector512 cb = chromaOffset + Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r); + Vector512 cr = chromaOffset + Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r); + + Unsafe.Add(ref destY, i) = y; + Unsafe.Add(ref destCb, i) = cb; + Unsafe.Add(ref destCr, i) = cr; + } + } + + /// + protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span rLane, Span gLane, Span bLane) + { + // rgb -> cmyk + CmykScalar.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane); + + // cmyk -> ycck + YccKScalar.ConvertFromRgb(in values, this.HalfValue, this.MaximumValue, rLane, gLane, bLane); + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm64.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm64.cs deleted file mode 100644 index d6d4d6ef9..000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm64.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using System.Runtime.Intrinsics.X86; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components; - -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 JpegColorConverterArm64 : JpegColorConverterBase - { - protected JpegColorConverterArm64(JpegColorSpace colorSpace, int precision) - : base(colorSpace, precision) - { - } - - public static bool IsSupported => AdvSimd.Arm64.IsSupported; - - public sealed override bool IsAvailable => IsSupported; - - public sealed override int ElementsPerBatch => Vector128.Count; - } -} diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs index 041f6b057..8cb3045dc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs @@ -71,25 +71,14 @@ internal abstract partial class JpegColorConverterBase /// The precision in bits. /// Invalid colorspace. public static JpegColorConverterBase GetConverter(JpegColorSpace colorSpace, int precision) - { - JpegColorConverterBase converter = Array.Find( - Converters, - c => c.ColorSpace == colorSpace - && c.Precision == precision); - - if (converter is null) - { - throw new InvalidImageContentException($"Could not find any converter for JpegColorSpace {colorSpace}!"); - } - - return converter; - } + => Array.Find(Converters, c => c.ColorSpace == colorSpace && c.Precision == precision) + ?? throw new InvalidImageContentException($"Could not find any converter for JpegColorSpace {colorSpace}!"); /// - /// Converts planar jpeg component values in to RGB color space inplace. + /// Converts planar jpeg component values in to RGB color space in-place. /// - /// The input/ouptut as a stack-only struct - public abstract void ConvertToRgbInplace(in ComponentValues values); + /// The input/output as a stack-only struct + public abstract void ConvertToRgbInPlace(in ComponentValues values); /// /// Converts RGB lanes to jpeg component values. @@ -101,31 +90,25 @@ internal abstract partial class JpegColorConverterBase public abstract void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane); /// - /// Returns the s for all supported colorspaces and precisions. + /// Returns the s for all supported color spaces and precisions. /// private static JpegColorConverterBase[] CreateConverters() - { - // 5 color types with 2 supported precisions: 8 bit & 12 bit - const int colorConvertersCount = 5 * 2; - - JpegColorConverterBase[] converters = new JpegColorConverterBase[colorConvertersCount]; - - // 8-bit converters - converters[0] = GetYCbCrConverter(8); - converters[1] = GetYccKConverter(8); - converters[2] = GetCmykConverter(8); - converters[3] = GetGrayScaleConverter(8); - converters[4] = GetRgbConverter(8); - - // 12-bit converters - converters[5] = GetYCbCrConverter(12); - converters[6] = GetYccKConverter(12); - converters[7] = GetCmykConverter(12); - converters[8] = GetGrayScaleConverter(12); - converters[9] = GetRgbConverter(12); - - return converters; - } + => [ + + // 8-bit converters + GetYCbCrConverter(8), + GetYccKConverter(8), + GetCmykConverter(8), + GetGrayScaleConverter(8), + GetRgbConverter(8), + + // 12-bit converters + GetYCbCrConverter(12), + GetYccKConverter(12), + GetCmykConverter(12), + GetGrayScaleConverter(12), + GetRgbConverter(12), + ]; /// /// Returns the s for the YCbCr colorspace. @@ -133,19 +116,19 @@ internal abstract partial class JpegColorConverterBase /// The precision in bits. private static JpegColorConverterBase GetYCbCrConverter(int precision) { - if (JpegColorConverterAvx.IsSupported) + if (JpegColorConverterVector512.IsSupported) { - return new YCbCrAvx(precision); + return new YCbCrVector512(precision); } - if (JpegColorConverterArm.IsSupported) + if (JpegColorConverterVector256.IsSupported) { - return new YCbCrArm(precision); + return new YCbCrVector256(precision); } - if (JpegColorConverterVector.IsSupported) + if (JpegColorConverterVector128.IsSupported) { - return new YCbCrVector(precision); + return new YCbCrVector128(precision); } return new YCbCrScalar(precision); @@ -157,19 +140,19 @@ internal abstract partial class JpegColorConverterBase /// The precision in bits. private static JpegColorConverterBase GetYccKConverter(int precision) { - if (JpegColorConverterAvx.IsSupported) + if (JpegColorConverterVector512.IsSupported) { - return new YccKAvx(precision); + return new YccKVector512(precision); } - if (JpegColorConverterArm64.IsSupported) + if (JpegColorConverterVector256.IsSupported) { - return new YccKArm64(precision); + return new YccKVector256(precision); } - if (JpegColorConverterVector.IsSupported) + if (JpegColorConverterVector128.IsSupported) { - return new YccKVector(precision); + return new YccKVector128(precision); } return new YccKScalar(precision); @@ -181,19 +164,19 @@ internal abstract partial class JpegColorConverterBase /// The precision in bits. private static JpegColorConverterBase GetCmykConverter(int precision) { - if (JpegColorConverterAvx.IsSupported) + if (JpegColorConverterVector512.IsSupported) { - return new CmykAvx(precision); + return new CmykVector512(precision); } - if (JpegColorConverterArm64.IsSupported) + if (JpegColorConverterVector256.IsSupported) { - return new CmykArm64(precision); + return new CmykVector256(precision); } - if (JpegColorConverterVector.IsSupported) + if (JpegColorConverterVector128.IsSupported) { - return new CmykVector(precision); + return new CmykVector128(precision); } return new CmykScalar(precision); @@ -205,22 +188,22 @@ internal abstract partial class JpegColorConverterBase /// The precision in bits. private static JpegColorConverterBase GetGrayScaleConverter(int precision) { - if (JpegColorConverterAvx.IsSupported) + if (JpegColorConverterVector512.IsSupported) { - return new GrayscaleAvx(precision); + return new GrayScaleVector512(precision); } - if (JpegColorConverterArm.IsSupported) + if (JpegColorConverterVector256.IsSupported) { - return new GrayscaleArm(precision); + return new GrayScaleVector256(precision); } - if (JpegColorConverterVector.IsSupported) + if (JpegColorConverterVector128.IsSupported) { - return new GrayScaleVector(precision); + return new GrayScaleVector128(precision); } - return new GrayscaleScalar(precision); + return new GrayScaleScalar(precision); } /// @@ -229,19 +212,19 @@ internal abstract partial class JpegColorConverterBase /// The precision in bits. private static JpegColorConverterBase GetRgbConverter(int precision) { - if (JpegColorConverterAvx.IsSupported) + if (JpegColorConverterVector512.IsSupported) { - return new RgbAvx(precision); + return new RgbVector512(precision); } - if (JpegColorConverterArm.IsSupported) + if (JpegColorConverterVector256.IsSupported) { - return new RgbArm(precision); + return new RgbVector256(precision); } - if (JpegColorConverterVector.IsSupported) + if (JpegColorConverterVector128.IsSupported) { - return new RgbVector(precision); + return new RgbVector128(precision); } return new RgbScalar(precision); @@ -295,7 +278,7 @@ internal abstract partial class JpegColorConverterBase // 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.Component3 = this.ComponentCount > 3 ? componentBuffers[3].DangerousGetRowSpan(row) : []; } /// @@ -314,7 +297,7 @@ internal abstract partial class JpegColorConverterBase // In case of grayscale, Component1 and Component2 point to Component0 memory area 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; + this.Component3 = this.ComponentCount > 3 ? processors[3].GetColorBufferRowSpan(row) : []; } /// @@ -333,7 +316,7 @@ internal abstract partial class JpegColorConverterBase // In case of grayscale, Component1 and Component2 point to Component0 memory area 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; + this.Component3 = this.ComponentCount > 3 ? processors[3].GetColorBufferRowSpan(row) : []; } internal ComponentValues( @@ -353,9 +336,9 @@ internal abstract partial class JpegColorConverterBase public ComponentValues Slice(int start, int length) { Span c0 = this.Component0.Slice(start, length); - Span c1 = this.Component1.Length > 0 ? this.Component1.Slice(start, length) : Span.Empty; - Span c2 = this.Component2.Length > 0 ? this.Component2.Slice(start, length) : Span.Empty; - Span c3 = this.Component3.Length > 0 ? this.Component3.Slice(start, length) : Span.Empty; + Span c1 = this.Component1.Length > 0 ? this.Component1.Slice(start, length) : []; + Span c2 = this.Component2.Length > 0 ? this.Component2.Slice(start, length) : []; + Span c3 = this.Component3.Length > 0 ? this.Component3.Slice(start, length) : []; return new ComponentValues(this.ComponentCount, c0, c1, c2, c3); } diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs index 5f9688a79..f3c3eb8db 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs @@ -36,7 +36,7 @@ internal abstract partial class JpegColorConverterBase public override int ElementsPerBatch => Vector.Count; /// - public sealed override void ConvertToRgbInplace(in ComponentValues values) + public sealed override void ConvertToRgbInPlace(in ComponentValues values) { DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware."); @@ -46,7 +46,7 @@ internal abstract partial class JpegColorConverterBase int simdCount = length - remainder; if (simdCount > 0) { - this.ConvertToRgbInplaceVectorized(values.Slice(0, simdCount)); + this.ConvertToRgbInPlaceVectorized(values.Slice(0, simdCount)); } // Jpeg images width is always divisible by 8 without a remainder @@ -56,12 +56,12 @@ internal abstract partial class JpegColorConverterBase // remainder pixels if (remainder > 0) { - this.ConvertToRgbInplaceScalarRemainder(values.Slice(simdCount, remainder)); + this.ConvertToRgbInPlaceScalarRemainder(values.Slice(simdCount, remainder)); } } /// - public sealed override void ConvertFromRgb(in ComponentValues values, Span r, Span g, Span b) + public sealed override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) { DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware."); @@ -73,9 +73,9 @@ internal abstract partial class JpegColorConverterBase { this.ConvertFromRgbVectorized( values.Slice(0, simdCount), - r.Slice(0, simdCount), - g.Slice(0, simdCount), - b.Slice(0, simdCount)); + rLane[..simdCount], + gLane[..simdCount], + bLane[..simdCount]); } // Jpeg images width is always divisible by 8 without a remainder @@ -87,25 +87,25 @@ internal abstract partial class JpegColorConverterBase { this.ConvertFromRgbScalarRemainder( values.Slice(simdCount, remainder), - r.Slice(simdCount, remainder), - g.Slice(simdCount, remainder), - b.Slice(simdCount, remainder)); + rLane.Slice(simdCount, remainder), + gLane.Slice(simdCount, remainder), + bLane.Slice(simdCount, remainder)); } } /// /// Converts planar jpeg component values in - /// to RGB color space inplace using API. + /// to RGB color space in place using API. /// - /// The input/ouptut as a stack-only struct - protected abstract void ConvertToRgbInplaceVectorized(in ComponentValues values); + /// The input/output as a stack-only struct + protected abstract void ConvertToRgbInPlaceVectorized(in ComponentValues values); /// /// Converts remainder of the planar jpeg component values after - /// conversion in . + /// conversion in . /// - /// The input/ouptut as a stack-only struct - protected abstract void ConvertToRgbInplaceScalarRemainder(in ComponentValues values); + /// The input/output as a stack-only struct + protected abstract void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values); /// /// Converts RGB lanes to jpeg component values using API. diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector128.cs similarity index 71% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector128.cs index bfbbf200c..5cbb376c7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector128.cs @@ -1,8 +1,7 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. + using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -10,7 +9,7 @@ internal abstract partial class JpegColorConverterBase { /// /// abstract base for implementations - /// based on instructions. + /// based on instructions. /// /// /// Converters of this family would expect input buffers lengths to be @@ -19,14 +18,14 @@ internal abstract partial class JpegColorConverterBase /// 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 JpegColorConverterArm : JpegColorConverterBase + internal abstract class JpegColorConverterVector128 : JpegColorConverterBase { - protected JpegColorConverterArm(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterVector128(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { } - public static bool IsSupported => AdvSimd.IsSupported; + public static bool IsSupported => Vector128.IsHardwareAccelerated; public sealed override bool IsAvailable => IsSupported; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector256.cs similarity index 73% rename from src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs rename to src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector256.cs index a3e41bdc6..61c37d846 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector256.cs @@ -1,7 +1,7 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. + using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -9,7 +9,7 @@ internal abstract partial class JpegColorConverterBase { /// /// abstract base for implementations - /// based on instructions. + /// based on instructions. /// /// /// Converters of this family would expect input buffers lengths to be @@ -18,14 +18,14 @@ internal abstract partial class JpegColorConverterBase /// 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 JpegColorConverterAvx : JpegColorConverterBase + internal abstract class JpegColorConverterVector256 : JpegColorConverterBase { - protected JpegColorConverterAvx(JpegColorSpace colorSpace, int precision) + protected JpegColorConverterVector256(JpegColorSpace colorSpace, int precision) : base(colorSpace, precision) { } - public static bool IsSupported => Avx.IsSupported; + public static bool IsSupported => Vector256.IsHardwareAccelerated; public sealed override bool IsAvailable => IsSupported; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector512.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector512.cs new file mode 100644 index 000000000..0c7d032d4 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector512.cs @@ -0,0 +1,111 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.Intrinsics; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components; + +internal abstract partial class JpegColorConverterBase +{ + /// + /// abstract base for implementations + /// based on instructions. + /// + internal abstract class JpegColorConverterVector512 : JpegColorConverterBase + { + protected JpegColorConverterVector512(JpegColorSpace colorSpace, int precision) + : base(colorSpace, precision) + { + } + + public static bool IsSupported => Vector512.IsHardwareAccelerated; + + /// + public override bool IsAvailable => IsSupported; + + /// + public override int ElementsPerBatch => Vector512.Count; + + /// + public sealed override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane) + { + DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware."); + + int length = values.Component0.Length; + int remainder = (int)((uint)length % (uint)Vector512.Count); + + int simdCount = length - remainder; + if (simdCount > 0) + { + this.ConvertFromRgbVectorized( + values.Slice(0, simdCount), + rLane[..simdCount], + gLane[..simdCount], + bLane[..simdCount]); + } + + if (remainder > 0) + { + this.ConvertFromRgbScalarRemainder( + values.Slice(simdCount, remainder), + rLane.Slice(simdCount, remainder), + gLane.Slice(simdCount, remainder), + bLane.Slice(simdCount, remainder)); + } + } + + /// + public sealed 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 = (int)((uint)length % (uint)Vector512.Count); + + int simdCount = length - remainder; + if (simdCount > 0) + { + this.ConvertToRgbInPlaceVectorized(values.Slice(0, simdCount)); + } + + if (remainder > 0) + { + this.ConvertToRgbInPlaceScalarRemainder(values.Slice(simdCount, remainder)); + } + } + + /// + /// Converts planar jpeg component values in + /// to RGB color space in place using API. + /// + /// The input/output as a stack-only struct + protected abstract void ConvertToRgbInPlaceVectorized(in ComponentValues values); + + /// + /// Converts remainder of the planar jpeg component values after + /// conversion in . + /// + /// The input/output as a stack-only struct + protected abstract void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values); + + /// + /// Converts RGB lanes to jpeg component values using API. + /// + /// Jpeg component values. + /// Red colors lane. + /// Green colors lane. + /// Blue colors lane. + protected abstract void ConvertFromRgbVectorized(in ComponentValues values, Span rLane, Span gLane, Span bLane); + + /// + /// Converts remainder of RGB lanes to jpeg component values after + /// conversion in . + /// + /// Jpeg component values. + /// Red colors lane. + /// Green colors lane. + /// Blue colors lane. + protected abstract void ConvertFromRgbScalarRemainder(in ComponentValues values, Span rLane, Span gLane, Span bLane); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 7f89baba5..561d273e6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -141,7 +141,7 @@ internal class SpectralConverter : SpectralConverter, IDisposable JpegColorConverterBase.ComponentValues values = new(this.componentProcessors, y); - this.colorConverter.ConvertToRgbInplace(values); + this.colorConverter.ConvertToRgbInPlace(values); values = values.Slice(0, width); // slice away Jpeg padding Span r = this.rgbBuffer.Slice(0, width); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 9189bec37..a1ba3fb8d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -17,32 +17,32 @@ public class CmykColorConversion : ColorConversionBenchmark [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.CmykScalar(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.CmykScalar(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVector8() + public void SimdVector128() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.CmykVector(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.CmykVector128(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorAvx() + public void SimdVector256() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.CmykAvx(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.CmykVector256(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorArm64() + public void SimdVector512() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.CmykArm64(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.CmykVector512(8).ConvertToRgbInPlace(values); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs index a1d85ef46..3ade4279f 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs @@ -7,9 +7,9 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; [Config(typeof(Config.Short))] -public class GrayscaleColorConversion : ColorConversionBenchmark +public class GrayScaleColorConversion : ColorConversionBenchmark { - public GrayscaleColorConversion() + public GrayScaleColorConversion() : base(1) { } @@ -17,24 +17,32 @@ public class GrayscaleColorConversion : ColorConversionBenchmark [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.GrayscaleScalar(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.GrayScaleScalar(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorAvx() + public void SimdVector128() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.GrayscaleAvx(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.GrayScaleVector128(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorArm() + public void SimdVector256() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.GrayscaleArm(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.GrayScaleVector256(8).ConvertToRgbInPlace(values); + } + + [Benchmark] + public void SimdVector512() + { + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); + + new JpegColorConverterBase.GrayScaleVector512(8).ConvertToRgbInPlace(values); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index 5e2b6fe86..2916dcdce 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -17,32 +17,32 @@ public class RgbColorConversion : ColorConversionBenchmark [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.RgbScalar(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.RgbScalar(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVector8() + public void SimdVector128() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.RgbVector(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.RgbVector128(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorAvx() + public void SimdVector256() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.RgbAvx(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.RgbVector256(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorArm() + public void SimdVector512() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.RgbArm(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.RgbVector512(8).ConvertToRgbInPlace(values); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index f8621c250..fbd762af4 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -17,32 +17,32 @@ public class YCbCrColorConversion : ColorConversionBenchmark [Benchmark] public void Scalar() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.YCbCrScalar(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.YCbCrScalar(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVector8() + public void SimdVector128() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.YCbCrVector(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.YCbCrVector128(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorAvx() + public void SimdVector256() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.YCbCrAvx(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.YCbCrVector256(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorArm() + public void SimdVector512() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.YCbCrArm(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.YCbCrVector512(8).ConvertToRgbInPlace(values); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index a414b6ed4..e6b04c152 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -17,32 +17,32 @@ public class YccKColorConverter : ColorConversionBenchmark [Benchmark(Baseline = true)] public void Scalar() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.YccKScalar(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.YccKScalar(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVector8() + public void SimdVector128() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.YccKVector(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.YccKVector128(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorAvx2() + public void SimdVector256() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.YccKAvx(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.YccKVector256(8).ConvertToRgbInPlace(values); } [Benchmark] - public void SimdVectorArm64() + public void SimdVector512() { - var values = new JpegColorConverterBase.ComponentValues(this.Input, 0); + JpegColorConverterBase.ComponentValues values = new(this.Input, 0); - new JpegColorConverterBase.YccKArm64(8).ConvertToRgbInplace(values); + new JpegColorConverterBase.YccKVector512(8).ConvertToRgbInPlace(values); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 7aabdaa58..25e605cef 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -21,7 +21,7 @@ public class JpegColorConverterTests private const int TestBufferLength = 40; - private const HwIntrinsics IntrinsicsConfig = HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2; + private const HwIntrinsics IntrinsicsConfig = HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX2; private static readonly ApproximateColorProfileComparer ColorSpaceComparer = new(epsilon: Precision); @@ -75,23 +75,23 @@ public class JpegColorConverterTests { FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableHWIntrinsic); + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableHWIntrinsic); static void RunTest(string arg) { // arrange Type expectedType = typeof(JpegColorConverterBase.RgbScalar); - if (Avx.IsSupported) + if (JpegColorConverterBase.JpegColorConverterVector512.IsSupported) { - expectedType = typeof(JpegColorConverterBase.RgbAvx); + expectedType = typeof(JpegColorConverterBase.RgbVector512); } - else if (Sse2.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector256.IsSupported) { - expectedType = typeof(JpegColorConverterBase.RgbVector); + expectedType = typeof(JpegColorConverterBase.RgbVector256); } - else if (AdvSimd.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector128.IsSupported) { - expectedType = typeof(JpegColorConverterBase.RgbArm); + expectedType = typeof(JpegColorConverterBase.RgbVector128); } // act @@ -108,23 +108,23 @@ public class JpegColorConverterTests { FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableHWIntrinsic); + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableHWIntrinsic); static void RunTest(string arg) { // arrange - Type expectedType = typeof(JpegColorConverterBase.GrayscaleScalar); - if (Avx.IsSupported) + Type expectedType = typeof(JpegColorConverterBase.GrayScaleScalar); + if (JpegColorConverterBase.JpegColorConverterVector512.IsSupported) { - expectedType = typeof(JpegColorConverterBase.GrayscaleAvx); + expectedType = typeof(JpegColorConverterBase.GrayScaleVector512); } - else if (Sse2.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector256.IsSupported) { - expectedType = typeof(JpegColorConverterBase.GrayScaleVector); + expectedType = typeof(JpegColorConverterBase.GrayScaleVector256); } - else if (AdvSimd.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector128.IsSupported) { - expectedType = typeof(JpegColorConverterBase.GrayscaleArm); + expectedType = typeof(JpegColorConverterBase.GrayScaleVector128); } // act @@ -147,17 +147,17 @@ public class JpegColorConverterTests { // arrange Type expectedType = typeof(JpegColorConverterBase.CmykScalar); - if (Avx.IsSupported) + if (JpegColorConverterBase.JpegColorConverterVector512.IsSupported) { - expectedType = typeof(JpegColorConverterBase.CmykAvx); + expectedType = typeof(JpegColorConverterBase.CmykVector512); } - else if (Sse2.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector256.IsSupported) { - expectedType = typeof(JpegColorConverterBase.CmykVector); + expectedType = typeof(JpegColorConverterBase.CmykVector256); } - else if (AdvSimd.Arm64.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector128.IsSupported) { - expectedType = typeof(JpegColorConverterBase.CmykArm64); + expectedType = typeof(JpegColorConverterBase.CmykVector128); } // act @@ -174,23 +174,23 @@ public class JpegColorConverterTests { FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableHWIntrinsic); + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableHWIntrinsic); static void RunTest(string arg) { // arrange Type expectedType = typeof(JpegColorConverterBase.YCbCrScalar); - if (Avx.IsSupported) + if (JpegColorConverterBase.JpegColorConverterVector512.IsSupported) { - expectedType = typeof(JpegColorConverterBase.YCbCrAvx); + expectedType = typeof(JpegColorConverterBase.YCbCrVector512); } - else if (Sse2.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector256.IsSupported) { - expectedType = typeof(JpegColorConverterBase.YCbCrVector); + expectedType = typeof(JpegColorConverterBase.YCbCrVector256); } - else if (AdvSimd.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector128.IsSupported) { - expectedType = typeof(JpegColorConverterBase.YCbCrArm); + expectedType = typeof(JpegColorConverterBase.YCbCrVector128); } // act @@ -207,23 +207,23 @@ public class JpegColorConverterTests { FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableHWIntrinsic); + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE2 | HwIntrinsics.DisableHWIntrinsic); static void RunTest(string arg) { // arrange Type expectedType = typeof(JpegColorConverterBase.YccKScalar); - if (Avx.IsSupported) + if (JpegColorConverterBase.JpegColorConverterVector512.IsSupported) { - expectedType = typeof(JpegColorConverterBase.YccKAvx); + expectedType = typeof(JpegColorConverterBase.YccKVector512); } - else if (Sse2.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector256.IsSupported) { - expectedType = typeof(JpegColorConverterBase.YccKVector); + expectedType = typeof(JpegColorConverterBase.YccKVector256); } - else if (AdvSimd.Arm64.IsSupported) + else if (JpegColorConverterBase.JpegColorConverterVector128.IsSupported) { - expectedType = typeof(JpegColorConverterBase.YccKArm64); + expectedType = typeof(JpegColorConverterBase.YccKVector128); } // act @@ -257,323 +257,308 @@ public class JpegColorConverterTests [Theory] [MemberData(nameof(Seeds))] - public void FromYCbCrVector(int seed) - { - JpegColorConverterBase.YCbCrVector converter = new(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - FeatureTestRunner.RunWithHwIntrinsicsFeature( - RunTest, + public void FromYCbCrVector512(int seed) => + this.TestConversionToRgb( + new JpegColorConverterBase.YCbCrVector512(8), + 3, seed, - IntrinsicsConfig); - - static void RunTest(string arg) => - ValidateConversionToRgb( - new JpegColorConverterBase.YCbCrVector(8), - 3, - FeatureTestRunner.Deserialize(arg), - new JpegColorConverterBase.YCbCrScalar(8)); - } - - [Theory] - [MemberData(nameof(Seeds))] - public void FromCmykBasic(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.CmykScalar(8), 4, seed); + new JpegColorConverterBase.YCbCrScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromCmykVector(int seed) - { - JpegColorConverterBase.CmykVector converter = new(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - FeatureTestRunner.RunWithHwIntrinsicsFeature( - RunTest, + public void FromYCbCrVector256(int seed) => + this.TestConversionToRgb( + new JpegColorConverterBase.YCbCrVector256(8), + 3, seed, - IntrinsicsConfig); - - static void RunTest(string arg) => - ValidateConversionToRgb( - new JpegColorConverterBase.CmykVector(8), - 4, - FeatureTestRunner.Deserialize(arg), - new JpegColorConverterBase.CmykScalar(8)); - } + new JpegColorConverterBase.YCbCrScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromGrayscaleBasic(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.GrayscaleScalar(8), 1, seed); + public void FromYCbCrVector128(int seed) => + this.TestConversionToRgb( + new JpegColorConverterBase.YCbCrVector128(8), + 3, + seed, + new JpegColorConverterBase.YCbCrScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromGrayscaleVector(int seed) - { - JpegColorConverterBase.GrayScaleVector converter = new(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - FeatureTestRunner.RunWithHwIntrinsicsFeature( - RunTest, + public void FromRgbToYCbCrVector512(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.YCbCrVector512(8), + 3, seed, - IntrinsicsConfig); - - static void RunTest(string arg) => - ValidateConversionToRgb( - new JpegColorConverterBase.GrayScaleVector(8), - 1, - FeatureTestRunner.Deserialize(arg), - new JpegColorConverterBase.GrayscaleScalar(8)); - } + new JpegColorConverterBase.YCbCrScalar(8), + precision: 2); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbBasic(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.RgbScalar(8), 3, seed); + public void FromRgbToYCbCrVector256(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.YCbCrVector256(8), + 3, + seed, + new JpegColorConverterBase.YCbCrScalar(8), + precision: 2); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbVector(int seed) - { - JpegColorConverterBase.RgbVector converter = new(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - FeatureTestRunner.RunWithHwIntrinsicsFeature( - RunTest, - seed, - IntrinsicsConfig); - - static void RunTest(string arg) => - ValidateConversionToRgb( - new JpegColorConverterBase.RgbVector(8), - 3, - FeatureTestRunner.Deserialize(arg), - new JpegColorConverterBase.RgbScalar(8)); - } + public void FromRgbToYCbCrVector128(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.YCbCrVector128(8), + 3, + seed, + new JpegColorConverterBase.YCbCrScalar(8), + precision: 2); [Theory] [MemberData(nameof(Seeds))] - public void FromYccKBasic(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.YccKScalar(8), 4, seed); + public void FromCmykBasic(int seed) => + this.TestConversionToRgb(new JpegColorConverterBase.CmykScalar(8), 4, seed); [Theory] [MemberData(nameof(Seeds))] - public void FromYccKVector(int seed) - { - JpegColorConverterBase.YccKVector converter = new(8); - - if (!converter.IsAvailable) - { - this.Output.WriteLine( - $"Skipping test - {converter.GetType().Name} is not supported on current hardware."); - return; - } - - FeatureTestRunner.RunWithHwIntrinsicsFeature( - RunTest, + public void FromCmykVector512(int seed) => + this.TestConversionToRgb( + new JpegColorConverterBase.CmykVector512(8), + 4, seed, - IntrinsicsConfig); - - static void RunTest(string arg) => - ValidateConversionToRgb( - new JpegColorConverterBase.YccKVector(8), - 4, - FeatureTestRunner.Deserialize(arg), - new JpegColorConverterBase.YccKScalar(8)); - } + new JpegColorConverterBase.CmykScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromYCbCrAvx2(int seed) => + public void FromCmykVector256(int seed) => this.TestConversionToRgb( - new JpegColorConverterBase.YCbCrAvx(8), - 3, + new JpegColorConverterBase.CmykVector256(8), + 4, seed, - new JpegColorConverterBase.YCbCrScalar(8)); + new JpegColorConverterBase.CmykScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbToYCbCrAvx2(int seed) => - this.TestConversionFromRgb( - new JpegColorConverterBase.YCbCrAvx(8), - 3, + public void FromCmykVector128(int seed) => + this.TestConversionToRgb( + new JpegColorConverterBase.CmykVector128(8), + 4, seed, - new JpegColorConverterBase.YCbCrScalar(8), - precísion: 2); + new JpegColorConverterBase.CmykScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromYCbCrArm(int seed) => - this.TestConversionToRgb( - new JpegColorConverterBase.YCbCrArm(8), - 3, + public void FromRgbToCmykVector512(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.CmykVector512(8), + 4, seed, - new JpegColorConverterBase.YCbCrScalar(8)); + new JpegColorConverterBase.CmykScalar(8), + precision: 2); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbToYCbCrArm(int seed) => - this.TestConversionFromRgb( - new JpegColorConverterBase.YCbCrArm(8), - 3, - seed, - new JpegColorConverterBase.YCbCrScalar(8), - precísion: 2); + public void FromRgbToCmykVector256(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.CmykVector256(8), + 4, + seed, + new JpegColorConverterBase.CmykScalar(8), + precision: 2); [Theory] [MemberData(nameof(Seeds))] - public void FromCmykAvx2(int seed) => - this.TestConversionToRgb( - new JpegColorConverterBase.CmykAvx(8), - 4, - seed, - new JpegColorConverterBase.CmykScalar(8)); + public void FromRgbToCmykVector128(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.CmykVector128(8), + 4, + seed, + new JpegColorConverterBase.CmykScalar(8), + precision: 2); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbToCmykAvx2(int seed) => - this.TestConversionFromRgb( - new JpegColorConverterBase.CmykAvx(8), - 4, - seed, - new JpegColorConverterBase.CmykScalar(8), - precísion: 4); + public void FromGrayScaleBasic(int seed) => + this.TestConversionToRgb(new JpegColorConverterBase.GrayScaleScalar(8), 1, seed); [Theory] [MemberData(nameof(Seeds))] - public void FromCmykArm(int seed) => + public void FromGrayScaleVector512(int seed) => this.TestConversionToRgb( - new JpegColorConverterBase.CmykArm64(8), - 4, + new JpegColorConverterBase.GrayScaleVector512(8), + 1, seed, - new JpegColorConverterBase.CmykScalar(8)); + new JpegColorConverterBase.GrayScaleScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbToCmykArm(int seed) => - this.TestConversionFromRgb( - new JpegColorConverterBase.CmykArm64(8), - 4, + public void FromGrayScaleVector256(int seed) => + this.TestConversionToRgb( + new JpegColorConverterBase.GrayScaleVector256(8), + 1, seed, - new JpegColorConverterBase.CmykScalar(8), - precísion: 4); + new JpegColorConverterBase.GrayScaleScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromGrayscaleAvx2(int seed) => + public void FromGrayScaleVector128(int seed) => this.TestConversionToRgb( - new JpegColorConverterBase.GrayscaleAvx(8), + new JpegColorConverterBase.GrayScaleVector128(8), 1, seed, - new JpegColorConverterBase.GrayscaleScalar(8)); + new JpegColorConverterBase.GrayScaleScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbToGrayscaleAvx2(int seed) => + public void FromRgbToGrayScaleVector512(int seed) => this.TestConversionFromRgb( - new JpegColorConverterBase.GrayscaleAvx(8), + new JpegColorConverterBase.GrayScaleVector512(8), 1, seed, - new JpegColorConverterBase.GrayscaleScalar(8), - precísion: 3); + new JpegColorConverterBase.GrayScaleScalar(8), + precision: 2); [Theory] [MemberData(nameof(Seeds))] - public void FromGrayscaleArm(int seed) => - this.TestConversionToRgb( - new JpegColorConverterBase.GrayscaleArm(8), - 1, - seed, - new JpegColorConverterBase.GrayscaleScalar(8)); + public void FromRgbToGrayScaleVector256(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.GrayScaleVector256(8), + 1, + seed, + new JpegColorConverterBase.GrayScaleScalar(8), + precision: 2); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbToGrayscaleArm(int seed) => - this.TestConversionFromRgb( - new JpegColorConverterBase.GrayscaleArm(8), - 1, + public void FromRgbToGrayScaleVector128(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.GrayScaleVector128(8), + 1, + seed, + new JpegColorConverterBase.GrayScaleScalar(8), + precision: 2); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromRgbBasic(int seed) => + this.TestConversionToRgb(new JpegColorConverterBase.RgbScalar(8), 3, seed); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromRgbVector512(int seed) => + this.TestConversionToRgb( + new JpegColorConverterBase.RgbVector512(8), + 3, seed, - new JpegColorConverterBase.GrayscaleScalar(8), - precísion: 3); + new JpegColorConverterBase.RgbScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbAvx2(int seed) => + public void FromRgbVector256(int seed) => this.TestConversionToRgb( - new JpegColorConverterBase.RgbAvx(8), + new JpegColorConverterBase.RgbVector256(8), 3, seed, new JpegColorConverterBase.RgbScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbArm(int seed) => + public void FromRgbVector128(int seed) => this.TestConversionToRgb( - new JpegColorConverterBase.RgbArm(8), + new JpegColorConverterBase.RgbVector128(8), 3, seed, new JpegColorConverterBase.RgbScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromYccKAvx2(int seed) => + public void FromRgbToRgbVector512(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.RgbVector512(8), + 3, + seed, + new JpegColorConverterBase.RgbScalar(8), + precision: 2); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromRgbToRgbVector256(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.RgbVector256(8), + 3, + seed, + new JpegColorConverterBase.RgbScalar(8), + precision: 2); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromRgbToRgbVector128(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.RgbVector128(8), + 3, + seed, + new JpegColorConverterBase.RgbScalar(8), + precision: 2); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromYccKBasic(int seed) => + this.TestConversionToRgb(new JpegColorConverterBase.YccKScalar(8), 4, seed); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromYccKVector512(int seed) => this.TestConversionToRgb( - new JpegColorConverterBase.YccKAvx(8), + new JpegColorConverterBase.YccKVector512(8), 4, seed, new JpegColorConverterBase.YccKScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbToYccKAvx2(int seed) => - this.TestConversionFromRgb( - new JpegColorConverterBase.YccKAvx(8), + public void FromYccKVector256(int seed) => + this.TestConversionToRgb( + new JpegColorConverterBase.YccKVector256(8), 4, seed, - new JpegColorConverterBase.YccKScalar(8), - precísion: 4); + new JpegColorConverterBase.YccKScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromYccKArm64(int seed) => + public void FromYccKVector128(int seed) => this.TestConversionToRgb( - new JpegColorConverterBase.YccKArm64(8), + new JpegColorConverterBase.YccKVector128(8), 4, seed, new JpegColorConverterBase.YccKScalar(8)); [Theory] [MemberData(nameof(Seeds))] - public void FromRgbToYccKArm64(int seed) => + public void FromRgbToYccKVector512(int seed) => this.TestConversionFromRgb( - new JpegColorConverterBase.YccKArm64(8), + new JpegColorConverterBase.YccKVector512(8), 4, seed, new JpegColorConverterBase.YccKScalar(8), - precísion: 4); + precision: 2); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromRgbToYccKVector256(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.YccKVector256(8), + 4, + seed, + new JpegColorConverterBase.YccKScalar(8), + precision: 2); + + [Theory] + [MemberData(nameof(Seeds))] + public void FromRgbToYccKVector128(int seed) => + this.TestConversionFromRgb( + new JpegColorConverterBase.YccKVector128(8), + 4, + seed, + new JpegColorConverterBase.YccKScalar(8), + precision: 2); private void TestConversionToRgb( JpegColorConverterBase converter, @@ -600,7 +585,7 @@ public class JpegColorConverterTests int componentCount, int seed, JpegColorConverterBase baseLineConverter, - int precísion) + int precision) { if (!converter.IsAvailable) { @@ -614,7 +599,7 @@ public class JpegColorConverterTests componentCount, seed, baseLineConverter, - precísion); + precision); } private static JpegColorConverterBase.ComponentValues CreateRandomValues( @@ -669,7 +654,7 @@ public class JpegColorConverterTests original.Component2.ToArray(), original.Component3.ToArray()); - converter.ConvertToRgbInplace(actual); + converter.ConvertToRgbInPlace(actual); for (int i = 0; i < TestBufferLength; i++) { @@ -685,7 +670,7 @@ public class JpegColorConverterTests original.Component1.ToArray(), original.Component2.ToArray(), original.Component3.ToArray()); - baseLineConverter.ConvertToRgbInplace(expected); + baseLineConverter.ConvertToRgbInPlace(expected); if (componentCount == 1) { Assert.True(expected.Component0.SequenceEqual(actual.Component0)); @@ -781,7 +766,7 @@ public class JpegColorConverterTests ValidateYCbCr(original, result, i); break; default: - Assert.True(false, $"Invalid Colorspace enum value: {colorSpace}."); + Assert.Fail($"Invalid Colorspace enum value: {colorSpace}."); break; } }