|
|
@ -2,7 +2,7 @@ |
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
|
|
|
|
|
using System; |
|
|
using System; |
|
|
|
|
|
using System.Runtime.Intrinsics.X86; |
|
|
using SixLabors.ImageSharp.Formats.Jpeg.Components; |
|
|
using SixLabors.ImageSharp.Formats.Jpeg.Components; |
|
|
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; |
|
|
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; |
|
|
|
|
|
|
|
|
@ -22,94 +22,160 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg |
|
|
{ |
|
|
{ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
[Fact] |
|
|
// Reference tests
|
|
|
public void IDCT2D8x4_LeftPart() |
|
|
[Theory] |
|
|
|
|
|
[InlineData(1)] |
|
|
|
|
|
[InlineData(2)] |
|
|
|
|
|
[InlineData(3)] |
|
|
|
|
|
public void LLM_TransformIDCT_CompareToNonOptimized(int seed) |
|
|
{ |
|
|
{ |
|
|
float[] sourceArray = Create8x8FloatData(); |
|
|
float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed); |
|
|
var expectedDestArray = new float[64]; |
|
|
|
|
|
|
|
|
|
|
|
ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D8x4_32f(sourceArray, expectedDestArray); |
|
|
var source = Block8x8F.Load(sourceArray); |
|
|
|
|
|
|
|
|
var source = default(Block8x8F); |
|
|
Block8x8F expected = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref source); |
|
|
source.LoadFrom(sourceArray); |
|
|
|
|
|
|
|
|
|
|
|
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]; |
|
|
[Theory] |
|
|
dest.ScaledCopyTo(actualDestArray); |
|
|
[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); |
|
|
var temp = default(Block8x8F); |
|
|
this.Output.WriteLine("**************"); |
|
|
var actual = default(Block8x8F); |
|
|
this.Print8x8Data(actualDestArray); |
|
|
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(); |
|
|
Span<float> src = Create8x8RoundedRandomFloatData(-200, 200, seed); |
|
|
var expectedDestArray = new float[64]; |
|
|
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<float> src = Create8x8RoundedRandomFloatData(-200, 200, seed); |
|
|
|
|
|
var srcBlock = default(Block8x8F); |
|
|
|
|
|
srcBlock.LoadFrom(src); |
|
|
|
|
|
|
|
|
var source = default(Block8x8F); |
|
|
var destBlock = default(Block8x8F); |
|
|
source.LoadFrom(sourceArray); |
|
|
|
|
|
|
|
|
|
|
|
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]; |
|
|
// testee
|
|
|
dest.ScaledCopyTo(actualDestArray); |
|
|
FastFloatingPointDCT.IDCT8x4_RightPart(ref srcBlock, ref destBlock); |
|
|
|
|
|
|
|
|
this.Print8x8Data(expectedDestArray); |
|
|
var actualDest = new float[64]; |
|
|
this.Output.WriteLine("**************"); |
|
|
destBlock.ScaledCopyTo(actualDest); |
|
|
this.Print8x8Data(actualDestArray); |
|
|
|
|
|
|
|
|
|
|
|
Assert.Equal(expectedDestArray, actualDestArray); |
|
|
Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
[Theory] |
|
|
[Theory] |
|
|
[InlineData(1)] |
|
|
[InlineData(1)] |
|
|
[InlineData(2)] |
|
|
[InlineData(2)] |
|
|
[InlineData(3)] |
|
|
public void IDCT8x8_Avx(int seed) |
|
|
public void LLM_TransformIDCT_CompareToNonOptimized(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<float> 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 expectedDest = new float[64]; |
|
|
var actual = default(Block8x8F); |
|
|
|
|
|
FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp); |
|
|
|
|
|
|
|
|
|
|
|
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] |
|
|
[Theory] |
|
|
[InlineData(1)] |
|
|
[InlineData(1)] |
|
|
[InlineData(2)] |
|
|
[InlineData(2)] |
|
|
[InlineData(3)] |
|
|
public void TransformIDCT(int seed) |
|
|
public void LLM_TransformIDCT_CompareToAccurate(int seed) |
|
|
|
|
|
{ |
|
|
{ |
|
|
float[] sourceArray = Create8x8RoundedRandomFloatData(-1000, 1000, seed); |
|
|
Span<float> 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); |
|
|
// reference
|
|
|
var actual = default(Block8x8F); |
|
|
ReferenceImplementations.LLM_FloatingPoint_DCT.IDCT2D_llm(src, expectedDest, temp1); |
|
|
FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp); |
|
|
|
|
|
|
|
|
|
|
|
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] |
|
|
[Theory] |
|
|
[InlineData(1)] |
|
|
[InlineData(1)] |
|
|
[InlineData(2)] |
|
|
[InlineData(2)] |
|
|
@ -123,7 +189,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg |
|
|
|
|
|
|
|
|
var expectedDest = new float[64]; |
|
|
var expectedDest = new float[64]; |
|
|
|
|
|
|
|
|
|
|
|
// reference
|
|
|
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src, expectedDest); |
|
|
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src, expectedDest); |
|
|
|
|
|
|
|
|
|
|
|
// testee
|
|
|
FastFloatingPointDCT.FDCT8x4_LeftPart(ref srcBlock, ref destBlock); |
|
|
FastFloatingPointDCT.FDCT8x4_LeftPart(ref srcBlock, ref destBlock); |
|
|
|
|
|
|
|
|
var actualDest = new float[64]; |
|
|
var actualDest = new float[64]; |
|
|
@ -145,7 +214,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg |
|
|
|
|
|
|
|
|
var expectedDest = new float[64]; |
|
|
var expectedDest = new float[64]; |
|
|
|
|
|
|
|
|
|
|
|
// reference
|
|
|
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4)); |
|
|
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan(4)); |
|
|
|
|
|
|
|
|
|
|
|
// testee
|
|
|
FastFloatingPointDCT.FDCT8x4_RightPart(ref srcBlock, ref destBlock); |
|
|
FastFloatingPointDCT.FDCT8x4_RightPart(ref srcBlock, ref destBlock); |
|
|
|
|
|
|
|
|
var actualDest = new float[64]; |
|
|
var actualDest = new float[64]; |
|
|
@ -154,6 +226,40 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg |
|
|
Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f)); |
|
|
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<float> 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] |
|
|
[Theory] |
|
|
[InlineData(1)] |
|
|
[InlineData(1)] |
|
|
[InlineData(2)] |
|
|
[InlineData(2)] |
|
|
@ -169,7 +275,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg |
|
|
var temp1 = new float[64]; |
|
|
var temp1 = new float[64]; |
|
|
var temp2 = default(Block8x8F); |
|
|
var temp2 = default(Block8x8F); |
|
|
|
|
|
|
|
|
|
|
|
// reference
|
|
|
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D_llm(src, expectedDest, temp1, downscaleBy8: true); |
|
|
ReferenceImplementations.LLM_FloatingPoint_DCT.FDCT2D_llm(src, expectedDest, temp1, downscaleBy8: true); |
|
|
|
|
|
|
|
|
|
|
|
// testee
|
|
|
FastFloatingPointDCT.TransformFDCT(ref srcBlock, ref destBlock, ref temp2, false); |
|
|
FastFloatingPointDCT.TransformFDCT(ref srcBlock, ref destBlock, ref temp2, false); |
|
|
|
|
|
|
|
|
var actualDest = new float[64]; |
|
|
var actualDest = new float[64]; |
|
|
|