|
|
|
@ -2,12 +2,8 @@ |
|
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
|
|
|
|
using System; |
|
|
|
#if SUPPORTS_RUNTIME_INTRINSICS
|
|
|
|
using System.Runtime.Intrinsics.X86; |
|
|
|
#endif
|
|
|
|
using SixLabors.ImageSharp.Formats.Jpeg.Components; |
|
|
|
using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder; |
|
|
|
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; |
|
|
|
using SixLabors.ImageSharp.Tests.TestUtilities; |
|
|
|
using Xunit; |
|
|
|
using Xunit.Abstractions; |
|
|
|
@ -22,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg |
|
|
|
|
|
|
|
public HuffmanScanEncoderTests(ITestOutputHelper output) |
|
|
|
{ |
|
|
|
Output = output; |
|
|
|
this.Output = output; |
|
|
|
} |
|
|
|
|
|
|
|
private static int GetHuffmanEncodingLength_Reference(uint number) |
|
|
|
@ -33,25 +29,30 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg |
|
|
|
number >>= 16; |
|
|
|
bits += 16; |
|
|
|
} |
|
|
|
|
|
|
|
if (number > 127) |
|
|
|
{ |
|
|
|
number >>= 8; |
|
|
|
bits += 8; |
|
|
|
} |
|
|
|
|
|
|
|
if (number > 7) |
|
|
|
{ |
|
|
|
number >>= 4; |
|
|
|
bits += 4; |
|
|
|
} |
|
|
|
|
|
|
|
if (number > 1) |
|
|
|
{ |
|
|
|
number >>= 2; |
|
|
|
bits += 2; |
|
|
|
} |
|
|
|
|
|
|
|
if (number > 0) |
|
|
|
{ |
|
|
|
bits++; |
|
|
|
} |
|
|
|
|
|
|
|
return bits; |
|
|
|
} |
|
|
|
|
|
|
|
@ -84,5 +85,157 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg |
|
|
|
Assert.Equal(expected, actual); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void GetLastValuableElementIndex_AllZero() |
|
|
|
{ |
|
|
|
static void RunTest() |
|
|
|
{ |
|
|
|
Block8x8F data = default; |
|
|
|
|
|
|
|
int expectedLessThan = 1; |
|
|
|
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data); |
|
|
|
|
|
|
|
Assert.True(actual < expectedLessThan); |
|
|
|
} |
|
|
|
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature( |
|
|
|
RunTest, |
|
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void GetLastValuableElementIndex_AllNonZero() |
|
|
|
{ |
|
|
|
static void RunTest() |
|
|
|
{ |
|
|
|
Block8x8F data = default; |
|
|
|
for (int i = 0; i < Block8x8F.Size; i++) |
|
|
|
{ |
|
|
|
data[i] = 10; |
|
|
|
} |
|
|
|
|
|
|
|
int expected = Block8x8F.Size - 1; |
|
|
|
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data); |
|
|
|
|
|
|
|
Assert.Equal(expected, actual); |
|
|
|
} |
|
|
|
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature( |
|
|
|
RunTest, |
|
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(1)] |
|
|
|
[InlineData(2)] |
|
|
|
public void GetLastValuableElementIndex_RandomFilledSingle(int seed) |
|
|
|
{ |
|
|
|
static void RunTest(string seedSerialized) |
|
|
|
{ |
|
|
|
int seed = FeatureTestRunner.Deserialize<int>(seedSerialized); |
|
|
|
var rng = new Random(seed); |
|
|
|
|
|
|
|
for (int i = 0; i < 1000; i++) |
|
|
|
{ |
|
|
|
Block8x8F data = default; |
|
|
|
|
|
|
|
int setIndex = rng.Next(1, Block8x8F.Size); |
|
|
|
data[setIndex] = rng.Next(); |
|
|
|
|
|
|
|
int expected = setIndex; |
|
|
|
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data); |
|
|
|
|
|
|
|
Assert.Equal(expected, actual); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature( |
|
|
|
RunTest, |
|
|
|
seed, |
|
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(1)] |
|
|
|
[InlineData(2)] |
|
|
|
public void GetLastValuableElementIndex_RandomFilledPartially(int seed) |
|
|
|
{ |
|
|
|
static void RunTest(string seedSerialized) |
|
|
|
{ |
|
|
|
int seed = FeatureTestRunner.Deserialize<int>(seedSerialized); |
|
|
|
var rng = new Random(seed); |
|
|
|
|
|
|
|
for (int i = 0; i < 1000; i++) |
|
|
|
{ |
|
|
|
Block8x8F data = default; |
|
|
|
|
|
|
|
int lastIndex = rng.Next(1, Block8x8F.Size); |
|
|
|
int fillValue = rng.Next(); |
|
|
|
for (int dataIndex = 0; dataIndex <= lastIndex; dataIndex++) |
|
|
|
{ |
|
|
|
data[dataIndex] = fillValue; |
|
|
|
} |
|
|
|
|
|
|
|
int expected = lastIndex; |
|
|
|
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data); |
|
|
|
|
|
|
|
Assert.Equal(expected, actual); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature( |
|
|
|
RunTest, |
|
|
|
seed, |
|
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(1)] |
|
|
|
[InlineData(2)] |
|
|
|
public void GetLastValuableElementIndex_RandomFilledFragmented(int seed) |
|
|
|
{ |
|
|
|
static void RunTest(string seedSerialized) |
|
|
|
{ |
|
|
|
int seed = FeatureTestRunner.Deserialize<int>(seedSerialized); |
|
|
|
var rng = new Random(seed); |
|
|
|
|
|
|
|
for (int i = 0; i < 1000; i++) |
|
|
|
{ |
|
|
|
Block8x8F data = default; |
|
|
|
|
|
|
|
int fillValue = rng.Next(); |
|
|
|
|
|
|
|
// first filled chunk
|
|
|
|
int lastIndex1 = rng.Next(1, Block8x8F.Size / 2); |
|
|
|
for (int dataIndex = 0; dataIndex <= lastIndex1; dataIndex++) |
|
|
|
{ |
|
|
|
data[dataIndex] = fillValue; |
|
|
|
} |
|
|
|
|
|
|
|
// second filled chunk, there might be a spot with zero(s) between first and second chunk
|
|
|
|
int lastIndex2 = rng.Next(lastIndex1 + 1, Block8x8F.Size); |
|
|
|
for (int dataIndex = 0; dataIndex <= lastIndex2; dataIndex++) |
|
|
|
{ |
|
|
|
data[dataIndex] = fillValue; |
|
|
|
} |
|
|
|
|
|
|
|
int expected = lastIndex2; |
|
|
|
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data); |
|
|
|
|
|
|
|
Assert.Equal(expected, actual); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature( |
|
|
|
RunTest, |
|
|
|
seed, |
|
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|