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