Browse Source

Merge branch 'main' into icc-color-conversion

pull/1567/head
James Jackson-South 9 months ago
committed by GitHub
parent
commit
afbd24785a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 30
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  2. 37
      src/ImageSharp/Common/Helpers/SimdUtils.cs
  3. 56
      src/ImageSharp/Common/Helpers/Vector128Utilities.cs
  4. 46
      src/ImageSharp/Common/Helpers/Vector256Utilities.cs
  5. 45
      src/ImageSharp/Common/Helpers/Vector512Utilities.cs
  6. 18
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykScalar.cs
  7. 104
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector.cs
  8. 54
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector128.cs
  9. 46
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector256.cs
  10. 103
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector512.cs
  11. 21
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs
  12. 72
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector.cs
  13. 25
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector128.cs
  14. 25
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector256.cs
  15. 75
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector512.cs
  16. 24
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbScalar.cs
  17. 59
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector.cs
  18. 18
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector128.cs
  19. 17
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector256.cs
  20. 59
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector512.cs
  21. 10
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrScalar.cs
  22. 126
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector.cs
  23. 74
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector128.cs
  24. 67
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector256.cs
  25. 123
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector512.cs
  26. 133
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKArm64.cs
  27. 10
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKScalar.cs
  28. 136
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector.cs
  29. 130
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector128.cs
  30. 84
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector256.cs
  31. 144
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector512.cs
  32. 35
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm64.cs
  33. 135
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
  34. 32
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs
  35. 13
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector128.cs
  36. 12
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector256.cs
  37. 111
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector512.cs
  38. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
  39. 22
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs
  40. 28
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs
  41. 22
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs
  42. 22
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs
  43. 22
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs
  44. 471
      tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

30
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);
}
/// <summary>
/// Performs a multiplication and an addition of the <see cref="Vector128{Single}"/>.
/// TODO: Fix. The arguments are in a different order to the FMA intrinsic.
/// </summary>
/// <remarks>ret = (vm0 * vm1) + va</remarks>
/// <param name="va">The vector to add to the intermediate result.</param>
/// <param name="vm0">The first vector to multiply.</param>
/// <param name="vm1">The second vector to multiply.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.AlwaysInline)]
public static Vector128<float> MultiplyAdd(
Vector128<float> va,
Vector128<float> vm0,
Vector128<float> 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);
}
/// <summary>

37
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
/// <summary>
/// Rounds all values in 'v' to the nearest integer following <see cref="MidpointRounding.ToEven"/> semantics.
/// Source:
/// <see>
/// <cref>https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110</cref>
/// </see>
/// </summary>
/// <param name="v">The vector</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector<float> FastRound(this Vector<float> v)
{
if (Avx2.IsSupported)
// .NET9+ has a built-in method for this Vector.Round
if (Avx2.IsSupported && Vector<float>.Count == Vector256<float>.Count)
{
ref Vector256<float> v256 = ref Unsafe.As<Vector<float>, Vector256<float>>(ref v);
Vector256<float> vRound = Avx.RoundToNearestInteger(v256);
return Unsafe.As<Vector256<float>, Vector<float>>(ref vRound);
}
else
if (Sse41.IsSupported && Vector<float>.Count == Vector128<float>.Count)
{
ref Vector128<float> v128 = ref Unsafe.As<Vector<float>, Vector128<float>>(ref v);
Vector128<float> vRound = Sse41.RoundToNearestInteger(v128);
return Unsafe.As<Vector128<float>, Vector<float>>(ref vRound);
}
if (AdvSimd.IsSupported && Vector<float>.Count == Vector128<float>.Count)
{
var magic0 = new Vector<int>(int.MinValue); // 0x80000000
var sgn0 = Vector.AsVectorSingle(magic0);
var and0 = Vector.BitwiseAnd(sgn0, v);
var or0 = Vector.BitwiseOr(and0, new Vector<float>(8388608.0f));
var add0 = Vector.Add(v, or0);
return Vector.Subtract(add0, or0);
ref Vector128<float> v128 = ref Unsafe.As<Vector<float>, Vector128<float>>(ref v);
Vector128<float> vRound = AdvSimd.RoundToNearest(v128);
return Unsafe.As<Vector128<float>, Vector<float>>(ref vRound);
}
// https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L11
Vector<float> sign = v & new Vector<float>(-0F);
Vector<float> val_2p23_f32 = sign | new Vector<float>(8388608F);
val_2p23_f32 = (v + val_2p23_f32) - val_2p23_f32;
return val_2p23_f32 | sign;
}
[Conditional("DEBUG")]

56
src/ImageSharp/Common/Helpers/Vector128Utilities.cs

@ -193,13 +193,65 @@ internal static class Vector128Utilities
return AdvSimd.ConvertToInt32RoundToEven(vector);
}
Vector128<float> sign = vector & Vector128.Create(-0.0f);
Vector128<float> val_2p23_f32 = sign | Vector128.Create(8388608.0f);
Vector128<float> sign = vector & Vector128.Create(-0F);
Vector128<float> val_2p23_f32 = sign | Vector128.Create(8388608F);
val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32;
return Vector128.ConvertToInt32(val_2p23_f32 | sign);
}
/// <summary>
/// Rounds all values in <paramref name="vector"/> to the nearest integer
/// following <see cref="MidpointRounding.ToEven"/> semantics.
/// </summary>
/// <param name="vector">The vector</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector128<float> RoundToNearestInteger(Vector128<float> vector)
{
if (Sse41.IsSupported)
{
return Sse41.RoundToNearestInteger(vector);
}
if (AdvSimd.IsSupported)
{
return AdvSimd.RoundToNearest(vector);
}
Vector128<float> sign = vector & Vector128.Create(-0F);
Vector128<float> val_2p23_f32 = sign | Vector128.Create(8388608F);
val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32;
return val_2p23_f32 | sign;
}
/// <summary>
/// Performs a multiplication and an addition of the <see cref="Vector128{Single}"/>.
/// </summary>
/// <remarks>ret = (vm0 * vm1) + va</remarks>
/// <param name="va">The vector to add to the intermediate result.</param>
/// <param name="vm0">The first vector to multiply.</param>
/// <param name="vm1">The second vector to multiply.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector128<float> MultiplyAdd(
Vector128<float> va,
Vector128<float> vm0,
Vector128<float> vm1)
{
if (Fma.IsSupported)
{
return Fma.MultiplyAdd(vm1, vm0, va);
}
if (AdvSimd.IsSupported)
{
return AdvSimd.FusedMultiplyAdd(va, vm0, vm1);
}
return va + (vm0 * vm1);
}
/// <summary>
/// Packs signed 16-bit integers to unsigned 8-bit integers and saturates.
/// </summary>

46
src/ImageSharp/Common/Helpers/Vector256Utilities.cs

@ -103,13 +103,55 @@ internal static class Vector256Utilities
return Vector256.Create(lower, upper);
}
Vector256<float> sign = vector & Vector256.Create(-0.0f);
Vector256<float> val_2p23_f32 = sign | Vector256.Create(8388608.0f);
Vector256<float> sign = vector & Vector256.Create(-0F);
Vector256<float> val_2p23_f32 = sign | Vector256.Create(8388608F);
val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32;
return Vector256.ConvertToInt32(val_2p23_f32 | sign);
}
/// <summary>
/// Rounds all values in <paramref name="vector"/> to the nearest integer
/// following <see cref="MidpointRounding.ToEven"/> semantics.
/// </summary>
/// <param name="vector">The vector</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> RoundToNearestInteger(Vector256<float> vector)
{
if (Avx.IsSupported)
{
return Avx.RoundToNearestInteger(vector);
}
Vector256<float> sign = vector & Vector256.Create(-0F);
Vector256<float> val_2p23_f32 = sign | Vector256.Create(8388608F);
val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32;
return val_2p23_f32 | sign;
}
/// <summary>
/// Performs a multiplication and an addition of the <see cref="Vector256{Single}"/>.
/// </summary>
/// <remarks>ret = (vm0 * vm1) + va</remarks>
/// <param name="va">The vector to add to the intermediate result.</param>
/// <param name="vm0">The first vector to multiply.</param>
/// <param name="vm1">The second vector to multiply.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> MultiplyAdd(
Vector256<float> va,
Vector256<float> vm0,
Vector256<float> vm1)
{
if (Fma.IsSupported)
{
return Fma.MultiplyAdd(vm0, vm1, va);
}
return va + (vm0 * vm1);
}
[DoesNotReturn]
private static void ThrowUnreachableException() => throw new UnreachableException();
}

45
src/ImageSharp/Common/Helpers/Vector512Utilities.cs

@ -110,6 +110,51 @@ internal static class Vector512Utilities
return Vector512.ConvertToInt32(val_2p23_f32 | sign);
}
/// <summary>
/// Rounds all values in <paramref name="vector"/> to the nearest integer
/// following <see cref="MidpointRounding.ToEven"/> semantics.
/// </summary>
/// <param name="vector">The vector</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector512<float> RoundToNearestInteger(Vector512<float> 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<float> sign = vector & Vector512.Create(-0F);
Vector512<float> val_2p23_f32 = sign | Vector512.Create(8388608F);
val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32;
return val_2p23_f32 | sign;
}
/// <summary>
/// Performs a multiplication and an addition of the <see cref="Vector512{Single}"/>.
/// </summary>
/// <remarks>ret = (vm0 * vm1) + va</remarks>
/// <param name="va">The vector to add to the intermediate result.</param>
/// <param name="vm0">The first vector to multiply.</param>
/// <param name="vm1">The second vector to multiply.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector512<float> MultiplyAdd(
Vector512<float> va,
Vector512<float> vm0,
Vector512<float> vm1)
{
if (Avx512F.IsSupported)
{
return Avx512F.FusedMultiplyAdd(vm0, vm1, va);
}
return va + (vm0 * vm1);
}
[DoesNotReturn]
private static void ThrowUnreachableException() => throw new UnreachableException();
}

18
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykScalar.cs

@ -13,14 +13,14 @@ internal abstract partial class JpegColorConverterBase
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values) =>
ConvertToRgbInplace(values, this.MaximumValue);
public override void ConvertToRgbInPlace(in ComponentValues values) =>
ConvertToRgbInPlace(values, this.MaximumValue);
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertFromRgb(values, this.MaximumValue, r, g, b);
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> 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<float> c0 = values.Component0;
Span<float> c1 = values.Component1;
@ -42,7 +42,7 @@ internal abstract partial class JpegColorConverterBase
}
}
public static void ConvertFromRgb(in ComponentValues values, float maxValue, Span<float> r, Span<float> g, Span<float> b)
public static void ConvertFromRgb(in ComponentValues values, float maxValue, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
Span<float> c = values.Component0;
Span<float> 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)

104
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector.cs

@ -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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceVectorized(in ComponentValues values)
{
ref Vector<float> cBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> mBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> yBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector<float> kBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component3));
var scale = new Vector<float>(1 / (this.MaximumValue * this.MaximumValue));
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector<float> c = ref Unsafe.Add(ref cBase, i);
ref Vector<float> m = ref Unsafe.Add(ref mBase, i);
ref Vector<float> y = ref Unsafe.Add(ref yBase, i);
Vector<float> k = Unsafe.Add(ref kBase, i);
k *= scale;
c *= k;
m *= k;
y *= k;
}
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values)
=> CmykScalar.ConvertToRgbInplace(values, this.MaximumValue);
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertFromRgbInplaceVectorized(in values, this.MaximumValue, r, g, b);
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertFromRgbInplaceRemainder(values, this.MaximumValue, r, g, b);
public static void ConvertFromRgbInplaceVectorized(in ComponentValues values, float maxValue, Span<float> r, Span<float> g, Span<float> b)
{
ref Vector<float> destC =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> destM =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> destY =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector<float> destK =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component3));
ref Vector<float> srcR =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(r));
ref Vector<float> srcG =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(g));
ref Vector<float> srcB =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(b));
// Used for the color conversion
var scale = new Vector<float>(maxValue);
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
Vector<float> ctmp = scale - Unsafe.Add(ref srcR, i);
Vector<float> mtmp = scale - Unsafe.Add(ref srcG, i);
Vector<float> ytmp = scale - Unsafe.Add(ref srcB, i);
Vector<float> ktmp = Vector.Min(ctmp, Vector.Min(mtmp, ytmp));
var kMask = Vector.Equals(ktmp, scale);
ctmp = Vector.AndNot((ctmp - ktmp) / (scale - ktmp), kMask.As<int, float>());
mtmp = Vector.AndNot((mtmp - ktmp) / (scale - ktmp), kMask.As<int, float>());
ytmp = Vector.AndNot((ytmp - ktmp) / (scale - ktmp), kMask.As<int, float>());
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<float> r, Span<float> g, Span<float> b)
=> CmykScalar.ConvertFromRgb(values, maxValue, r, g, b);
}
}

54
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykArm64.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
@ -30,20 +29,20 @@ internal abstract partial class JpegColorConverterBase
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component3));
// Used for the color conversion
var scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue));
Vector128<float> scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue));
nint n = (nint)(uint)values.Component0.Length / Vector128<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector128<float> c = ref Unsafe.Add(ref c0Base, i);
ref Vector128<float> m = ref Unsafe.Add(ref c1Base, i);
ref Vector128<float> y = ref Unsafe.Add(ref c2Base, i);
Vector128<float> 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<float> srcB =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(bLane));
var scale = Vector128.Create(maxValue);
Vector128<float> scale = Vector128.Create(maxValue);
nint n = (nint)(uint)values.Component0.Length / Vector128<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector128<float> ctmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcR, i));
Vector128<float> mtmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcG, i));
Vector128<float> ytmp = AdvSimd.Subtract(scale, Unsafe.Add(ref srcB, i));
Vector128<float> ktmp = AdvSimd.Min(ctmp, AdvSimd.Min(mtmp, ytmp));
Vector128<float> ctmp = scale - Unsafe.Add(ref srcR, i);
Vector128<float> mtmp = scale - Unsafe.Add(ref srcG, i);
Vector128<float> ytmp = scale - Unsafe.Add(ref srcB, i);
Vector128<float> ktmp = Vector128.Min(ctmp, Vector128.Min(mtmp, ytmp));
Vector128<float> kMask = AdvSimd.Not(AdvSimd.CompareEqual(ktmp, scale));
Vector128<float> kMask = ~Vector128.Equals(ktmp, scale);
Vector128<float> 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;
}
}
}

46
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykAvx.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector256<float> c0Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
@ -30,7 +29,7 @@ internal abstract partial class JpegColorConverterBase
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component3));
// Used for the color conversion
var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
Vector256<float> scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
@ -40,10 +39,10 @@ internal abstract partial class JpegColorConverterBase
ref Vector256<float> y = ref Unsafe.Add(ref c2Base, i);
Vector256<float> 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<float> srcB =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(bLane));
var scale = Vector256.Create(maxValue);
Vector256<float> scale = Vector256.Create(maxValue);
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector256<float> ctmp = Avx.Subtract(scale, Unsafe.Add(ref srcR, i));
Vector256<float> mtmp = Avx.Subtract(scale, Unsafe.Add(ref srcG, i));
Vector256<float> ytmp = Avx.Subtract(scale, Unsafe.Add(ref srcB, i));
Vector256<float> ktmp = Avx.Min(ctmp, Avx.Min(mtmp, ytmp));
Vector256<float> ctmp = scale - Unsafe.Add(ref srcR, i);
Vector256<float> mtmp = scale - Unsafe.Add(ref srcG, i);
Vector256<float> ytmp = scale - Unsafe.Add(ref srcB, i);
Vector256<float> ktmp = Vector256.Min(ctmp, Vector256.Min(mtmp, ytmp));
Vector256<float> kMask = Avx.CompareNotEqual(ktmp, scale);
Vector256<float> kMask = ~Vector256.Equals(ktmp, scale);
Vector256<float> 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;
}
}
}

103
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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values)
{
ref Vector512<float> c0Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector512<float> c1Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector512<float> c2Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector512<float> c3Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component3));
// Used for the color conversion
Vector512<float> scale = Vector512.Create(1 / (this.MaximumValue * this.MaximumValue));
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector512<float> c = ref Unsafe.Add(ref c0Base, i);
ref Vector512<float> m = ref Unsafe.Add(ref c1Base, i);
ref Vector512<float> y = ref Unsafe.Add(ref c2Base, i);
Vector512<float> k = Unsafe.Add(ref c3Base, i);
k *= scale;
c *= k;
m *= k;
y *= k;
}
}
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> ConvertFromRgbVectorized(in values, this.MaximumValue, rLane, gLane, bLane);
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values)
=> CmykScalar.ConvertToRgbInPlace(values, this.MaximumValue);
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> CmykScalar.ConvertFromRgb(values, this.MaximumValue, rLane, gLane, bLane);
internal static void ConvertFromRgbVectorized(in ComponentValues values, float maxValue, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector512<float> destC =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector512<float> destM =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector512<float> destY =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector512<float> destK =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component3));
ref Vector512<float> srcR =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector512<float> srcG =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector512<float> srcB =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(bLane));
Vector512<float> scale = Vector512.Create(maxValue);
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector512<float> ctmp = scale - Unsafe.Add(ref srcR, i);
Vector512<float> mtmp = scale - Unsafe.Add(ref srcG, i);
Vector512<float> ytmp = scale - Unsafe.Add(ref srcB, i);
Vector512<float> ktmp = Vector512.Min(ctmp, Vector512.Min(mtmp, ytmp));
Vector512<float> kMask = ~Vector512.Equals(ktmp, scale);
Vector512<float> 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;
}
}
}
}

21
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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
=> ConvertToRgbInplace(values.Component0, this.MaximumValue);
public override void ConvertToRgbInPlace(in ComponentValues values)
=> ConvertToRgbInPlace(values.Component0, this.MaximumValue);
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertCoreInplaceFromRgb(values, r, g, b);
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> ConvertFromRgbScalar(values, rLane, gLane, bLane);
internal static void ConvertToRgbInplace(Span<float> values, float maxValue)
internal static void ConvertToRgbInPlace(Span<float> 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<float> rLane, Span<float> gLane, Span<float> bLane)
internal static void ConvertFromRgbScalar(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
Span<float> 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]));
}
}
}

72
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector.cs

@ -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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceVectorized(in ComponentValues values)
{
ref Vector<float> cBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
var scale = new Vector<float>(1 / this.MaximumValue);
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector<float> c0 = ref Unsafe.Add(ref cBase, i);
c0 *= scale;
}
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values)
=> GrayscaleScalar.ConvertToRgbInplace(values.Component0, this.MaximumValue);
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector<float> destLuma =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> srcR =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector<float> srcG =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector<float> srcB =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(bLane));
var rMult = new Vector<float>(0.299f);
var gMult = new Vector<float>(0.587f);
var bMult = new Vector<float>(0.114f);
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
Vector<float> r = Unsafe.Add(ref srcR, i);
Vector<float> g = Unsafe.Add(ref srcR, i);
Vector<float> 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);
}
}
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> GrayscaleScalar.ConvertCoreInplaceFromRgb(values, r, g, b);
}
}

25
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleArm.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
// Used for the color conversion
var scale = Vector128.Create(1 / this.MaximumValue);
Vector128<float> scale = Vector128.Create(1 / this.MaximumValue);
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector128<float> 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<float, Vector128<float>>(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<float> f0299 = Vector128.Create(0.299f);
Vector128<float> f0587 = Vector128.Create(0.587f);
Vector128<float> f0114 = Vector128.Create(0.114f);
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
@ -60,8 +59,8 @@ internal abstract partial class JpegColorConverterBase
ref Vector128<float> g = ref Unsafe.Add(ref srcGreen, i);
ref Vector128<float> 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);
}
}
}

25
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleAvx.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector256<float> c0Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
Vector256<float> scale = Vector256.Create(1 / this.MaximumValue);
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector256<float> 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<float, Vector256<float>>(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<float> f0299 = Vector256.Create(0.299f);
Vector256<float> f0587 = Vector256.Create(0.587f);
Vector256<float> f0114 = Vector256.Create(0.114f);
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
@ -60,8 +59,8 @@ internal abstract partial class JpegColorConverterBase
ref Vector256<float> g = ref Unsafe.Add(ref srcGreen, i);
ref Vector256<float> 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);
}
}
}

75
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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values)
{
ref Vector512<float> c0Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
// Used for the color conversion
Vector512<float> scale = Vector512.Create(1 / this.MaximumValue);
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector512<float> c0 = ref Unsafe.Add(ref c0Base, i);
c0 *= scale;
}
}
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector512<float> destLuminance =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector512<float> srcRed =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector512<float> srcGreen =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector512<float> srcBlue =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(bLane));
// Used for the color conversion
Vector512<float> f0299 = Vector512.Create(0.299f);
Vector512<float> f0587 = Vector512.Create(0.587f);
Vector512<float> f0114 = Vector512.Create(0.114f);
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector512<float> r = ref Unsafe.Add(ref srcRed, i);
ref Vector512<float> g = ref Unsafe.Add(ref srcGreen, i);
ref Vector512<float> 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);
}
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values)
=> GrayScaleScalar.ConvertToRgbInPlace(values.Component0, this.MaximumValue);
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> GrayScaleScalar.ConvertFromRgbScalar(values, rLane, gLane, bLane);
}
}

24
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbScalar.cs

@ -13,25 +13,25 @@ internal abstract partial class JpegColorConverterBase
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
=> ConvertToRgbInplace(values, this.MaximumValue);
public override void ConvertToRgbInPlace(in ComponentValues values)
=> ConvertToRgbInPlace(values, this.MaximumValue);
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertFromRgb(values, r, g, b);
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> 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<float> r, Span<float> g, Span<float> b)
internal static void ConvertFromRgb(ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> 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);
}
}
}

59
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector.cs

@ -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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceVectorized(in ComponentValues values)
{
ref Vector<float> rBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> gBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> bBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
var scale = new Vector<float>(1 / this.MaximumValue);
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector<float> r = ref Unsafe.Add(ref rBase, i);
ref Vector<float> g = ref Unsafe.Add(ref gBase, i);
ref Vector<float> b = ref Unsafe.Add(ref bBase, i);
r *= scale;
g *= scale;
b *= scale;
}
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values)
=> RgbScalar.ConvertToRgbInplace(values, this.MaximumValue);
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
{
r.CopyTo(values.Component0);
g.CopyTo(values.Component1);
b.CopyTo(values.Component2);
}
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> RgbScalar.ConvertFromRgb(values, r, g, b);
}
}

18
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbArm.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector128<float> rBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
@ -29,16 +27,16 @@ internal abstract partial class JpegColorConverterBase
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
// Used for the color conversion
var scale = Vector128.Create(1 / this.MaximumValue);
Vector128<float> scale = Vector128.Create(1 / this.MaximumValue);
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector128<float> r = ref Unsafe.Add(ref rBase, i);
ref Vector128<float> g = ref Unsafe.Add(ref gBase, i);
ref Vector128<float> 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;
}
}

17
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbAvx.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector256<float> rBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
@ -28,16 +27,16 @@ internal abstract partial class JpegColorConverterBase
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component2));
// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
Vector256<float> scale = Vector256.Create(1 / this.MaximumValue);
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector256<float> r = ref Unsafe.Add(ref rBase, i);
ref Vector256<float> g = ref Unsafe.Add(ref gBase, i);
ref Vector256<float> 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;
}
}

59
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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values)
{
ref Vector512<float> rBase =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector512<float> gBase =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector512<float> bBase =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component2));
// Used for the color conversion
Vector512<float> scale = Vector512.Create(1 / this.MaximumValue);
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector512<float> r = ref Unsafe.Add(ref rBase, i);
ref Vector512<float> g = ref Unsafe.Add(ref gBase, i);
ref Vector512<float> b = ref Unsafe.Add(ref bBase, i);
r *= scale;
g *= scale;
b *= scale;
}
}
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
rLane.CopyTo(values.Component0);
gLane.CopyTo(values.Component1);
bLane.CopyTo(values.Component2);
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values)
=> RgbScalar.ConvertToRgbInPlace(values, this.MaximumValue);
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> RgbScalar.ConvertFromRgb(values, rLane, gLane, bLane);
}
}

10
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrScalar.cs

@ -19,14 +19,14 @@ internal abstract partial class JpegColorConverterBase
}
/// <inheritdoc/>
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);
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertFromRgb(values, this.HalfValue, r, g, b);
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> 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<float> c0 = values.Component0;
Span<float> c1 = values.Component1;

126
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector.cs

@ -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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceVectorized(in ComponentValues values)
{
ref Vector<float> c0Base =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> c1Base =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> c2Base =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
var chromaOffset = new Vector<float>(-this.HalfValue);
var scale = new Vector<float>(1 / this.MaximumValue);
var rCrMult = new Vector<float>(YCbCrScalar.RCrMult);
var gCbMult = new Vector<float>(-YCbCrScalar.GCbMult);
var gCrMult = new Vector<float>(-YCbCrScalar.GCrMult);
var bCbMult = new Vector<float>(YCbCrScalar.BCbMult);
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
// cr = crVals[i] - 128F;
ref Vector<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector<float> y = Unsafe.Add(ref c0Base, i);
Vector<float> cb = Unsafe.Add(ref c1Base, i) + chromaOffset;
Vector<float> 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<float> r = y + (cr * rCrMult);
Vector<float> g = y + (cb * gCbMult) + (cr * gCrMult);
Vector<float> 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;
}
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values)
=> YCbCrScalar.ConvertToRgbInplace(values, this.MaximumValue, this.HalfValue);
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector<float> destY =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> destCb =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> destCr =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector<float> srcR =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector<float> srcG =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector<float> srcB =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(bLane));
var chromaOffset = new Vector<float>(this.HalfValue);
var rYMult = new Vector<float>(0.299f);
var gYMult = new Vector<float>(0.587f);
var bYMult = new Vector<float>(0.114f);
var rCbMult = new Vector<float>(0.168736f);
var gCbMult = new Vector<float>(0.331264f);
var bCbMult = new Vector<float>(0.5f);
var rCrMult = new Vector<float>(0.5f);
var gCrMult = new Vector<float>(0.418688f);
var bCrMult = new Vector<float>(0.081312f);
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
Vector<float> r = Unsafe.Add(ref srcR, i);
Vector<float> g = Unsafe.Add(ref srcG, i);
Vector<float> 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);
}
}
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> YCbCrScalar.ConvertFromRgb(values, this.HalfValue, r, g, b);
}
}

74
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrArm.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
@ -30,16 +27,15 @@ internal abstract partial class JpegColorConverterBase
ref Vector128<float> c2Base =
ref Unsafe.As<float, Vector128<float>>(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<float> chromaOffset = Vector128.Create(-this.HalfValue);
Vector128<float> scale = Vector128.Create(1 / this.MaximumValue);
Vector128<float> rCrMult = Vector128.Create(YCbCrScalar.RCrMult);
Vector128<float> gCbMult = Vector128.Create(-YCbCrScalar.GCbMult);
Vector128<float> gCrMult = Vector128.Create(-YCbCrScalar.GCrMult);
Vector128<float> bCbMult = Vector128.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step:
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
@ -50,19 +46,19 @@ internal abstract partial class JpegColorConverterBase
ref Vector128<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector128<float> y = c0;
Vector128<float> cb = AdvSimd.Add(c1, chromaOffset);
Vector128<float> cr = AdvSimd.Add(c2, chromaOffset);
Vector128<float> cb = c1 + chromaOffset;
Vector128<float> cr = c2 + chromaOffset;
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
Vector128<float> r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult);
Vector128<float> g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector128<float> b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult);
Vector128<float> r = Vector128_.MultiplyAdd(y, cr, rCrMult);
Vector128<float> g = Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector128<float> 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<float> srcB =
ref Unsafe.As<float, Vector128<float>>(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<float>.Count;
Vector128<float> chromaOffset = Vector128.Create(this.HalfValue);
Vector128<float> f0299 = Vector128.Create(0.299f);
Vector128<float> f0587 = Vector128.Create(0.587f);
Vector128<float> f0114 = Vector128.Create(0.114f);
Vector128<float> fn0168736 = Vector128.Create(-0.168736f);
Vector128<float> fn0331264 = Vector128.Create(-0.331264f);
Vector128<float> fn0418688 = Vector128.Create(-0.418688f);
Vector128<float> fn0081312F = Vector128.Create(-0.081312F);
Vector128<float> f05 = Vector128.Create(0.5f);
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector128<float> 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<float> y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r);
Vector128<float> cb = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f05, b), fn0331264, g), fn0168736, r));
Vector128<float> cr = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(fn0081312F, b), fn0418688, g), f05, r));
Vector128<float> y = Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(f0114 * b, f0587, g), f0299, r);
Vector128<float> cb = chromaOffset + Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r);
Vector128<float> cr = chromaOffset + Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r);
Unsafe.Add(ref destY, i) = y;
Unsafe.Add(ref destCb, i) = cb;

67
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrAvx.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector256<float> c0Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
@ -29,13 +27,12 @@ internal abstract partial class JpegColorConverterBase
ref Vector256<float> c2Base =
ref Unsafe.As<float, Vector256<float>>(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<float> chromaOffset = Vector256.Create(-this.HalfValue);
Vector256<float> scale = Vector256.Create(1 / this.MaximumValue);
Vector256<float> rCrMult = Vector256.Create(YCbCrScalar.RCrMult);
Vector256<float> gCbMult = Vector256.Create(-YCbCrScalar.GCbMult);
Vector256<float> gCrMult = Vector256.Create(-YCbCrScalar.GCrMult);
Vector256<float> bCbMult = Vector256.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step:
nuint n = values.Component0.Vector256Count<float>();
@ -49,19 +46,19 @@ internal abstract partial class JpegColorConverterBase
ref Vector256<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector256<float> y = c0;
Vector256<float> cb = Avx.Add(c1, chromaOffset);
Vector256<float> cr = Avx.Add(c2, chromaOffset);
Vector256<float> cb = c1 + chromaOffset;
Vector256<float> cr = c2 + chromaOffset;
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
Vector256<float> r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult);
Vector256<float> g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector256<float> b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult);
Vector256<float> r = Vector256_.MultiplyAdd(y, cr, rCrMult);
Vector256<float> g = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector256<float> 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<float> srcB =
ref Unsafe.As<float, Vector256<float>>(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<float> chromaOffset = Vector256.Create(this.HalfValue);
Vector256<float> f0299 = Vector256.Create(0.299f);
Vector256<float> f0587 = Vector256.Create(0.587f);
Vector256<float> f0114 = Vector256.Create(0.114f);
Vector256<float> fn0168736 = Vector256.Create(-0.168736f);
Vector256<float> fn0331264 = Vector256.Create(-0.331264f);
Vector256<float> fn0418688 = Vector256.Create(-0.418688f);
Vector256<float> fn0081312F = Vector256.Create(-0.081312F);
Vector256<float> f05 = Vector256.Create(0.5f);
nuint n = values.Component0.Vector256Count<float>();
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<float> y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f0114, b), f0587, g), f0299, r);
Vector256<float> cb = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f05, b), fn0331264, g), fn0168736, r));
Vector256<float> cr = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(fn0081312F, b), fn0418688, g), f05, r));
Vector256<float> y = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f0114 * b, f0587, g), f0299, r);
Vector256<float> cb = chromaOffset + Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r);
Vector256<float> cr = chromaOffset + Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r);
Unsafe.Add(ref destY, i) = y;
Unsafe.Add(ref destCb, i) = cb;

123
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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values)
{
ref Vector512<float> c0Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector512<float> c1Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector512<float> c2Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component2));
Vector512<float> chromaOffset = Vector512.Create(-this.HalfValue);
Vector512<float> scale = Vector512.Create(1 / this.MaximumValue);
Vector512<float> rCrMult = Vector512.Create(YCbCrScalar.RCrMult);
Vector512<float> gCbMult = Vector512.Create(-YCbCrScalar.GCbMult);
Vector512<float> gCrMult = Vector512.Create(-YCbCrScalar.GCrMult);
Vector512<float> bCbMult = Vector512.Create(YCbCrScalar.BCbMult);
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
// cr = crVals[i] - 128F;
ref Vector512<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector512<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector512<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector512<float> y = c0;
Vector512<float> cb = c1 + chromaOffset;
Vector512<float> cr = c2 + chromaOffset;
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
Vector512<float> r = Vector512_.MultiplyAdd(y, cr, rCrMult);
Vector512<float> g = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector512<float> 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;
}
}
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector512<float> destY =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector512<float> destCb =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector512<float> destCr =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector512<float> srcR =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector512<float> srcG =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector512<float> srcB =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(bLane));
Vector512<float> chromaOffset = Vector512.Create(this.HalfValue);
Vector512<float> f0299 = Vector512.Create(0.299f);
Vector512<float> f0587 = Vector512.Create(0.587f);
Vector512<float> f0114 = Vector512.Create(0.114f);
Vector512<float> fn0168736 = Vector512.Create(-0.168736f);
Vector512<float> fn0331264 = Vector512.Create(-0.331264f);
Vector512<float> fn0418688 = Vector512.Create(-0.418688f);
Vector512<float> fn0081312F = Vector512.Create(-0.081312F);
Vector512<float> f05 = Vector512.Create(0.5f);
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector512<float> r = Unsafe.Add(ref srcR, i);
Vector512<float> g = Unsafe.Add(ref srcG, i);
Vector512<float> 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<float> y = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f0114 * b, f0587, g), f0299, r);
Vector512<float> cb = chromaOffset + Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r);
Vector512<float> 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;
}
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values)
=> YCbCrScalar.ConvertToRgbInPlace(values, this.MaximumValue, this.HalfValue);
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> YCbCrScalar.ConvertFromRgb(values, this.HalfValue, rLane, gLane, bLane);
}
}

133
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKArm64.cs

@ -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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> c1Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> c2Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> kBase =
ref Unsafe.As<float, Vector128<float>>(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<float>.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<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector128<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector128<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector128<float> y = c0;
Vector128<float> cb = AdvSimd.Add(c1, chromaOffset);
Vector128<float> cr = AdvSimd.Add(c2, chromaOffset);
Vector128<float> 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<float> r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult);
Vector128<float> g =
HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector128<float> 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;
}
}
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
// rgb -> cmyk
CmykArm64.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane);
// cmyk -> ycck
ref Vector128<float> destY =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> destCb =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> destCr =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> srcR = ref destY;
ref Vector128<float> srcG = ref destCb;
ref Vector128<float> 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<float>.Count;
for (nuint i = 0; i < n; i++)
{
Vector128<float> r = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcR, i));
Vector128<float> g = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcG, i));
Vector128<float> 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<float> y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r);
Vector128<float> cb = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f05, b), fn0331264, g), fn0168736, r));
Vector128<float> 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;
}
}
}
}

10
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKScalar.cs

@ -19,14 +19,14 @@ internal abstract partial class JpegColorConverterBase
}
/// <inheritdoc/>
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);
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertFromRgb(values, this.HalfValue, this.MaximumValue, r, g, b);
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> 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<float> c0 = values.Component0;
Span<float> c1 = values.Component1;

136
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector.cs

@ -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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceVectorized(in ComponentValues values)
{
ref Vector<float> c0Base =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> c1Base =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> c2Base =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector<float> kBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component3));
var chromaOffset = new Vector<float>(-this.HalfValue);
var scale = new Vector<float>(1 / (this.MaximumValue * this.MaximumValue));
var max = new Vector<float>(this.MaximumValue);
var rCrMult = new Vector<float>(YCbCrScalar.RCrMult);
var gCbMult = new Vector<float>(-YCbCrScalar.GCbMult);
var gCrMult = new Vector<float>(-YCbCrScalar.GCrMult);
var bCbMult = new Vector<float>(YCbCrScalar.BCbMult);
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
// cr = crVals[i] - 128F;
// k = kVals[i] / 256F;
ref Vector<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector<float> y = c0;
Vector<float> cb = c1 + chromaOffset;
Vector<float> cr = c2 + chromaOffset;
Vector<float> 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<float> r = y + (cr * rCrMult);
Vector<float> g = y + (cb * gCbMult) + (cr * gCrMult);
Vector<float> 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;
}
}
/// <inheritdoc/>
protected override void ConvertToRgbInplaceScalarRemainder(in ComponentValues values)
=> YccKScalar.ConvertToRgpInplace(values, this.MaximumValue, this.HalfValue);
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
// rgb -> cmyk
CmykVector.ConvertFromRgbInplaceVectorized(in values, this.MaximumValue, rLane, gLane, bLane);
// cmyk -> ycck
ref Vector<float> destY =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> destCb =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> destCr =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector<float> srcR = ref destY;
ref Vector<float> srcG = ref destCb;
ref Vector<float> srcB = ref destCr;
var maxSampleValue = new Vector<float>(this.MaximumValue);
var chromaOffset = new Vector<float>(this.HalfValue);
var rYMult = new Vector<float>(0.299f);
var gYMult = new Vector<float>(0.587f);
var bYMult = new Vector<float>(0.114f);
var rCbMult = new Vector<float>(0.168736f);
var gCbMult = new Vector<float>(0.331264f);
var bCbMult = new Vector<float>(0.5f);
var rCrMult = new Vector<float>(0.5f);
var gCrMult = new Vector<float>(0.418688f);
var bCrMult = new Vector<float>(0.081312f);
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
Vector<float> r = maxSampleValue - Unsafe.Add(ref srcR, i);
Vector<float> g = maxSampleValue - Unsafe.Add(ref srcG, i);
Vector<float> 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);
}
}
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> r, Span<float> g, Span<float> 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);
}
}
}

130
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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> c1Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> c2Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> kBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component3));
// Used for the color conversion
Vector128<float> chromaOffset = Vector128.Create(-this.HalfValue);
Vector128<float> scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue));
Vector128<float> max = Vector128.Create(this.MaximumValue);
Vector128<float> rCrMult = Vector128.Create(YCbCrScalar.RCrMult);
Vector128<float> gCbMult = Vector128.Create(-YCbCrScalar.GCbMult);
Vector128<float> gCrMult = Vector128.Create(-YCbCrScalar.GCrMult);
Vector128<float> bCbMult = Vector128.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step:
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
// cr = crVals[i] - 128F;
// k = kVals[i] / 256F;
ref Vector128<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector128<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector128<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector128<float> y = c0;
Vector128<float> cb = c1 + chromaOffset;
Vector128<float> cr = c2 + chromaOffset;
Vector128<float> 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<float> r = Vector128_.MultiplyAdd(y, cr, rCrMult);
Vector128<float> g = Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector128<float> 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;
}
}
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
// rgb -> cmyk
CmykVector128.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane);
// cmyk -> ycck
ref Vector128<float> destY =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> destCb =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> destCr =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> srcR = ref destY;
ref Vector128<float> srcG = ref destCb;
ref Vector128<float> srcB = ref destCr;
// Used for the color conversion
Vector128<float> maxSampleValue = Vector128.Create(this.MaximumValue);
Vector128<float> chromaOffset = Vector128.Create(this.HalfValue);
Vector128<float> f0299 = Vector128.Create(0.299f);
Vector128<float> f0587 = Vector128.Create(0.587f);
Vector128<float> f0114 = Vector128.Create(0.114f);
Vector128<float> fn0168736 = Vector128.Create(-0.168736f);
Vector128<float> fn0331264 = Vector128.Create(-0.331264f);
Vector128<float> fn0418688 = Vector128.Create(-0.418688f);
Vector128<float> fn0081312F = Vector128.Create(-0.081312F);
Vector128<float> f05 = Vector128.Create(0.5f);
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector128<float> r = maxSampleValue - Unsafe.Add(ref srcR, i);
Vector128<float> g = maxSampleValue - Unsafe.Add(ref srcG, i);
Vector128<float> 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<float> y = Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(f0114 * b, f0587, g), f0299, r);
Vector128<float> cb = chromaOffset + Vector128_.MultiplyAdd(Vector128_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r);
Vector128<float> 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;
}
}
}
}

84
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKAvx.cs → 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)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector256<float> c0Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
@ -31,13 +30,13 @@ internal abstract partial class JpegColorConverterBase
ref Unsafe.As<float, Vector256<float>>(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<float> chromaOffset = Vector256.Create(-this.HalfValue);
Vector256<float> scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
Vector256<float> max = Vector256.Create(this.MaximumValue);
Vector256<float> rCrMult = Vector256.Create(YCbCrScalar.RCrMult);
Vector256<float> gCbMult = Vector256.Create(-YCbCrScalar.GCbMult);
Vector256<float> gCrMult = Vector256.Create(-YCbCrScalar.GCrMult);
Vector256<float> bCbMult = Vector256.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step:
nuint n = values.Component0.Vector256Count<float>();
@ -51,25 +50,24 @@ internal abstract partial class JpegColorConverterBase
ref Vector256<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector256<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector256<float> y = c0;
Vector256<float> cb = Avx.Add(c1, chromaOffset);
Vector256<float> cr = Avx.Add(c2, chromaOffset);
Vector256<float> scaledK = Avx.Multiply(Unsafe.Add(ref kBase, i), scale);
Vector256<float> cb = c1 + chromaOffset;
Vector256<float> cr = c2 + chromaOffset;
Vector256<float> 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<float> r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult);
Vector256<float> g =
HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector256<float> b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult);
Vector256<float> r = Vector256_.MultiplyAdd(y, cr, rCrMult);
Vector256<float> g = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector256<float> 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<float> rLane, Span<float> gLane, Span<float> 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<float> destY =
@ -96,32 +94,32 @@ internal abstract partial class JpegColorConverterBase
ref Vector256<float> srcB = ref destCr;
// Used for the color conversion
var maxSampleValue = Vector256.Create(this.MaximumValue);
Vector256<float> maxSampleValue = Vector256.Create(this.MaximumValue);
var chromaOffset = Vector256.Create(this.HalfValue);
Vector256<float> 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<float> f0299 = Vector256.Create(0.299f);
Vector256<float> f0587 = Vector256.Create(0.587f);
Vector256<float> f0114 = Vector256.Create(0.114f);
Vector256<float> fn0168736 = Vector256.Create(-0.168736f);
Vector256<float> fn0331264 = Vector256.Create(-0.331264f);
Vector256<float> fn0418688 = Vector256.Create(-0.418688f);
Vector256<float> fn0081312F = Vector256.Create(-0.081312F);
Vector256<float> f05 = Vector256.Create(0.5f);
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector256<float> r = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcR, i));
Vector256<float> g = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcG, i));
Vector256<float> b = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcB, i));
Vector256<float> r = maxSampleValue - Unsafe.Add(ref srcR, i);
Vector256<float> g = maxSampleValue - Unsafe.Add(ref srcG, i);
Vector256<float> 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<float> y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f0114, b), f0587, g), f0299, r);
Vector256<float> cb = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f05, b), fn0331264, g), fn0168736, r));
Vector256<float> cr = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(fn0081312F, b), fn0418688, g), f05, r));
Vector256<float> y = Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f0114 * b, f0587, g), f0299, r);
Vector256<float> cb = chromaOffset + Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r);
Vector256<float> cr = chromaOffset + Vector256_.MultiplyAdd(Vector256_.MultiplyAdd(fn0081312F * b, fn0418688, g), f05, r);
Unsafe.Add(ref destY, i) = y;
Unsafe.Add(ref destCb, i) = cb;

144
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)
{
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceVectorized(in ComponentValues values)
{
ref Vector512<float> c0Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector512<float> c1Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector512<float> c2Base =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector512<float> kBase =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component3));
// Used for the color conversion
Vector512<float> chromaOffset = Vector512.Create(-this.HalfValue);
Vector512<float> scale = Vector512.Create(1 / (this.MaximumValue * this.MaximumValue));
Vector512<float> max = Vector512.Create(this.MaximumValue);
Vector512<float> rCrMult = Vector512.Create(YCbCrScalar.RCrMult);
Vector512<float> gCbMult = Vector512.Create(-YCbCrScalar.GCbMult);
Vector512<float> gCrMult = Vector512.Create(-YCbCrScalar.GCrMult);
Vector512<float> bCbMult = Vector512.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step:
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
// cr = crVals[i] - 128F;
// k = kVals[i] / 256F;
ref Vector512<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector512<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector512<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector512<float> y = c0;
Vector512<float> cb = c1 + chromaOffset;
Vector512<float> cr = c2 + chromaOffset;
Vector512<float> 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<float> r = Vector512_.MultiplyAdd(y, cr, rCrMult);
Vector512<float> g = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector512<float> 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;
}
}
/// <inheritdoc/>
protected override void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values)
=> YccKScalar.ConvertToRgpInPlace(values, this.MaximumValue, this.HalfValue);
/// <inheritdoc/>
protected override void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
// rgb -> cmyk
CmykVector512.ConvertFromRgbVectorized(in values, this.MaximumValue, rLane, gLane, bLane);
// cmyk -> ycck
ref Vector512<float> destY =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector512<float> destCb =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector512<float> destCr =
ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector512<float> srcR = ref destY;
ref Vector512<float> srcG = ref destCb;
ref Vector512<float> srcB = ref destCr;
// Used for the color conversion
Vector512<float> maxSampleValue = Vector512.Create(this.MaximumValue);
Vector512<float> chromaOffset = Vector512.Create(this.HalfValue);
Vector512<float> f0299 = Vector512.Create(0.299f);
Vector512<float> f0587 = Vector512.Create(0.587f);
Vector512<float> f0114 = Vector512.Create(0.114f);
Vector512<float> fn0168736 = Vector512.Create(-0.168736f);
Vector512<float> fn0331264 = Vector512.Create(-0.331264f);
Vector512<float> fn0418688 = Vector512.Create(-0.418688f);
Vector512<float> fn0081312F = Vector512.Create(-0.081312F);
Vector512<float> f05 = Vector512.Create(0.5f);
nuint n = values.Component0.Vector512Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector512<float> r = maxSampleValue - Unsafe.Add(ref srcR, i);
Vector512<float> g = maxSampleValue - Unsafe.Add(ref srcG, i);
Vector512<float> 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<float> y = Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f0114 * b, f0587, g), f0299, r);
Vector512<float> cb = chromaOffset + Vector512_.MultiplyAdd(Vector512_.MultiplyAdd(f05 * b, fn0331264, g), fn0168736, r);
Vector512<float> 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;
}
}
/// <inheritdoc/>
protected override void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> 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);
}
}
}

35
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm64.cs

@ -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
{
/// <summary>
/// <see cref="JpegColorConverterBase"/> abstract base for implementations
/// based on <see cref="Avx"/> instructions.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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<float>.Count;
}
}

135
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs

@ -71,25 +71,14 @@ internal abstract partial class JpegColorConverterBase
/// <param name="precision">The precision in bits.</param>
/// <exception cref="InvalidImageContentException">Invalid colorspace.</exception>
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}!");
/// <summary>
/// Converts planar jpeg component values in <paramref name="values"/> to RGB color space inplace.
/// Converts planar jpeg component values in <paramref name="values"/> to RGB color space in-place.
/// </summary>
/// <param name="values">The input/ouptut as a stack-only <see cref="ComponentValues"/> struct</param>
public abstract void ConvertToRgbInplace(in ComponentValues values);
/// <param name="values">The input/output as a stack-only <see cref="ComponentValues"/> struct</param>
public abstract void ConvertToRgbInPlace(in ComponentValues values);
/// <summary>
/// Converts RGB lanes to jpeg component values.
@ -101,31 +90,25 @@ internal abstract partial class JpegColorConverterBase
public abstract void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane);
/// <summary>
/// Returns the <see cref="JpegColorConverterBase"/>s for all supported colorspaces and precisions.
/// Returns the <see cref="JpegColorConverterBase"/>s for all supported color spaces and precisions.
/// </summary>
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),
];
/// <summary>
/// Returns the <see cref="JpegColorConverterBase"/>s for the YCbCr colorspace.
@ -133,19 +116,19 @@ internal abstract partial class JpegColorConverterBase
/// <param name="precision">The precision in bits.</param>
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
/// <param name="precision">The precision in bits.</param>
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
/// <param name="precision">The precision in bits.</param>
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
/// <param name="precision">The precision in bits.</param>
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);
}
/// <summary>
@ -229,19 +212,19 @@ internal abstract partial class JpegColorConverterBase
/// <param name="precision">The precision in bits.</param>
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<float>.Empty;
this.Component3 = this.ComponentCount > 3 ? componentBuffers[3].DangerousGetRowSpan(row) : [];
}
/// <summary>
@ -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<float>.Empty;
this.Component3 = this.ComponentCount > 3 ? processors[3].GetColorBufferRowSpan(row) : [];
}
/// <summary>
@ -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<float>.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<float> c0 = this.Component0.Slice(start, length);
Span<float> c1 = this.Component1.Length > 0 ? this.Component1.Slice(start, length) : Span<float>.Empty;
Span<float> c2 = this.Component2.Length > 0 ? this.Component2.Slice(start, length) : Span<float>.Empty;
Span<float> c3 = this.Component3.Length > 0 ? this.Component3.Slice(start, length) : Span<float>.Empty;
Span<float> c1 = this.Component1.Length > 0 ? this.Component1.Slice(start, length) : [];
Span<float> c2 = this.Component2.Length > 0 ? this.Component2.Slice(start, length) : [];
Span<float> c3 = this.Component3.Length > 0 ? this.Component3.Slice(start, length) : [];
return new ComponentValues(this.ComponentCount, c0, c1, c2, c3);
}

32
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs

@ -36,7 +36,7 @@ internal abstract partial class JpegColorConverterBase
public override int ElementsPerBatch => Vector<float>.Count;
/// <inheritdoc/>
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));
}
}
/// <inheritdoc/>
public sealed override void ConvertFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
public sealed override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> 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));
}
}
/// <summary>
/// Converts planar jpeg component values in <paramref name="values"/>
/// to RGB color space inplace using <see cref="Vector"/> API.
/// to RGB color space in place using <see cref="Vector"/> API.
/// </summary>
/// <param name="values">The input/ouptut as a stack-only <see cref="ComponentValues"/> struct</param>
protected abstract void ConvertToRgbInplaceVectorized(in ComponentValues values);
/// <param name="values">The input/output as a stack-only <see cref="ComponentValues"/> struct</param>
protected abstract void ConvertToRgbInPlaceVectorized(in ComponentValues values);
/// <summary>
/// Converts remainder of the planar jpeg component values after
/// conversion in <see cref="ConvertToRgbInplaceVectorized(in ComponentValues)"/>.
/// conversion in <see cref="ConvertToRgbInPlaceVectorized(in ComponentValues)"/>.
/// </summary>
/// <param name="values">The input/ouptut as a stack-only <see cref="ComponentValues"/> struct</param>
protected abstract void ConvertToRgbInplaceScalarRemainder(in ComponentValues values);
/// <param name="values">The input/output as a stack-only <see cref="ComponentValues"/> struct</param>
protected abstract void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values);
/// <summary>
/// Converts RGB lanes to jpeg component values using <see cref="Vector"/> API.

13
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterArm.cs → 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
{
/// <summary>
/// <see cref="JpegColorConverterBase"/> abstract base for implementations
/// based on <see cref="Avx"/> instructions.
/// based on <see cref="Vector128{T}"/> instructions.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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;

12
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterAvx.cs → 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
{
/// <summary>
/// <see cref="JpegColorConverterBase"/> abstract base for implementations
/// based on <see cref="Avx"/> instructions.
/// based on <see cref="Vector256{T}"/> instructions.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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;

111
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
{
/// <summary>
/// <see cref="JpegColorConverterBase"/> abstract base for implementations
/// based on <see cref="Vector512{T}"/> instructions.
/// </summary>
internal abstract class JpegColorConverterVector512 : JpegColorConverterBase
{
protected JpegColorConverterVector512(JpegColorSpace colorSpace, int precision)
: base(colorSpace, precision)
{
}
public static bool IsSupported => Vector512.IsHardwareAccelerated;
/// <inheritdoc/>
public override bool IsAvailable => IsSupported;
/// <inheritdoc/>
public override int ElementsPerBatch => Vector512<float>.Count;
/// <inheritdoc/>
public sealed override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> 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<float>.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));
}
}
/// <inheritdoc/>
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<float>.Count);
int simdCount = length - remainder;
if (simdCount > 0)
{
this.ConvertToRgbInPlaceVectorized(values.Slice(0, simdCount));
}
if (remainder > 0)
{
this.ConvertToRgbInPlaceScalarRemainder(values.Slice(simdCount, remainder));
}
}
/// <summary>
/// Converts planar jpeg component values in <paramref name="values"/>
/// to RGB color space in place using <see cref="Vector"/> API.
/// </summary>
/// <param name="values">The input/output as a stack-only <see cref="ComponentValues"/> struct</param>
protected abstract void ConvertToRgbInPlaceVectorized(in ComponentValues values);
/// <summary>
/// Converts remainder of the planar jpeg component values after
/// conversion in <see cref="ConvertToRgbInPlaceVectorized(in ComponentValues)"/>.
/// </summary>
/// <param name="values">The input/output as a stack-only <see cref="ComponentValues"/> struct</param>
protected abstract void ConvertToRgbInPlaceScalarRemainder(in ComponentValues values);
/// <summary>
/// Converts RGB lanes to jpeg component values using <see cref="Vector"/> API.
/// </summary>
/// <param name="values">Jpeg component values.</param>
/// <param name="rLane">Red colors lane.</param>
/// <param name="gLane">Green colors lane.</param>
/// <param name="bLane">Blue colors lane.</param>
protected abstract void ConvertFromRgbVectorized(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane);
/// <summary>
/// Converts remainder of RGB lanes to jpeg component values after
/// conversion in <see cref="ConvertFromRgbVectorized(in ComponentValues, Span{float}, Span{float}, Span{float})"/>.
/// </summary>
/// <param name="values">Jpeg component values.</param>
/// <param name="rLane">Red colors lane.</param>
/// <param name="gLane">Green colors lane.</param>
/// <param name="bLane">Blue colors lane.</param>
protected abstract void ConvertFromRgbScalarRemainder(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane);
}
}

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs

@ -141,7 +141,7 @@ internal class SpectralConverter<TPixel> : 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<byte> r = this.rgbBuffer.Slice(0, width);

22
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);
}
}

28
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);
}
}

22
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);
}
}

22
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);
}
}

22
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);
}
}

471
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<int>(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<int>(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<int>(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<int>(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<int>(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;
}
}

Loading…
Cancel
Save