Browse Source

refactor

af/merge-core
Anton Firszov 10 years ago
parent
commit
f96feb6084
  1. 6
      src/ImageSharp46/Formats/Jpg/Components/Block.cs
  2. 4
      src/ImageSharp46/Formats/Jpg/Components/Block8x8F.Generated.cs
  3. 4
      src/ImageSharp46/Formats/Jpg/Components/Block8x8F.Generated.tt
  4. 80
      src/ImageSharp46/Formats/Jpg/Components/Block8x8F.cs
  5. 4
      src/ImageSharp46/Formats/Jpg/Components/Span.cs
  6. 85
      src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs
  7. 11
      src/ImageSharp46/ImageSharp46.csproj
  8. 2
      tests/ConsoleBenchmark/ConsoleBenchmark.csproj
  9. 2
      tests/ConsoleBenchmark/Program.cs
  10. 140
      tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs
  11. 15
      tests/ImageSharp.Tests46/Formats/Jpg/DctTests.cs
  12. 102
      tests/ImageSharp.Tests46/Formats/Jpg/ReferenceDCT.cs
  13. 6
      tests/ImageSharp.Tests46/Formats/Jpg/UtilityTestClassBase.cs
  14. 5
      tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj
  15. 1
      tests/ImageSharp.Tests46/packages.config

6
src/ImageSharp46/Formats/Jpg/Components/Block.cs

@ -109,6 +109,12 @@ namespace ImageSharp.Formats
}
}
/// <summary>
/// Temporal class to make refactoring easier.
/// 1. Refactor Block -> BlockF
/// 2. Test
/// 3. Refactor BlockF -> Block8x8F
/// </summary>
internal struct BlockF : IDisposable
{
private static readonly ArrayPool<float> ArrayPool = ArrayPool<float>.Create(BlockSize, 50);

4
src/ImageSharp46/Formats/Jpg/Components/Block8x8.Generated.cs → src/ImageSharp46/Formats/Jpg/Components/Block8x8F.Generated.cs

@ -5,10 +5,10 @@ using System.Runtime.CompilerServices;
namespace ImageSharp.Formats
{
public partial struct Block8x8
internal partial struct Block8x8F
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void TransposeInto(ref Block8x8 d)
public void TransposeInto(ref Block8x8F d)
{
d.V0L.X = V0L.X; d.V1L.X = V0L.Y; d.V2L.X = V0L.Z; d.V3L.X = V0L.W; d.V4L.X = V0R.X; d.V5L.X = V0R.Y; d.V6L.X = V0R.Z; d.V7L.X = V0R.W;
d.V0L.Y = V1L.X; d.V1L.Y = V1L.Y; d.V2L.Y = V1L.Z; d.V3L.Y = V1L.W; d.V4L.Y = V1R.X; d.V5L.Y = V1R.Y; d.V6L.Y = V1R.Z; d.V7L.Y = V1R.W;

4
src/ImageSharp46/Formats/Jpg/Components/Block8x8.Generated.tt → src/ImageSharp46/Formats/Jpg/Components/Block8x8F.Generated.tt

@ -11,10 +11,10 @@ using System.Runtime.CompilerServices;
namespace ImageSharp.Formats
{
public partial struct Block8x8
internal partial struct Block8x8F
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void TransposeInto(ref Block8x8 d)
public void TransposeInto(ref Block8x8F d)
{
<#
char[] coordz = new[] {'X', 'Y', 'Z', 'W'};

80
src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs → src/ImageSharp46/Formats/Jpg/Components/Block8x8F.cs

@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
namespace ImageSharp.Formats
{
public partial struct Block8x8
internal partial struct Block8x8F
{
public Vector4 V0L;
public Vector4 V0R;
@ -66,13 +66,13 @@ namespace ImageSharp.Formats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void LoadFrom(Block8x8* blockPtr, Span<float> source)
public static unsafe void LoadFrom(Block8x8F* blockPtr, Span<float> source)
{
Marshal.Copy(source.Data, source.Offset, (IntPtr)blockPtr, ScalarCount);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void CopyTo(Block8x8* blockPtr, Span<float> dest)
public static unsafe void CopyTo(Block8x8F* blockPtr, Span<float> dest)
{
Marshal.Copy((IntPtr)blockPtr, dest.Data, dest.Offset, ScalarCount);
}
@ -125,7 +125,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Reference implementation we can benchmark against
/// </summary>
internal unsafe void TransposeInto_PinningImpl(ref Block8x8 destination)
internal unsafe void TransposeInto_PinningImpl(ref Block8x8F destination)
{
fixed (Vector4* sPtr = &V0L)
{
@ -150,7 +150,7 @@ namespace ImageSharp.Formats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void TransposeInto(Block8x8* sourcePtr, Block8x8* destPtr)
public static unsafe void TransposeInto(Block8x8F* sourcePtr, Block8x8F* destPtr)
{
float* src = (float*)sourcePtr;
float* dest = (float*) destPtr;
@ -175,7 +175,7 @@ namespace ImageSharp.Formats
}
// ReSharper disable once InconsistentNaming
public void IDCTInto(ref Block8x8 dest, ref Block8x8 temp)
public void IDCTInto(ref Block8x8F dest, ref Block8x8F temp)
{
TransposeInto(ref temp);
temp.iDCT2D8x4_LeftPart(ref dest);
@ -192,8 +192,8 @@ namespace ImageSharp.Formats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IDCTInplace()
{
Block8x8 result = new Block8x8();
Block8x8 temp = new Block8x8();
Block8x8F result = new Block8x8F();
Block8x8F temp = new Block8x8F();
IDCTInto(ref result, ref temp);
this = result;
}
@ -213,7 +213,7 @@ namespace ImageSharp.Formats
private static readonly Vector4 _0_125 = new Vector4(0.1250f);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void iDCT2D8x4_LeftPart(ref Block8x8 d)
internal void iDCT2D8x4_LeftPart(ref Block8x8F d)
{
/*
float a0,a1,a2,a3,b0,b1,b2,b3; float z0,z1,z2,z3,z4; float r[8]; int i;
@ -320,7 +320,7 @@ namespace ImageSharp.Formats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void iDCT2D8x4_RightPart(ref Block8x8 d)
internal void iDCT2D8x4_RightPart(ref Block8x8F d)
{
/*
float a0,a1,a2,a3,b0,b1,b2,b3; float z0,z1,z2,z3,z4; float r[8]; int i;
@ -428,11 +428,11 @@ namespace ImageSharp.Formats
internal static void SuchIDCT(ref Block block)
{
Block8x8 source = new Block8x8();
Block8x8F source = new Block8x8F();
source.LoadFrom(block.Data);
Block8x8 dest = new Block8x8();
Block8x8 temp = new Block8x8();
Block8x8F dest = new Block8x8F();
Block8x8F temp = new Block8x8F();
source.IDCTInto(ref dest, ref temp);
dest.CopyTo(block.Data);
@ -440,11 +440,11 @@ namespace ImageSharp.Formats
internal static void SuchIDCT(ref BlockF block)
{
Block8x8 source = new Block8x8();
Block8x8F source = new Block8x8F();
source.LoadFrom(block.Data);
Block8x8 dest = new Block8x8();
Block8x8 temp = new Block8x8();
Block8x8F dest = new Block8x8F();
Block8x8F temp = new Block8x8F();
source.IDCTInto(ref dest, ref temp);
dest.CopyTo(block.Data);
@ -455,7 +455,7 @@ namespace ImageSharp.Formats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
fixed (Block8x8* p = &this)
fixed (Block8x8F* p = &this)
{
float* fp = (float*) p;
return fp[idx];
@ -464,7 +464,7 @@ namespace ImageSharp.Formats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
fixed (Block8x8* p = &this)
fixed (Block8x8F* p = &this)
{
float* fp = (float*)p;
fp[idx] = value;
@ -473,14 +473,14 @@ namespace ImageSharp.Formats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe float GetScalarAt(Block8x8* blockPtr, int idx)
internal static unsafe float GetScalarAt(Block8x8F* blockPtr, int idx)
{
float* fp = (float*) blockPtr;
return fp[idx];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void SetScalarAt(Block8x8* blockPtr, int idx, float value)
internal static unsafe void SetScalarAt(Block8x8F* blockPtr, int idx, float value)
{
float* fp = (float*)blockPtr;
fp[idx] = value;
@ -489,7 +489,7 @@ namespace ImageSharp.Formats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Clear()
{
this = new Block8x8(); // LOL C# Plz!
this = new Block8x8F(); // LOL C# Plz!
}
internal void LoadFrom(ref BlockF legacyBlock)
@ -501,5 +501,43 @@ namespace ImageSharp.Formats
{
CopyTo(legacyBlock.Data);
}
internal unsafe void CopyColorsTo(Span<byte> buffer, int stride)
{
fixed (Block8x8F* p = &this)
{
float* b = (float*) p;
for (int y = 0; y < 8; y++)
{
int y8 = y * 8;
int yStride = y * stride;
for (int x = 0; x < 8; x++)
{
float c = b[y8 + x];
if (c < -128)
{
c = 0;
}
else if (c > 127)
{
c = 255;
}
else
{
c += 128;
}
buffer[yStride + x] = (byte) c;
//dst[yStride + x + offset] = (byte)c;
}
}
}
}
}
}

4
src/ImageSharp46/Formats/Jpg/Components/Span.cs

@ -4,7 +4,7 @@ using System.Runtime.CompilerServices;
namespace ImageSharp.Formats
{
public struct Span<T>
internal struct Span<T>
{
public T[] Data;
public int Offset;
@ -57,7 +57,7 @@ namespace ImageSharp.Formats
}
}
public static class SpanExtensions
internal static class SpanExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SaveTo(this Span<float> data, ref Vector4 v)

85
src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs

@ -85,7 +85,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Saved state between progressive-mode scans.
/// </summary>
private readonly Block8x8[][] progCoeffs;
private readonly Block8x8F[][] progCoeffs;
/// <summary>
/// The huffman trees
@ -97,7 +97,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Quantization tables, in zigzag order.
/// </summary>
private readonly Block8x8[] quantizationTables;
private readonly Block8x8F[] quantizationTables;
/// <summary>
/// A temporary buffer for holding pixels
@ -204,10 +204,10 @@ namespace ImageSharp.Formats
//this.huffmanTrees = new Huffman[MaxTc + 1, MaxTh + 1];
this.huffmanTrees = new Huffman[(MaxTc + 1) * (MaxTh + 1)];
this.quantizationTables = new Block8x8[MaxTq + 1];
this.quantizationTables = new Block8x8F[MaxTq + 1];
this.temp = new byte[2 * BlockF.BlockSize];
this.componentArray = new Component[MaxComponents];
this.progCoeffs = new Block8x8[MaxComponents][];
this.progCoeffs = new Block8x8F[MaxComponents][];
this.bits = new Bits();
this.bytes = new Bytes();
@ -1571,7 +1571,7 @@ namespace ImageSharp.Formats
{
var size = mxx * myy * this.componentArray[compIndex].HorizontalFactor * this.componentArray[compIndex].VerticalFactor;
this.progCoeffs[compIndex] = new Block8x8[size];
this.progCoeffs[compIndex] = new Block8x8F[size];
}
}
}
@ -1589,9 +1589,9 @@ namespace ImageSharp.Formats
// blocks: the third block in the first row has (bx, by) = (2, 0).
int bx, by, blockCount = 0;
Block8x8 b = new Block8x8();
Block8x8 temp1 = new Block8x8();
Block8x8 temp2 = new Block8x8();
Block8x8F b = new Block8x8F();
Block8x8F temp1 = new Block8x8F();
Block8x8F temp2 = new Block8x8F();
for (int my = 0; my < myy; my++)
{
@ -1648,13 +1648,13 @@ namespace ImageSharp.Formats
var qtIndex = this.componentArray[compIndex].Selector;
// TODO: Find a way to clean up this mess
fixed (Block8x8* qtp = &this.quantizationTables[qtIndex])
fixed (Block8x8F* qtp = &this.quantizationTables[qtIndex])
{
if (this.isProgressive) // Load the previous partially decoded coefficients, if applicable.
{
blockIndex = ((@by * mxx) * hi) + bx;
fixed (Block8x8* bp = &this.progCoeffs[compIndex][blockIndex])
fixed (Block8x8F* bp = &this.progCoeffs[compIndex][blockIndex])
{
ProcessBlockImpl(ah,
bp,
@ -1722,13 +1722,13 @@ namespace ImageSharp.Formats
private void ProcessBlockImpl(
int ah,
Block8x8* b,
Block8x8* temp1,
Block8x8* temp2,
Block8x8F* b,
Block8x8F* temp1,
Block8x8F* temp2,
Scan[] scan,
int i, int zigStart, int zigEnd, int al,
int[] dc, int compIndex, int @by, int mxx, int hi, int bx,
Block8x8* qt)
Block8x8F* qt)
{
if (ah != 0)
{
@ -1752,7 +1752,7 @@ namespace ImageSharp.Formats
dc[compIndex] += deltaDC;
//b[0] = dc[compIndex] << al;
Block8x8.SetScalarAt(b, 0, dc[compIndex] << al);
Block8x8F.SetScalarAt(b, 0, dc[compIndex] << al);
}
if (zig <= zigEnd && this.eobRun > 0)
@ -1779,7 +1779,7 @@ namespace ImageSharp.Formats
int ac = this.ReceiveExtend(val1);
//b[Unzig[zig]] = ac << al;
Block8x8.SetScalarAt(b, Unzig[zig], ac << al);
Block8x8F.SetScalarAt(b, Unzig[zig], ac << al);
}
else
{
@ -1828,15 +1828,15 @@ namespace ImageSharp.Formats
//b[Unzig[zig]] *= qt[zig];
int unzigIdx = Unzig[zig];
float value = Block8x8.GetScalarAt(b, unzigIdx);
value *= Block8x8.GetScalarAt(qt, zig);
Block8x8.SetScalarAt(b, unzigIdx, value);
float value = Block8x8F.GetScalarAt(b, unzigIdx);
value *= Block8x8F.GetScalarAt(qt, zig);
Block8x8F.SetScalarAt(b, unzigIdx, value);
}
//IDCT.Transform(ref b);
//FloatIDCT.Transform(ref b);
//ReferenceDCT.IDCT(ref b);
//Block8x8.SuchIDCT(ref b);
//Block8x8F.SuchIDCT(ref b);
//b->IDCTInplace();
b->IDCTInto(ref *temp1, ref *temp2);
@ -1885,35 +1885,10 @@ namespace ImageSharp.Formats
}
// Level shift by +128, clip to [0, 255], and write to dst.
for (int y = 0; y < 8; y++)
{
int y8 = y * 8;
int yStride = y * stride;
for (int x = 0; x < 8; x++)
{
//float c = b[y8 + x];
//float c = Block8x8.GetScalarAt(b, y8 + x);
float c = Block8x8.GetScalarAt(temp1, y8 + x);
if (c < -128)
{
c = 0;
}
else if (c > 127)
{
c = 255;
}
else
{
c += 128;
}
dst[yStride + x + offset] = (byte)c;
}
}
temp1->CopyColorsTo(new Span<byte>(dst, offset), stride);
}
private void ProcessScanImpl(int i, ref Scan currentScan, Scan[] scan, ref int totalHv)
{
// Component selector.
@ -1977,7 +1952,7 @@ namespace ImageSharp.Formats
/// <param name="zigStart">The zig-zag start index</param>
/// <param name="zigEnd">The zig-zag end index</param>
/// <param name="delta">The low transform offset</param>
private void Refine(Block8x8* b, ref Huffman h, int zigStart, int zigEnd, int delta)
private void Refine(Block8x8F* b, ref Huffman h, int zigStart, int zigEnd, int delta)
{
// Refining a DC component is trivial.
if (zigStart == 0)
@ -1990,12 +1965,12 @@ namespace ImageSharp.Formats
bool bit = this.DecodeBit();
if (bit)
{
int stuff = (int) Block8x8.GetScalarAt(b, 0);
int stuff = (int) Block8x8F.GetScalarAt(b, 0);
//int stuff = (int)b[0];
stuff |= delta;
//b[0] = stuff;
Block8x8.SetScalarAt(b, 0, stuff);
Block8x8F.SetScalarAt(b, 0, stuff);
}
return;
@ -2057,7 +2032,7 @@ namespace ImageSharp.Formats
if (z != 0)
{
//b[Unzig[zig]] = z;
Block8x8.SetScalarAt(b, Unzig[zig], z);
Block8x8F.SetScalarAt(b, Unzig[zig], z);
}
}
}
@ -2079,12 +2054,12 @@ namespace ImageSharp.Formats
/// <param name="nz">The non-zero entry</param>
/// <param name="delta">The low transform offset</param>
/// <returns>The <see cref="int"/></returns>
private int RefineNonZeroes(Block8x8* b, int zig, int zigEnd, int nz, int delta)
private int RefineNonZeroes(Block8x8F* b, int zig, int zigEnd, int nz, int delta)
{
for (; zig <= zigEnd; zig++)
{
int u = Unzig[zig];
float bu = Block8x8.GetScalarAt(b, u);
float bu = Block8x8F.GetScalarAt(b, u);
// TODO: Are the equality comparsions OK with floating point values? Isn't an epsilon value necessary?
if (bu == 0)
@ -2107,12 +2082,12 @@ namespace ImageSharp.Formats
if (bu >= 0)
{
//b[u] += delta;
Block8x8.SetScalarAt(b, u, bu + delta);
Block8x8F.SetScalarAt(b, u, bu + delta);
}
else
{
//b[u] -= delta;
Block8x8.SetScalarAt(b, u, bu - delta);
Block8x8F.SetScalarAt(b, u, bu - delta);
}
}

11
src/ImageSharp46/ImageSharp46.csproj

@ -227,11 +227,11 @@
<Compile Include="Formats\IImageFormat.cs" />
<Compile Include="Formats\Jpg\Components\Bits.cs" />
<Compile Include="Formats\Jpg\Components\Block.cs" />
<Compile Include="Formats\Jpg\Components\Block8x8.cs" />
<Compile Include="Formats\Jpg\Components\Block8x8.Generated.cs">
<Compile Include="Formats\Jpg\Components\Block8x8F.cs" />
<Compile Include="Formats\Jpg\Components\Block8x8F.Generated.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Block8x8.Generated.tt</DependentUpon>
<DependentUpon>Block8x8F.Generated.tt</DependentUpon>
</Compile>
<Compile Include="Formats\Jpg\Components\Bytes.cs" />
<Compile Include="Formats\Jpg\Components\Component.cs" />
@ -240,7 +240,6 @@
<Compile Include="Formats\Jpg\Components\GrayImage.cs" />
<Compile Include="Formats\Jpg\Components\Huffman.cs" />
<Compile Include="Formats\Jpg\Components\IDCT.cs" />
<Compile Include="Formats\Jpg\Components\ReferenceDCT.cs" />
<Compile Include="Formats\Jpg\Components\Span.cs" />
<Compile Include="Formats\Jpg\Components\YCbCrImage.cs" />
<Compile Include="Formats\Jpg\JpegConstants.cs" />
@ -400,9 +399,9 @@
<None Include="Profiles\Exif\README.md" />
</ItemGroup>
<ItemGroup>
<Content Include="Formats\Jpg\Components\Block8x8.Generated.tt">
<Content Include="Formats\Jpg\Components\Block8x8F.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8.Generated.cs</LastGenOutput>
<LastGenOutput>Block8x8F.Generated.cs</LastGenOutput>
</Content>
</ItemGroup>
<ItemGroup>

2
tests/ConsoleBenchmark/ConsoleBenchmark.csproj

@ -32,6 +32,8 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />

2
tests/ConsoleBenchmark/Program.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using ImageSharp.Tests;
@ -26,6 +27,7 @@ namespace ConsoleBenchmark
static void Main(string[] args)
{
Console.WriteLine("HW ACC: "+ Vector.IsHardwareAccelerated);
DecodeJpegBenchmark benchmark = new DecodeJpegBenchmark(new Output());
benchmark.JpegCore(100);
//JpegSandbox test = new JpegSandbox(null);

140
tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs

@ -32,14 +32,14 @@ namespace ImageSharp.Tests.Formats.Jpg
float sum = 0;
Measure(Times, () =>
{
Block8x8 block = new Block8x8();
Block8x8F block = new Block8x8F();
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
block[i] = i;
}
sum = 0;
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
sum += block[i];
}
@ -53,16 +53,16 @@ namespace ImageSharp.Tests.Formats.Jpg
float sum = 0;
Measure(Times, () =>
{
Block8x8 block = new Block8x8();
Block8x8F block = new Block8x8F();
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
Block8x8.SetScalarAt(&block, i, i);
Block8x8F.SetScalarAt(&block, i, i);
}
sum = 0;
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
sum += Block8x8.GetScalarAt(&block, i);
sum += Block8x8F.GetScalarAt(&block, i);
}
});
Assert.Equal(sum, 64f * 63f * 0.5f);
@ -76,14 +76,14 @@ namespace ImageSharp.Tests.Formats.Jpg
Measure(Times, () =>
{
//Block8x8 block = new Block8x8();
//Block8x8F block = new Block8x8F();
float[] block = new float[64];
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
block[i] = i;
}
sum = 0;
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
sum += block[i];
}
@ -94,16 +94,16 @@ namespace ImageSharp.Tests.Formats.Jpg
[Fact]
public void Load_Store_FloatArray()
{
float[] data = new float[Block8x8.ScalarCount];
float[] mirror = new float[Block8x8.ScalarCount];
float[] data = new float[Block8x8F.ScalarCount];
float[] mirror = new float[Block8x8F.ScalarCount];
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
data[i] = i;
}
Measure(Times, () =>
{
Block8x8 b = new Block8x8();
Block8x8F b = new Block8x8F();
b.LoadFrom(data);
b.CopyTo(mirror);
});
@ -115,18 +115,18 @@ namespace ImageSharp.Tests.Formats.Jpg
[Fact]
public unsafe void Load_Store_FloatArray_Ptr()
{
float[] data = new float[Block8x8.ScalarCount];
float[] mirror = new float[Block8x8.ScalarCount];
float[] data = new float[Block8x8F.ScalarCount];
float[] mirror = new float[Block8x8F.ScalarCount];
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
data[i] = i;
}
Measure(Times, () =>
{
Block8x8 b = new Block8x8();
Block8x8.LoadFrom(&b, data);
Block8x8.CopyTo(&b, mirror);
Block8x8F b = new Block8x8F();
Block8x8F.LoadFrom(&b, data);
Block8x8F.CopyTo(&b, mirror);
});
Assert.Equal(data, mirror);
@ -136,16 +136,16 @@ namespace ImageSharp.Tests.Formats.Jpg
[Fact]
public void Load_Store_IntArray()
{
int[] data = new int[Block8x8.ScalarCount];
int[] mirror = new int[Block8x8.ScalarCount];
int[] data = new int[Block8x8F.ScalarCount];
int[] mirror = new int[Block8x8F.ScalarCount];
for (int i = 0; i < Block8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8F.ScalarCount; i++)
{
data[i] = i;
}
Measure(Times, () =>
{
Block8x8 v = new Block8x8();
Block8x8F v = new Block8x8F();
v.LoadFrom(data);
v.CopyTo(mirror);
});
@ -160,7 +160,7 @@ namespace ImageSharp.Tests.Formats.Jpg
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Block8x8 buffer = new Block8x8();
Block8x8F buffer = new Block8x8F();
buffer.LoadFrom(Create8x8FloatData());
buffer.TransposeInplace();
@ -177,10 +177,10 @@ namespace ImageSharp.Tests.Formats.Jpg
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Block8x8 source = new Block8x8();
Block8x8F source = new Block8x8F();
source.LoadFrom(Create8x8FloatData());
Block8x8 dest = new Block8x8();
Block8x8F dest = new Block8x8F();
source.TransposeInto_PinningImpl(ref dest);
float[] actual = new float[64];
@ -195,10 +195,10 @@ namespace ImageSharp.Tests.Formats.Jpg
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Block8x8 source = new Block8x8();
Block8x8F source = new Block8x8F();
source.LoadFrom(Create8x8FloatData());
Block8x8 dest = new Block8x8();
Block8x8F dest = new Block8x8F();
source.TransposeInto(ref dest);
float[] actual = new float[64];
@ -239,15 +239,15 @@ namespace ImageSharp.Tests.Formats.Jpg
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Block8x8 source = new Block8x8();
Block8x8F source = new Block8x8F();
source.LoadFrom(Create8x8FloatData());
Block8x8 dest = new Block8x8();
Block8x8F dest = new Block8x8F();
Block8x8* sPtr = &source;
Block8x8* dPtr = &dest;
Block8x8F* sPtr = &source;
Block8x8F* dPtr = &dest;
Block8x8.TransposeInto(sPtr, dPtr);
Block8x8F.TransposeInto(sPtr, dPtr);
float[] actual = new float[64];
dest.CopyTo(actual);
@ -257,7 +257,7 @@ namespace ImageSharp.Tests.Formats.Jpg
private class BufferHolder
{
public Block8x8 Buffer;
public Block8x8F Buffer;
}
[Fact]
@ -306,16 +306,16 @@ namespace ImageSharp.Tests.Formats.Jpg
source.Buffer.LoadFrom(Create8x8FloatData());
BufferHolder dest = new BufferHolder();
fixed (Block8x8* sPtr = &source.Buffer)
fixed (Block8x8F* sPtr = &source.Buffer)
{
fixed (Block8x8* dPtr = &dest.Buffer)
fixed (Block8x8F* dPtr = &dest.Buffer)
{
Output.WriteLine($"TransposeInto_WithPointers_Benchmark X {Times} ...");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Times; i++)
{
Block8x8.TransposeInto(sPtr, dPtr);
Block8x8F.TransposeInto(sPtr, dPtr);
}
sw.Stop();
@ -334,10 +334,10 @@ namespace ImageSharp.Tests.Formats.Jpg
ReferenceDCT.iDCT2D8x4_32f(sourceArray, expectedDestArray);
Block8x8 source = new Block8x8();
Block8x8F source = new Block8x8F();
source.LoadFrom(sourceArray);
Block8x8 dest = new Block8x8();
Block8x8F dest = new Block8x8F();
source.iDCT2D8x4_LeftPart(ref dest);
@ -359,10 +359,10 @@ namespace ImageSharp.Tests.Formats.Jpg
ReferenceDCT.iDCT2D8x4_32f(sourceArray.Slice(4), expectedDestArray.Slice(4));
Block8x8 source = new Block8x8();
Block8x8F source = new Block8x8F();
source.LoadFrom(sourceArray);
Block8x8 dest = new Block8x8();
Block8x8F dest = new Block8x8F();
source.iDCT2D8x4_RightPart(ref dest);
@ -377,7 +377,7 @@ namespace ImageSharp.Tests.Formats.Jpg
}
[Fact]
public void IDCT()
public void IDCTInto()
{
float[] sourceArray = Create8x8FloatData();
float[] expectedDestArray = new float[64];
@ -385,11 +385,11 @@ namespace ImageSharp.Tests.Formats.Jpg
ReferenceDCT.iDCT8x8_llm_sse(sourceArray, expectedDestArray, tempArray);
Block8x8 source = new Block8x8();
Block8x8F source = new Block8x8F();
source.LoadFrom(sourceArray);
Block8x8 dest = new Block8x8();
Block8x8 tempBuffer = new Block8x8();
Block8x8F dest = new Block8x8F();
Block8x8F tempBuffer = new Block8x8F();
source.IDCTInto(ref dest, ref tempBuffer);
@ -401,6 +401,50 @@ namespace ImageSharp.Tests.Formats.Jpg
Print8x8Data(actualDestArray);
Assert.Equal(expectedDestArray, actualDestArray);
}
private unsafe void CopyColorsTo_ReferenceImpl(ref Block8x8F block, Span<byte> buffer, int stride)
{
fixed (Block8x8F* p = &block)
{
float* b = (float*)p;
for (int y = 0; y < 8; y++)
{
int y8 = y * 8;
int yStride = y * stride;
for (int x = 0; x < 8; x++)
{
float c = b[y8 + x];
if (c < -128)
{
c = 0;
}
else if (c > 127)
{
c = 255;
}
else
{
c += 128;
}
buffer[yStride + x] = (byte)c;
}
}
}
}
[Fact]
public void CopyColorsTo()
{
var data = Create8x8FloatData();
Block8x8F block = new Block8x8F();
block.LoadFrom(data);
}
}
}

15
tests/ImageSharp.Tests46/Formats/Jpg/DctTests.cs

@ -26,20 +26,7 @@ namespace ImageSharp.Tests.Formats.Jpg
Print8x8Data(data);
}
[Fact]
public void Load_Store()
{
var data = Create8x8FloatData();
var m = ReferenceDCT.Load(data, 1, 1);
m = Matrix4x4.Transpose(m);
ReferenceDCT.Store(m, data, 4, 4);
Print8x8Data(data);
}
[Fact]
public void Transpose8x8()
{

102
src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs → tests/ImageSharp.Tests46/Formats/Jpg/ReferenceDCT.cs

@ -15,92 +15,8 @@ namespace ImageSharp.Formats
{
private static readonly ArrayPool<float> FloatArrayPool = ArrayPool<float>.Create(Block.BlockSize, 50);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix4x4 Load(Span<float> src, int x, int y)
{
int b0 = y*8 + x;
y++;
int b1 = y*8 + x;
y++;
int b2 = y*8 + x;
y++;
int b3 = y*8 + x;
return new Matrix4x4(
src[b0], src[b0 + 1], src[b0 + 2], src[b0 + 3],
src[b1], src[b1 + 1], src[b1 + 2], src[b1 + 3],
src[b2], src[b2 + 1], src[b2 + 2], src[b2 + 3],
src[b3], src[b3 + 1], src[b3 + 2], src[b3 + 3]
);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Store(Matrix4x4 s, Span<float> d, int x, int y)
{
int b0 = y*8 + x;
y++;
int b1 = y*8 + x;
y++;
int b2 = y*8 + x;
y++;
int b3 = y*8 + x;
d[b0] = s.M11;
d[b0 + 1] = s.M12;
d[b0 + 2] = s.M13;
d[b0 + 3] = s.M14;
d[b1] = s.M21;
d[b1 + 1] = s.M22;
d[b1 + 2] = s.M23;
d[b1 + 3] = s.M24;
d[b2] = s.M31;
d[b2 + 1] = s.M32;
d[b2 + 2] = s.M33;
d[b2 + 3] = s.M34;
d[b3] = s.M41;
d[b3 + 1] = s.M42;
d[b3 + 2] = s.M43;
d[b3 + 3] = s.M44;
}
public static void Transpose8x8_SSE_Slow(Span<float> data)
{
Matrix4x4 a11 = Load(data, 0, 0);
Matrix4x4 a12 = Load(data, 4, 0);
Matrix4x4 a21 = Load(data, 0, 4);
Matrix4x4 a22 = Load(data, 4, 4);
a11 = Matrix4x4.Transpose(a11);
a12 = Matrix4x4.Transpose(a12);
a21 = Matrix4x4.Transpose(a21);
a22 = Matrix4x4.Transpose(a22);
Store(a11, data, 0, 0);
Store(a21, data, 4, 0);
Store(a12, data, 0, 4);
Store(a22, data, 4, 4);
}
public static void Transpose8x8_SSE_Slow(Span<float> src, Span<float> dest)
{
Matrix4x4 a11 = Load(src, 0, 0);
Matrix4x4 a12 = Load(src, 4, 0);
Matrix4x4 a21 = Load(src, 0, 4);
Matrix4x4 a22 = Load(src, 4, 4);
a11 = Matrix4x4.Transpose(a11);
a12 = Matrix4x4.Transpose(a12);
a21 = Matrix4x4.Transpose(a21);
a22 = Matrix4x4.Transpose(a22);
Store(a11, dest, 0, 0);
Store(a21, dest, 4, 0);
Store(a12, dest, 0, 4);
Store(a22, dest, 4, 4);
}
public static void Transpose8x8(Span<float> data)
internal static void Transpose8x8(Span<float> data)
{
for (int i = 1; i < 8; i++)
{
@ -114,7 +30,7 @@ namespace ImageSharp.Formats
}
}
public static void Transpose8x8(Span<float> src, Span<float> dest)
internal static void Transpose8x8(Span<float> src, Span<float> dest)
{
for (int i = 0; i < 8; i++)
{
@ -141,7 +57,7 @@ namespace ImageSharp.Formats
//Store(a22, dest, 4, 4);
}
public static void iDCT1Dllm_32f(Span<float> y, Span<float> x)
internal static void iDCT1Dllm_32f(Span<float> y, Span<float> x)
{
float a0, a1, a2, a3, b0, b1, b2, b3;
float z0, z1, z2, z3, z4;
@ -191,7 +107,7 @@ namespace ImageSharp.Formats
x[4] = a3 - b3;
}
public static void iDCT2D_llm(Span<float> s, Span<float> d, Span<float> temp)
internal static void iDCT2D_llm(Span<float> s, Span<float> d, Span<float> temp)
{
int j;
@ -241,7 +157,7 @@ namespace ImageSharp.Formats
temp.ReturnToPool();
}
public static void iDCT8x8GT(Span<float> s, Span<float> d)
internal static void iDCT8x8GT(Span<float> s, Span<float> d)
{
idct81d_sse_GT(s, d);
@ -285,7 +201,7 @@ namespace ImageSharp.Formats
}
public static void idct81d_sse_GT(Span<float> src, Span<float> dst)
internal static void idct81d_sse_GT(Span<float> src, Span<float> dst)
{
Vector4 c1414 = new Vector4(1.4142135623731f);
Vector4 c0250 = new Vector4(0.25f);
@ -363,7 +279,7 @@ namespace ImageSharp.Formats
private static readonly Vector4 _1_847759 = new Vector4(-1.847759f);
private static readonly Vector4 _0_765367 = new Vector4(0.765367f);
public static void iDCT2D8x4_32f(Span<float> y, Span<float> x)
internal static void iDCT2D8x4_32f(Span<float> y, Span<float> x)
{
/*
float a0,a1,a2,a3,b0,b1,b2,b3; float z0,z1,z2,z3,z4; float r[8]; int i;
@ -476,7 +392,7 @@ namespace ImageSharp.Formats
*/
}
public static void iDCT8x8_llm_sse(Span<float> s, Span<float> d, Span<float> temp)
internal static void iDCT8x8_llm_sse(Span<float> s, Span<float> d, Span<float> temp)
{
Transpose8x8(s, temp);
iDCT2D8x4_32f(temp, d);

6
tests/ImageSharp.Tests46/Formats/Jpg/UtilityTestClassBase.cs

@ -44,9 +44,9 @@ namespace ImageSharp.Tests.Formats.Jpg
return result;
}
protected void Print8x8Data<T>(Span<T> data) => Print8x8Data(data.Data);
internal void Print8x8Data<T>(Span<T> data) => Print8x8Data(data.Data);
protected void Print8x8Data<T>(T[] data)
internal void Print8x8Data<T>(T[] data)
{
StringBuilder bld = new StringBuilder();
for (int i = 0; i < 8; i++)
@ -61,7 +61,7 @@ namespace ImageSharp.Tests.Formats.Jpg
Output.WriteLine(bld.ToString());
}
protected void PrintLinearData<T>(Span<T> data, int count = -1)
internal void PrintLinearData<T>(Span<T> data, int count = -1)
{
if (count < 0) count = data.TotalCount;

5
tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj

@ -37,6 +37,10 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Buffers.4.0.0\lib\netstandard1.1\System.Buffers.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Numerics" />
@ -77,6 +81,7 @@
<Compile Include="Formats\Jpg\Block8x8Tests.cs" />
<Compile Include="Formats\Jpg\DctTests.cs" />
<Compile Include="Formats\Jpg\JpegTests.cs" />
<Compile Include="Formats\Jpg\ReferenceDCT.cs" />
<Compile Include="Formats\Jpg\UtilityTestClassBase.cs" />
<Compile Include="Formats\Png\PngTests.cs" />
<Compile Include="Helpers\GuardTests.cs" />

1
tests/ImageSharp.Tests46/packages.config

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.Buffers" version="4.0.0" targetFramework="net461" />
<package id="System.Numerics.Vectors" version="4.1.1" targetFramework="net461" />
<package id="xunit" version="2.1.0" targetFramework="net461" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net461" />

Loading…
Cancel
Save