Browse Source

auto-generated implementation for Block8x8.Transpose()

pull/34/head
Anton Firszov 9 years ago
parent
commit
303e479aae
  1. 23
      src/ImageSharp46/Formats/Jpg/Components/Block8x8.Generated.cs
  2. 46
      src/ImageSharp46/Formats/Jpg/Components/Block8x8.Generated.tt
  3. 41
      src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs
  4. 8
      src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs
  5. 16
      src/ImageSharp46/ImageSharp46.csproj
  6. 136
      tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs
  7. 2
      tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj

23
src/ImageSharp46/Formats/Jpg/Components/Block8x8.Generated.cs

@ -0,0 +1,23 @@

using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace ImageSharp.Formats
{
public partial struct Block8x8
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void TransposeInto(ref Block8x8 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;
d.V0L.Z = V2L.X; d.V1L.Z = V2L.Y; d.V2L.Z = V2L.Z; d.V3L.Z = V2L.W; d.V4L.Z = V2R.X; d.V5L.Z = V2R.Y; d.V6L.Z = V2R.Z; d.V7L.Z = V2R.W;
d.V0L.W = V3L.X; d.V1L.W = V3L.Y; d.V2L.W = V3L.Z; d.V3L.W = V3L.W; d.V4L.W = V3R.X; d.V5L.W = V3R.Y; d.V6L.W = V3R.Z; d.V7L.W = V3R.W;
d.V0R.X = V4L.X; d.V1R.X = V4L.Y; d.V2R.X = V4L.Z; d.V3R.X = V4L.W; d.V4R.X = V4R.X; d.V5R.X = V4R.Y; d.V6R.X = V4R.Z; d.V7R.X = V4R.W;
d.V0R.Y = V5L.X; d.V1R.Y = V5L.Y; d.V2R.Y = V5L.Z; d.V3R.Y = V5L.W; d.V4R.Y = V5R.X; d.V5R.Y = V5R.Y; d.V6R.Y = V5R.Z; d.V7R.Y = V5R.W;
d.V0R.Z = V6L.X; d.V1R.Z = V6L.Y; d.V2R.Z = V6L.Z; d.V3R.Z = V6L.W; d.V4R.Z = V6R.X; d.V5R.Z = V6R.Y; d.V6R.Z = V6R.Z; d.V7R.Z = V6R.W;
d.V0R.W = V7L.X; d.V1R.W = V7L.Y; d.V2R.W = V7L.Z; d.V3R.W = V7L.W; d.V4R.W = V7R.X; d.V5R.W = V7R.Y; d.V6R.W = V7R.Z; d.V7R.W = V7R.W;
}
}
}

46
src/ImageSharp46/Formats/Jpg/Components/Block8x8.Generated.tt

@ -0,0 +1,46 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace ImageSharp.Formats
{
public partial struct Block8x8
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void TransposeInto(ref Block8x8 d)
{
<#
char[] coordz = new[] {'X', 'Y', 'Z', 'W'};
//StringBuilder bld = new StringBuilder();
PushIndent(" ");
for (int i = 0; i < 8; i++)
{
char destCoord = coordz[i % 4];
char destSide = (i / 4) % 2 == 0 ? 'L' : 'R';
for (int j = 0; j < 8; j++)
{
char srcCoord = coordz[j % 4];
char srcSide = (j / 4) % 2 == 0 ? 'L' : 'R';
string expression = $"d.V{j}{destSide}.{destCoord} = V{i}{srcSide}.{srcCoord}; ";
//bld.Append(expression);
Write(expression);
}
//bld.AppendLine();
WriteLine("");
}
PopIndent();
//Write(bld.ToString());
#>
}
}
}

41
src/ImageSharp46/Formats/Jpg/Components/Buffer8x8.cs → src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs

@ -1,11 +1,11 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
// ReSharper disable InconsistentNaming
namespace ImageSharp.Formats
{
// ReSharper disable once InconsistentNaming
public struct Buffer8x8
public partial struct Block8x8
{
public Vector4 V0L;
public Vector4 V0R;
@ -103,7 +103,10 @@ namespace ImageSharp.Formats
}
public unsafe void TranposeInto(ref Buffer8x8 destination)
/// <summary>
/// Used as a reference implementation for benchmarking
/// </summary>
internal unsafe void TransposeInto_PinningImpl(ref Block8x8 destination)
{
fixed (Vector4* sPtr = &V0L)
{
@ -125,14 +128,10 @@ namespace ImageSharp.Formats
}
}
public void TransposeIntoSafe(ref Buffer8x8 d)
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void PinnedTransposeInto(Buffer8x8* sourcePtr, Buffer8x8* destPtr)
public static unsafe void TransposeInto(Block8x8* sourcePtr, Block8x8* destPtr)
{
float* src = (float*)sourcePtr;
float* dest = (float*) destPtr;
@ -147,7 +146,7 @@ namespace ImageSharp.Formats
}
}
private static readonly Vector4 _c = new Vector4(0.1250f);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyAllInplace(Vector4 s)
@ -159,18 +158,18 @@ namespace ImageSharp.Formats
}
// ReSharper disable once InconsistentNaming
public void TransformIDCTInto(ref Buffer8x8 dest, ref Buffer8x8 temp)
public void IDCTInto(ref Block8x8 dest, ref Block8x8 temp)
{
TranposeInto(ref temp);
TransposeInto(ref temp);
temp.iDCT2D8x4_LeftPart(ref dest);
temp.iDCT2D8x4_RightPart(ref dest);
dest.TranposeInto(ref temp);
dest.TransposeInto(ref temp);
temp.iDCT2D8x4_LeftPart(ref dest);
temp.iDCT2D8x4_RightPart(ref dest);
dest.MultiplyAllInplace(new Vector4(0.1250f));
dest.MultiplyAllInplace(_0_125);
}
private static readonly Vector4 _1_175876 = new Vector4(1.175876f);
@ -185,8 +184,10 @@ namespace ImageSharp.Formats
private static readonly Vector4 _0_541196 = new Vector4(0.541196f);
private static readonly Vector4 _1_847759 = new Vector4(-1.847759f);
private static readonly Vector4 _0_765367 = new Vector4(0.765367f);
private static readonly Vector4 _0_125 = new Vector4(0.1250f);
internal void iDCT2D8x4_LeftPart(ref Buffer8x8 d)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void iDCT2D8x4_LeftPart(ref Block8x8 d)
{
/*
float a0,a1,a2,a3,b0,b1,b2,b3; float z0,z1,z2,z3,z4; float r[8]; int i;
@ -292,8 +293,8 @@ namespace ImageSharp.Formats
*/
}
internal void iDCT2D8x4_RightPart(ref Buffer8x8 d)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void iDCT2D8x4_RightPart(ref Block8x8 d)
{
/*
float a0,a1,a2,a3,b0,b1,b2,b3; float z0,z1,z2,z3,z4; float r[8]; int i;
@ -401,13 +402,13 @@ namespace ImageSharp.Formats
public static void SuchIDCT(ref Block block)
{
Buffer8x8 source = new Buffer8x8();
Block8x8 source = new Block8x8();
source.LoadFrom(block.Data);
Buffer8x8 dest = new Buffer8x8();
Buffer8x8 temp = new Buffer8x8();
Block8x8 dest = new Block8x8();
Block8x8 temp = new Block8x8();
source.TransformIDCTInto(ref dest, ref temp);
source.IDCTInto(ref dest, ref temp);
dest.CopyTo(block.Data);
}
}

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

@ -1814,7 +1814,7 @@ namespace ImageSharp.Formats
//IDCT.Transform(ref b);
//FloatIDCT.Transform(ref b);
//ReferenceDCT.IDCT(ref b);
Buffer8x8.SuchIDCT(ref b);
Block8x8.SuchIDCT(ref b);
byte[] dst;
int offset;
@ -2014,7 +2014,7 @@ namespace ImageSharp.Formats
break;
}
zig = this.RefineNonZeroes(b, zig, zigEnd, val0, delta);
zig = this.RefineNonZeroes(ref b, zig, zigEnd, val0, delta);
if (zig > zigEnd)
{
throw new ImageFormatException($"Too many coefficients {zig} > {zigEnd}");
@ -2030,7 +2030,7 @@ namespace ImageSharp.Formats
if (this.eobRun > 0)
{
this.eobRun--;
this.RefineNonZeroes(b, zig, zigEnd, -1, delta);
this.RefineNonZeroes(ref b, zig, zigEnd, -1, delta);
}
}
@ -2044,7 +2044,7 @@ 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(Block b, int zig, int zigEnd, int nz, int delta)
private int RefineNonZeroes(ref Block b, int zig, int zigEnd, int nz, int delta)
{
for (; zig <= zigEnd; zig++)
{

16
src/ImageSharp46/ImageSharp46.csproj

@ -227,7 +227,12 @@
<Compile Include="Formats\IImageFormat.cs" />
<Compile Include="Formats\Jpg\Components\Bits.cs" />
<Compile Include="Formats\Jpg\Components\Block.cs" />
<Compile Include="Formats\Jpg\Components\Buffer8x8.cs" />
<Compile Include="Formats\Jpg\Components\Block8x8.cs" />
<Compile Include="Formats\Jpg\Components\Block8x8.Generated.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Block8x8.Generated.tt</DependentUpon>
</Compile>
<Compile Include="Formats\Jpg\Components\Bytes.cs" />
<Compile Include="Formats\Jpg\Components\Component.cs" />
<Compile Include="Formats\Jpg\Components\FDCT.cs" />
@ -394,6 +399,15 @@
<None Include="packages.config" />
<None Include="Profiles\Exif\README.md" />
</ItemGroup>
<ItemGroup>
<Content Include="Formats\Jpg\Components\Block8x8.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8.Generated.cs</LastGenOutput>
</Content>
</ItemGroup>
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

136
tests/ImageSharp.Tests46/Formats/Jpg/Buffer8x8Tests.cs → tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs

@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using ImageSharp.Formats;
using Xunit;
using Xunit.Abstractions;
@ -9,9 +10,9 @@ using Xunit.Abstractions;
namespace ImageSharp.Tests.Formats.Jpg
{
// ReSharper disable once InconsistentNaming
public class Buffer8x8Tests : UtilityTestClassBase
public class Block8x8Tests : UtilityTestClassBase
{
public Buffer8x8Tests(ITestOutputHelper output) : base(output)
public Block8x8Tests(ITestOutputHelper output) : base(output)
{
}
@ -22,16 +23,16 @@ namespace ImageSharp.Tests.Formats.Jpg
{
float[] data = new float[Buffer8x8.ScalarCount];
float[] mirror = new float[Buffer8x8.ScalarCount];
float[] data = new float[Block8x8.ScalarCount];
float[] mirror = new float[Block8x8.ScalarCount];
for (int i = 0; i < Buffer8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
data[i] = i;
}
Measure(times, () =>
{
Buffer8x8 v = new Buffer8x8();
Block8x8 v = new Block8x8();
v.LoadFrom(data);
v.CopyTo(mirror);
});
@ -47,16 +48,16 @@ namespace ImageSharp.Tests.Formats.Jpg
{
int[] data = new int[Buffer8x8.ScalarCount];
int[] mirror = new int[Buffer8x8.ScalarCount];
int[] data = new int[Block8x8.ScalarCount];
int[] mirror = new int[Block8x8.ScalarCount];
for (int i = 0; i < Buffer8x8.ScalarCount; i++)
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
data[i] = i;
}
Measure(times, () =>
{
Buffer8x8 v = new Buffer8x8();
Block8x8 v = new Block8x8();
v.LoadFrom(data);
v.CopyTo(mirror);
});
@ -71,7 +72,7 @@ namespace ImageSharp.Tests.Formats.Jpg
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Buffer8x8 buffer = new Buffer8x8();
Block8x8 buffer = new Block8x8();
buffer.LoadFrom(Create8x8FloatData());
buffer.TransposeInplace();
@ -83,16 +84,16 @@ namespace ImageSharp.Tests.Formats.Jpg
}
[Fact]
public void TransposeInto()
public void TranposeInto_PinningImpl()
{
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Buffer8x8 source = new Buffer8x8();
Block8x8 source = new Block8x8();
source.LoadFrom(Create8x8FloatData());
Buffer8x8 dest = new Buffer8x8();
source.TranposeInto(ref dest);
Block8x8 dest = new Block8x8();
source.TransposeInto_PinningImpl(ref dest);
float[] actual = new float[64];
dest.CopyTo(actual);
@ -101,16 +102,16 @@ namespace ImageSharp.Tests.Formats.Jpg
}
[Fact]
public void TransposeIntoSafe()
public void TransposeInto()
{
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Buffer8x8 source = new Buffer8x8();
Block8x8 source = new Block8x8();
source.LoadFrom(Create8x8FloatData());
Buffer8x8 dest = new Buffer8x8();
source.TransposeIntoSafe(ref dest);
Block8x8 dest = new Block8x8();
source.TransposeInto(ref dest);
float[] actual = new float[64];
dest.CopyTo(actual);
@ -119,20 +120,46 @@ namespace ImageSharp.Tests.Formats.Jpg
}
[Fact]
public unsafe void PinnedTransposeInto()
public void Buffer8x8_TransposeInto_GeneratorTest()
{
char[] coordz = new[] {'X', 'Y', 'Z', 'W'};
StringBuilder bld = new StringBuilder();
for (int i = 0; i < 8; i++)
{
char destCoord = coordz[i % 4];
char destSide = (i / 4) % 2 == 0 ? 'L' : 'R';
for (int j = 0; j < 8; j++)
{
char srcCoord = coordz[j % 4];
char srcSide = (j / 4) % 2 == 0 ? 'L' : 'R';
string expression = $"d.V{j}{destSide}.{destCoord} = V{i}{srcSide}.{srcCoord}; ";
bld.Append(expression);
}
bld.AppendLine();
}
Output.WriteLine(bld.ToString());
}
[Fact]
public unsafe void TransposeInto_WithPointers()
{
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Buffer8x8 source = new Buffer8x8();
Block8x8 source = new Block8x8();
source.LoadFrom(Create8x8FloatData());
Buffer8x8 dest = new Buffer8x8();
Block8x8 dest = new Block8x8();
Buffer8x8* sPtr = &source;
Buffer8x8* dPtr = &dest;
Block8x8* sPtr = &source;
Block8x8* dPtr = &dest;
Buffer8x8.PinnedTransposeInto(sPtr, dPtr);
Block8x8.TransposeInto(sPtr, dPtr);
float[] actual = new float[64];
dest.CopyTo(actual);
@ -142,53 +169,74 @@ namespace ImageSharp.Tests.Formats.Jpg
private class BufferHolder
{
public Buffer8x8 Buffer;
public Block8x8 Buffer;
}
[Theory]
[InlineData(1)]
[InlineData(10000000)]
public void TranposeInto_Benchmark(int times)
{
BufferHolder source = new BufferHolder();
source.Buffer.LoadFrom(Create8x8FloatData());
BufferHolder dest = new BufferHolder();
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {times} ...");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++)
{
source.Buffer.TransposeInto(ref dest.Buffer);
}
sw.Stop();
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms");
}
[Theory]
[InlineData(1)]
[InlineData(10000000)]
public void TransposeInto_Benchmark(int times)
public void TranposeInto_PinningImpl_Benchmark(int times)
{
BufferHolder source = new BufferHolder();
source.Buffer.LoadFrom(Create8x8FloatData());
BufferHolder dest = new BufferHolder();
Output.WriteLine($"TransposeInto_Benchmark X {times} ...");
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {times} ...");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++)
{
source.Buffer.TranposeInto(ref dest.Buffer);
source.Buffer.TransposeInto_PinningImpl(ref dest.Buffer);
}
sw.Stop();
Output.WriteLine($"TransposeInto_Benchmark finished in {sw.ElapsedMilliseconds} ms");
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms");
}
[Theory]
[InlineData(1)]
[InlineData(10000000)]
public unsafe void PinnedTransposeInto_Benchmark(int times)
public unsafe void TransposeInto_WithPointers_Benchmark(int times)
{
BufferHolder source = new BufferHolder();
source.Buffer.LoadFrom(Create8x8FloatData());
BufferHolder dest = new BufferHolder();
fixed (Buffer8x8* sPtr = &source.Buffer)
fixed (Block8x8* sPtr = &source.Buffer)
{
fixed (Buffer8x8* dPtr = &dest.Buffer)
fixed (Block8x8* dPtr = &dest.Buffer)
{
Output.WriteLine($"PinnedTransposeInto_Benchmark X {times} ...");
Output.WriteLine($"TransposeInto_WithPointers_Benchmark X {times} ...");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++)
{
Buffer8x8.PinnedTransposeInto(sPtr, dPtr);
Block8x8.TransposeInto(sPtr, dPtr);
}
sw.Stop();
Output.WriteLine($"PinnedTransposeInto_Benchmark finished in {sw.ElapsedMilliseconds} ms");
Output.WriteLine($"TransposeInto_WithPointers_Benchmark finished in {sw.ElapsedMilliseconds} ms");
}
}
@ -203,10 +251,10 @@ namespace ImageSharp.Tests.Formats.Jpg
ReferenceDCT.iDCT2D8x4_32f(sourceArray, expectedDestArray);
Buffer8x8 source = new Buffer8x8();
Block8x8 source = new Block8x8();
source.LoadFrom(sourceArray);
Buffer8x8 dest = new Buffer8x8();
Block8x8 dest = new Block8x8();
source.iDCT2D8x4_LeftPart(ref dest);
@ -228,10 +276,10 @@ namespace ImageSharp.Tests.Formats.Jpg
ReferenceDCT.iDCT2D8x4_32f(sourceArray.Slice(4), expectedDestArray.Slice(4));
Buffer8x8 source = new Buffer8x8();
Block8x8 source = new Block8x8();
source.LoadFrom(sourceArray);
Buffer8x8 dest = new Buffer8x8();
Block8x8 dest = new Block8x8();
source.iDCT2D8x4_RightPart(ref dest);
@ -254,13 +302,13 @@ namespace ImageSharp.Tests.Formats.Jpg
ReferenceDCT.iDCT8x8_llm_sse(sourceArray, expectedDestArray, tempArray);
Buffer8x8 source = new Buffer8x8();
Block8x8 source = new Block8x8();
source.LoadFrom(sourceArray);
Buffer8x8 dest = new Buffer8x8();
Buffer8x8 tempBuffer = new Buffer8x8();
Block8x8 dest = new Block8x8();
Block8x8 tempBuffer = new Block8x8();
source.TransformIDCTInto(ref dest, ref tempBuffer);
source.IDCTInto(ref dest, ref tempBuffer);
float[] actualDestArray = new float[64];
dest.CopyTo(actualDestArray);

2
tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj

@ -74,7 +74,7 @@
<Compile Include="FileTestBase.cs" />
<Compile Include="Formats\Bmp\BitmapTests.cs" />
<Compile Include="Formats\GeneralFormatTests.cs" />
<Compile Include="Formats\Jpg\Buffer8x8Tests.cs" />
<Compile Include="Formats\Jpg\Block8x8Tests.cs" />
<Compile Include="Formats\Jpg\DctTests.cs" />
<Compile Include="Formats\Jpg\JpegTests.cs" />
<Compile Include="Formats\Jpg\UtilityTestClassBase.cs" />

Loading…
Cancel
Save