diff --git a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
index afcf4158be..ad2e290f6f 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
@@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// Source
/// Destination
- private static void FDCT8x8_Avx(ref Block8x8F s, ref Block8x8F d)
+ public static void FDCT8x8_Avx(ref Block8x8F s, ref Block8x8F d)
{
#if SUPPORTS_RUNTIME_INTRINSICS
Debug.Assert(Avx.IsSupported, "AVX is required to execute this method");
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
index 75ad5427c7..99dce57c70 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
+using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
@@ -22,94 +22,160 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
}
- [Fact]
- public void IDCT2D8x4_LeftPart()
+ // Reference tests
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ public void LLM_TransformIDCT_CompareToNonOptimized(int seed)
{
- float[] sourceArray = Create8x8FloatData();
- var expectedDestArray = new float[64];
+ float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed);
- ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(sourceArray, expectedDestArray);
+ var source = Block8x8F.Load(sourceArray);
- var source = default(Block8x8F);
- source.LoadFrom(sourceArray);
+ Block8x8F expected = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref source);
- var dest = default(Block8x8F);
+ var temp = default(Block8x8F);
+ var actual = default(Block8x8F);
+ FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);
- FastFloatingPointDCT.IDCT8x4_LeftPart(ref source, ref dest);
+ this.CompareBlocks(expected, actual, 1f);
+ }
- var actualDestArray = new float[64];
- dest.ScaledCopyTo(actualDestArray);
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ public void LLM_TransformIDCT_CompareToAccurate(int seed)
+ {
+ float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed);
+
+ var source = Block8x8F.Load(sourceArray);
+
+ Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformIDCT(ref source);
- this.Print8x8Data(expectedDestArray);
- this.Output.WriteLine("**************");
- this.Print8x8Data(actualDestArray);
+ var temp = default(Block8x8F);
+ var actual = default(Block8x8F);
+ FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);
- Assert.Equal(expectedDestArray, actualDestArray);
+ this.CompareBlocks(expected, actual, 1f);
}
- [Fact]
- public void IDCT2D8x4_RightPart()
+
+ // Inverse transform
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void IDCT8x4_LeftPart(int seed)
{
- float[] sourceArray = Create8x8FloatData();
- var expectedDestArray = new float[64];
+ Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
+ var srcBlock = default(Block8x8F);
+ srcBlock.LoadFrom(src);
+
+ var destBlock = default(Block8x8F);
+
+ var expectedDest = new float[64];
+
+ // reference
+ ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(src, expectedDest);
- ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(sourceArray.AsSpan(4), expectedDestArray.AsSpan(4));
+ // testee
+ FastFloatingPointDCT.IDCT8x4_LeftPart(ref srcBlock, ref destBlock);
+
+ var actualDest = new float[64];
+ destBlock.ScaledCopyTo(actualDest);
+
+ Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void IDCT8x4_RightPart(int seed)
+ {
+ Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
+ var srcBlock = default(Block8x8F);
+ srcBlock.LoadFrom(src);
- var source = default(Block8x8F);
- source.LoadFrom(sourceArray);
+ var destBlock = default(Block8x8F);
- var dest = default(Block8x8F);
+ var expectedDest = new float[64];
- FastFloatingPointDCT.IDCT8x4_RightPart(ref source, ref dest);
+ // reference
+ ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4));
- var actualDestArray = new float[64];
- dest.ScaledCopyTo(actualDestArray);
+ // testee
+ FastFloatingPointDCT.IDCT8x4_RightPart(ref srcBlock, ref destBlock);
- this.Print8x8Data(expectedDestArray);
- this.Output.WriteLine("**************");
- this.Print8x8Data(actualDestArray);
+ var actualDest = new float[64];
+ destBlock.ScaledCopyTo(actualDest);
- Assert.Equal(expectedDestArray, actualDestArray);
+ Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
}
[Theory]
[InlineData(1)]
[InlineData(2)]
- [InlineData(3)]
- public void LLM_TransformIDCT_CompareToNonOptimized(int seed)
+ public void IDCT8x8_Avx(int seed)
{
- float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed);
+ if (!Avx.IsSupported)
+ {
+ this.Output.WriteLine("No AVX present, skipping test!");
+ return;
+ }
- var source = Block8x8F.Load(sourceArray);
+ Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
+ var srcBlock = default(Block8x8F);
+ srcBlock.LoadFrom(src);
- Block8x8F expected = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref source);
+ var destBlock = default(Block8x8F);
- var temp = default(Block8x8F);
- var actual = default(Block8x8F);
- FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);
+ var expectedDest = new float[64];
- this.CompareBlocks(expected, actual, 1f);
+ // reference, left part
+ ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(src, expectedDest);
+
+ // reference, right part
+ ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4));
+
+ // testee, whole 8x8
+ FastFloatingPointDCT.IDCT8x8_Avx(ref srcBlock, ref destBlock);
+
+ var actualDest = new float[64];
+ destBlock.ScaledCopyTo(actualDest);
+
+ Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
}
[Theory]
[InlineData(1)]
[InlineData(2)]
- [InlineData(3)]
- public void LLM_TransformIDCT_CompareToAccurate(int seed)
+ public void TransformIDCT(int seed)
{
- float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed);
+ Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
+ var srcBlock = default(Block8x8F);
+ srcBlock.LoadFrom(src);
- var source = Block8x8F.Load(sourceArray);
+ var destBlock = default(Block8x8F);
- Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformIDCT(ref source);
+ var expectedDest = new float[64];
+ var temp1 = new float[64];
+ var temp2 = default(Block8x8F);
- var temp = default(Block8x8F);
- var actual = default(Block8x8F);
- FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);
+ // reference
+ ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D_llm(src, expectedDest, temp1);
- this.CompareBlocks(expected, actual, 1f);
+ // testee
+ FastFloatingPointDCT.TransformIDCT(ref srcBlock, ref destBlock, ref temp2);
+
+ var actualDest = new float[64];
+ destBlock.ScaledCopyTo(actualDest);
+
+ Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
}
+
+ // Forward transform
[Theory]
[InlineData(1)]
[InlineData(2)]
@@ -123,7 +189,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var expectedDest = new float[64];
+ // reference
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src, expectedDest);
+
+ // testee
FastFloatingPointDCT.FDCT8x4_LeftPart(ref srcBlock, ref destBlock);
var actualDest = new float[64];
@@ -145,7 +214,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var expectedDest = new float[64];
+ // reference
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4));
+
+ // testee
FastFloatingPointDCT.FDCT8x4_RightPart(ref srcBlock, ref destBlock);
var actualDest = new float[64];
@@ -154,6 +226,40 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
}
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void FDCT8x8_Avx(int seed)
+ {
+ if (!Avx.IsSupported)
+ {
+ this.Output.WriteLine("No AVX present, skipping test!");
+ return;
+ }
+
+ Span src = Create8x8RoundedRandomFloatData(-200, 200, seed);
+ var srcBlock = default(Block8x8F);
+ srcBlock.LoadFrom(src);
+
+ var destBlock = default(Block8x8F);
+
+ var expectedDest = new float[64];
+
+ // reference, left part
+ ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src, expectedDest);
+
+ // reference, right part
+ ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4));
+
+ // testee, whole 8x8
+ FastFloatingPointDCT.FDCT8x8_Avx(ref srcBlock, ref destBlock);
+
+ var actualDest = new float[64];
+ destBlock.ScaledCopyTo(actualDest);
+
+ Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
+ }
+
[Theory]
[InlineData(1)]
[InlineData(2)]
@@ -169,7 +275,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var temp1 = new float[64];
var temp2 = default(Block8x8F);
+ // reference
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D_llm(src, expectedDest, temp1, downscaleBy8: true);
+
+ // testee
FastFloatingPointDCT.TransformFDCT(ref srcBlock, ref destBlock, ref temp2, false);
var actualDest = new float[64];