Browse Source

Port CMYK converter

pull/2917/head
James Jackson-South 1 year ago
parent
commit
3b430e19c1
  1. 10
      src/ImageSharp/Common/Helpers/Vector128Utilities.cs
  2. 93
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector128.cs
  3. 93
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector256.cs
  4. 98
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector512.cs
  5. 126
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector.cs
  6. 19
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
  7. 24
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs
  8. 8
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs
  9. 187
      tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

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

@ -244,16 +244,6 @@ internal static class Vector128Utilities
return Fma.MultiplyAdd(vm1, vm0, va);
}
if (AdvSimd.IsSupported)
{
return AdvSimd.Add(AdvSimd.Multiply(vm0, vm1), va);
}
if (Sse.IsSupported)
{
return Sse.Add(Sse.Multiply(vm0, vm1), va);
}
return va + (vm0 * vm1);
}

93
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector128.cs

@ -0,0 +1,93 @@
// 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 CmykVector128 : JpegColorConverterVector128
{
public CmykVector128(int precision)
: base(JpegColorSpace.Cmyk, 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> c3Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component3));
// Used for the color conversion
Vector128<float> scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue));
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 *= scale;
c *= k;
m *= k;
y *= k;
}
}
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane);
public static void ConvertFromRgb(in ComponentValues values, float maxValue, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector128<float> destC =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> destM =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> destY =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> destK =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component3));
ref Vector128<float> srcR =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector128<float> srcG =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector128<float> srcB =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(bLane));
Vector128<float> scale = Vector128.Create(maxValue);
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
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 = Vector128.Equals(ktmp, scale);
ctmp = Vector128.AndNot((ctmp - ktmp) / (scale - ktmp), kMask);
mtmp = Vector128.AndNot((mtmp - ktmp) / (scale - ktmp), kMask);
ytmp = Vector128.AndNot((ytmp - ktmp) / (scale - ktmp), 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;
}
}
}
}

93
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector256.cs

@ -0,0 +1,93 @@
// 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 CmykVector256 : JpegColorConverterVector256
{
public CmykVector256(int precision)
: base(JpegColorSpace.Cmyk, precision)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInPlace(in ComponentValues values)
{
ref Vector256<float> c0Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256<float> c1Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector256<float> c2Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector256<float> c3Base =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component3));
// Used for the color conversion
Vector256<float> scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector256<float> c = ref Unsafe.Add(ref c0Base, i);
ref Vector256<float> m = ref Unsafe.Add(ref c1Base, i);
ref Vector256<float> y = ref Unsafe.Add(ref c2Base, i);
Vector256<float> k = Unsafe.Add(ref c3Base, i);
k *= scale;
c *= k;
m *= k;
y *= k;
}
}
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
=> ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane);
public static void ConvertFromRgb(in ComponentValues values, float maxValue, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector256<float> destC =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256<float> destM =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector256<float> destY =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector256<float> destK =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component3));
ref Vector256<float> srcR =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector256<float> srcG =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector256<float> srcB =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(bLane));
Vector256<float> scale = Vector256.Create(maxValue);
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
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 = Vector256.Equals(ktmp, scale);
ctmp = Vector256.AndNot((ctmp - ktmp) / (scale - ktmp), kMask);
mtmp = Vector256.AndNot((mtmp - ktmp) / (scale - ktmp), kMask);
ytmp = Vector256.AndNot((ytmp - ktmp) / (scale - ktmp), 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;
}
}
}
}

98
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector512.cs

@ -0,0 +1,98 @@
// 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)
{
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(this.MaximumValue);
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);
ctmp = Vector512.AndNot((ctmp - ktmp) / (scale - ktmp), kMask);
mtmp = Vector512.AndNot((mtmp - ktmp) / (scale - ktmp), kMask);
ytmp = Vector512.AndNot((ytmp - ktmp) / (scale - ktmp), 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;
}
}
/// <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);
}
}

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));
Vector<float> chromaOffset = new(-this.HalfValue);
Vector<float> scale = new(1 / this.MaximumValue);
Vector<float> rCrMult = new(YCbCrScalar.RCrMult);
Vector<float> gCbMult = new(-YCbCrScalar.GCbMult);
Vector<float> gCrMult = new(-YCbCrScalar.GCrMult);
Vector<float> bCbMult = new(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.RoundToNearestInteger();
g = g.RoundToNearestInteger();
b = b.RoundToNearestInteger();
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));
Vector<float> chromaOffset = new(this.HalfValue);
Vector<float> rYMult = new(0.299f);
Vector<float> gYMult = new(0.587f);
Vector<float> bYMult = new(0.114f);
Vector<float> rCbMult = new(0.168736f);
Vector<float> gCbMult = new(0.331264f);
Vector<float> bCbMult = new(0.5f);
Vector<float> rCrMult = new(0.5f);
Vector<float> gCrMult = new(0.418688f);
Vector<float> bCrMult = new(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> rLane, Span<float> gLane, Span<float> bLane)
=> YCbCrScalar.ConvertFromRgb(values, this.HalfValue, rLane, gLane, bLane);
}
}

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

@ -131,11 +131,6 @@ internal abstract partial class JpegColorConverterBase
return new YCbCrVector128(precision);
}
if (JpegColorConverterVector.IsSupported)
{
return new YCbCrVector(precision);
}
return new YCbCrScalar(precision);
}
@ -159,9 +154,19 @@ internal abstract partial class JpegColorConverterBase
/// <param name="precision">The precision in bits.</param>
private static JpegColorConverterBase GetCmykConverter(int precision)
{
if (JpegColorConverterVector.IsSupported)
if (JpegColorConverterVector512.IsSupported)
{
return new CmykVector512(precision);
}
if (JpegColorConverterVector256.IsSupported)
{
return new CmykVector256(precision);
}
if (JpegColorConverterVector128.IsSupported)
{
return new CmykVector(precision);
return new CmykVector128(precision);
}
return new CmykScalar(precision);

24
tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs

@ -17,16 +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);
}
[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 SimdVector256()
{
JpegColorConverterBase.ComponentValues values = new(this.Input, 0);
new JpegColorConverterBase.CmykVector256(8).ConvertToRgbInPlace(values);
}
[Benchmark]
public void SimdVector512()
{
JpegColorConverterBase.ComponentValues values = new(this.Input, 0);
new JpegColorConverterBase.CmykVector512(8).ConvertToRgbInPlace(values);
}
}

8
tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs

@ -22,14 +22,6 @@ public class YCbCrColorConversion : ColorConversionBenchmark
new JpegColorConverterBase.YCbCrScalar(8).ConvertToRgbInPlace(values);
}
[Benchmark]
public void SimdVector8()
{
JpegColorConverterBase.ComponentValues values = new(this.Input, 0);
new JpegColorConverterBase.YCbCrVector(8).ConvertToRgbInPlace(values);
}
[Benchmark]
public void SimdVector128()
{

187
tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

@ -1,7 +1,6 @@
// 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;
using SixLabors.ImageSharp.ColorProfiles;
@ -22,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);
@ -148,17 +147,17 @@ public class JpegColorConverterTests
{
// arrange
Type expectedType = typeof(JpegColorConverterBase.CmykScalar);
if (Avx.IsSupported)
if (JpegColorConverterBase.JpegColorConverterVector512.IsSupported)
{
expectedType = typeof(JpegColorConverterBase.CmykVector);
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.CmykVector);
expectedType = typeof(JpegColorConverterBase.CmykVector128);
}
// act
@ -175,7 +174,7 @@ 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)
{
@ -193,14 +192,6 @@ public class JpegColorConverterTests
{
expectedType = typeof(JpegColorConverterBase.YCbCrVector128);
}
else if (Sse2.IsSupported)
{
expectedType = typeof(JpegColorConverterBase.YCbCrVector);
}
else if (AdvSimd.IsSupported)
{
expectedType = typeof(JpegColorConverterBase.YCbCrVector);
}
// act
JpegColorConverterBase converter = JpegColorConverterBase.GetConverter(JpegColorSpace.YCbCr, 8);
@ -216,7 +207,7 @@ 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)
{
@ -266,29 +257,60 @@ public class JpegColorConverterTests
[Theory]
[MemberData(nameof(Seeds))]
public void FromYCbCrVector(int seed)
{
JpegColorConverterBase.YCbCrVector converter = new(8);
public void FromYCbCrVector512(int seed) =>
this.TestConversionToRgb(
new JpegColorConverterBase.YCbCrVector512(8),
3,
seed,
new JpegColorConverterBase.YCbCrScalar(8));
if (!converter.IsAvailable)
{
this.Output.WriteLine(
$"Skipping test - {converter.GetType().Name} is not supported on current hardware.");
return;
}
[Theory]
[MemberData(nameof(Seeds))]
public void FromYCbCrVector256(int seed) =>
this.TestConversionToRgb(
new JpegColorConverterBase.YCbCrVector256(8),
3,
seed,
new JpegColorConverterBase.YCbCrScalar(8));
FeatureTestRunner.RunWithHwIntrinsicsFeature(
RunTest,
[Theory]
[MemberData(nameof(Seeds))]
public void FromYCbCrVector128(int seed) =>
this.TestConversionToRgb(
new JpegColorConverterBase.YCbCrVector128(8),
3,
seed,
IntrinsicsConfig);
new JpegColorConverterBase.YCbCrScalar(8));
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 FromRgbToYCbCrVector512(int seed) =>
this.TestConversionFromRgb(
new JpegColorConverterBase.YCbCrVector512(8),
3,
seed,
new JpegColorConverterBase.YCbCrScalar(8),
precision: 2);
[Theory]
[MemberData(nameof(Seeds))]
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 FromRgbToYCbCrVector128(int seed) =>
this.TestConversionFromRgb(
new JpegColorConverterBase.YCbCrVector128(8),
3,
seed,
new JpegColorConverterBase.YCbCrScalar(8),
precision: 2);
[Theory]
[MemberData(nameof(Seeds))]
@ -297,29 +319,60 @@ public class JpegColorConverterTests
[Theory]
[MemberData(nameof(Seeds))]
public void FromCmykVector(int seed)
{
JpegColorConverterBase.CmykVector converter = new(8);
public void FromCmykVector512(int seed) =>
this.TestConversionToRgb(
new JpegColorConverterBase.CmykVector512(8),
4,
seed,
new JpegColorConverterBase.CmykScalar(8));
if (!converter.IsAvailable)
{
this.Output.WriteLine(
$"Skipping test - {converter.GetType().Name} is not supported on current hardware.");
return;
}
[Theory]
[MemberData(nameof(Seeds))]
public void FromCmykVector256(int seed) =>
this.TestConversionToRgb(
new JpegColorConverterBase.CmykVector256(8),
4,
seed,
new JpegColorConverterBase.CmykScalar(8));
FeatureTestRunner.RunWithHwIntrinsicsFeature(
RunTest,
[Theory]
[MemberData(nameof(Seeds))]
public void FromCmykVector128(int seed) =>
this.TestConversionToRgb(
new JpegColorConverterBase.CmykVector128(8),
4,
seed,
IntrinsicsConfig);
new JpegColorConverterBase.CmykScalar(8));
static void RunTest(string arg) =>
ValidateConversionToRgb(
new JpegColorConverterBase.CmykVector(8),
4,
FeatureTestRunner.Deserialize<int>(arg),
new JpegColorConverterBase.CmykScalar(8));
}
[Theory]
[MemberData(nameof(Seeds))]
public void FromRgbToCmykVector512(int seed) =>
this.TestConversionFromRgb(
new JpegColorConverterBase.CmykVector512(8),
4,
seed,
new JpegColorConverterBase.CmykScalar(8),
precision: 2);
[Theory]
[MemberData(nameof(Seeds))]
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 FromRgbToCmykVector128(int seed) =>
this.TestConversionFromRgb(
new JpegColorConverterBase.CmykVector128(8),
4,
seed,
new JpegColorConverterBase.CmykScalar(8),
precision: 2);
[Theory]
[MemberData(nameof(Seeds))]
@ -434,6 +487,28 @@ public class JpegColorConverterTests
baseLineConverter);
}
private void TestConversionFromRgb(
JpegColorConverterBase converter,
int componentCount,
int seed,
JpegColorConverterBase baseLineConverter,
int precision)
{
if (!converter.IsAvailable)
{
this.Output.WriteLine(
$"Skipping test - {converter.GetType().Name} is not supported on current hardware.");
return;
}
ValidateConversionFromRgb(
converter,
componentCount,
seed,
baseLineConverter,
precision);
}
private static JpegColorConverterBase.ComponentValues CreateRandomValues(
int length,
int componentCount,

Loading…
Cancel
Save