Browse Source

Buffer64

af/merge-core
Anton Firszov 9 years ago
parent
commit
1cd2f2bbf5
  1. 404
      src/ImageSharp46/Formats/Jpg/Components/Buffer64.cs
  2. 61
      src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs
  3. 100
      src/ImageSharp46/Formats/Jpg/Components/Span.cs
  4. 3
      src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs
  5. 4
      src/ImageSharp46/ImageSharp46.csproj
  6. 97
      tests/ImageSharp.Tests46/DctSandbox.cs
  7. 180
      tests/ImageSharp.Tests46/Formats/Jpg/Buffer64Tests.cs
  8. 67
      tests/ImageSharp.Tests46/Formats/Jpg/DctTests.cs
  9. 90
      tests/ImageSharp.Tests46/Formats/Jpg/UtilityTestClassBase.cs
  10. 4
      tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj

404
src/ImageSharp46/Formats/Jpg/Components/Buffer64.cs

@ -0,0 +1,404 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace ImageSharp.Formats
{
public struct Buffer64
{
public Vector4 V00;
public Vector4 V01;
public Vector4 V02;
public Vector4 V03;
public Vector4 V10;
public Vector4 V11;
public Vector4 V12;
public Vector4 V13;
public Vector4 V20;
public Vector4 V21;
public Vector4 V22;
public Vector4 V23;
public Vector4 V30;
public Vector4 V31;
public Vector4 V32;
public Vector4 V33;
public const int VectorCount = 16;
public const int ScalarCount = VectorCount * 4;
public unsafe void LoadFrom(Span<float> source)
{
fixed (Vector4* ptr = &V00)
{
float* fp = (float*)ptr;
for (int i = 0; i < ScalarCount; i++)
{
fp[i] = source[i];
}
}
}
public unsafe void CopyTo(Span<float> dest)
{
fixed (Vector4* ptr = &V00)
{
float* fp = (float*)ptr;
for (int i = 0; i < ScalarCount; i++)
{
dest[i] = fp[i];
}
}
}
internal unsafe void LoadFrom(Span<int> source)
{
fixed (Vector4* ptr = &V00)
{
float* fp = (float*)ptr;
for (int i = 0; i < ScalarCount; i++)
{
fp[i] = source[i];
}
}
}
internal unsafe void CopyTo(Span<int> dest)
{
fixed (Vector4* ptr = &V00)
{
float* fp = (float*)ptr;
for (int i = 0; i < ScalarCount; i++)
{
dest[i] = (int) fp[i];
}
}
}
public unsafe void TransposeInplace()
{
fixed (Vector4* ptr = &V00)
{
float* data = (float*) ptr;
for (int i = 1; i < 8; i++)
{
int i8 = i * 8;
for (int j = 0; j < i; j++)
{
float tmp = data[i8 + j];
data[i8 + j] = data[j * 8 + i];
data[j * 8 + i] = tmp;
}
}
}
}
public unsafe void TranposeInto(ref Buffer64 destination)
{
fixed (Vector4* sPtr = &V00)
{
float* src = (float*)sPtr;
fixed (Vector4* dPtr = &destination.V00)
{
float* dest = (float*) dPtr;
for (int i = 0; i < 8; i++)
{
int i8 = i * 8;
for (int j = 0; j < 8; j++)
{
dest[j * 8 + i] = src[i8 + j];
}
}
}
}
}
//public struct Matrix
//{
// public Matrix4x4 A, B, C, D;
// public void LoadFrom(ref Buffer64 b)
// {
// fixed (Vector4*)
// }
//}
public void TransposeIntoSafe(ref Buffer64 destination)
{
Matrix4x4 a;
}
private static readonly Vector4 _c = new Vector4(0.1250f);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyAllInplace(Vector4 s)
{
V00 *= s; V01 *= s; V02 *= s; V03 *= s;
V10 *= s; V11 *= s; V12 *= s; V13 *= s;
V20 *= s; V21 *= s; V22 *= s; V23 *= s;
V30 *= s; V31 *= s; V32 *= s; V33 *= s;
}
// ReSharper disable once InconsistentNaming
public void TransformIDCTInto(ref Buffer64 dest, ref Buffer64 temp)
{
TranposeInto(ref temp);
temp.iDCT2D8x4_LeftPart(ref dest);
temp.iDCT2D8x4_RightPart(ref dest);
dest.TranposeInto(ref temp);
temp.iDCT2D8x4_LeftPart(ref dest);
temp.iDCT2D8x4_RightPart(ref dest);
dest.MultiplyAllInplace(new Vector4(0.1250f));
}
private static readonly Vector4 _1_175876 = new Vector4(1.175876f);
private static readonly Vector4 _1_961571 = new Vector4(-1.961571f);
private static readonly Vector4 _0_390181 = new Vector4(-0.390181f);
private static readonly Vector4 _0_899976 = new Vector4(-0.899976f);
private static readonly Vector4 _2_562915 = new Vector4(-2.562915f);
private static readonly Vector4 _0_298631 = new Vector4(0.298631f);
private static readonly Vector4 _2_053120 = new Vector4(2.053120f);
private static readonly Vector4 _3_072711 = new Vector4(3.072711f);
private static readonly Vector4 _1_501321 = new Vector4(1.501321f);
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);
internal void iDCT2D8x4_LeftPart(ref Buffer64 d)
{
/*
float a0,a1,a2,a3,b0,b1,b2,b3; float z0,z1,z2,z3,z4; float r[8]; int i;
for(i = 0;i < 8;i++){ r[i] = (float)(cos((double)i / 16.0 * M_PI) * M_SQRT2); }
*/
/*
0: 1.414214
1: 1.387040
2: 1.306563
3:
4: 1.000000
5: 0.785695
6:
7: 0.275899
*/
Vector4 my1 = V02;
Vector4 my7 = V32;
Vector4 mz0 = my1 + my7;
Vector4 my3 = V12;
Vector4 mz2 = my3 + my7;
Vector4 my5 = V22;
Vector4 mz1 = my3 + my5;
Vector4 mz3 = my1 + my5;
Vector4 mz4 = ((mz0 + mz1) * _1_175876);
//z0 = y[1] + y[7]; z1 = y[3] + y[5]; z2 = y[3] + y[7]; z3 = y[1] + y[5];
//z4 = (z0 + z1) * r[3];
mz2 = mz2 * _1_961571 + mz4;
mz3 = mz3 * _0_390181 + mz4;
mz0 = mz0 * _0_899976;
mz1 = mz1 * _2_562915;
/*
-0.899976
-2.562915
-1.961571
-0.390181
z0 = z0 * (-r[3] + r[7]);
z1 = z1 * (-r[3] - r[1]);
z2 = z2 * (-r[3] - r[5]) + z4;
z3 = z3 * (-r[3] + r[5]) + z4;*/
Vector4 mb3 = my7 * _0_298631 + mz0 + mz2;
Vector4 mb2 = my5 * _2_053120 + mz1 + mz3;
Vector4 mb1 = my3 * _3_072711 + mz1 + mz2;
Vector4 mb0 = my1 * _1_501321 + mz0 + mz3;
/*
0.298631
2.053120
3.072711
1.501321
b3 = y[7] * (-r[1] + r[3] + r[5] - r[7]) + z0 + z2;
b2 = y[5] * ( r[1] + r[3] - r[5] + r[7]) + z1 + z3;
b1 = y[3] * ( r[1] + r[3] + r[5] - r[7]) + z1 + z2;
b0 = y[1] * ( r[1] + r[3] - r[5] - r[7]) + z0 + z3;
*/
Vector4 my2 = V10;
Vector4 my6 = V30;
mz4 = (my2 + my6) * _0_541196;
Vector4 my0 = V00;
Vector4 my4 = V20;
mz0 = my0 + my4;
mz1 = my0 - my4;
mz2 = mz4 + my6 * _1_847759;
mz3 = mz4 + my2 * _0_765367;
my0 = mz0 + mz3;
my3 = mz0 - mz3;
my1 = mz1 + mz2;
my2 = mz1 - mz2;
/*
1.847759
0.765367
z4 = (y[2] + y[6]) * r[6];
z0 = y[0] + y[4]; z1 = y[0] - y[4];
z2 = z4 - y[6] * (r[2] + r[6]);
z3 = z4 + y[2] * (r[2] - r[6]);
a0 = z0 + z3; a3 = z0 - z3;
a1 = z1 + z2; a2 = z1 - z2;
*/
d.V00 = my0 + mb0;
d.V32 = my0 - mb0;
d.V02 = my1 + mb1;
d.V30 = my1 - mb1;
d.V10 = my2 + mb2;
d.V22 = my2 - mb2;
d.V12 = my3 + mb3;
d.V20 = my3 - mb3;
/*
x[0] = a0 + b0; x[7] = a0 - b0;
x[1] = a1 + b1; x[6] = a1 - b1;
x[2] = a2 + b2; x[5] = a2 - b2;
x[3] = a3 + b3; x[4] = a3 - b3;
for(i = 0;i < 8;i++){ x[i] *= 0.353554f; }
*/
}
internal void iDCT2D8x4_RightPart(ref Buffer64 d)
{
/*
float a0,a1,a2,a3,b0,b1,b2,b3; float z0,z1,z2,z3,z4; float r[8]; int i;
for(i = 0;i < 8;i++){ r[i] = (float)(cos((double)i / 16.0 * M_PI) * M_SQRT2); }
*/
/*
0: 1.414214
1: 1.387040
2: 1.306563
3:
4: 1.000000
5: 0.785695
6:
7: 0.275899
*/
Vector4 my1 = V03;
Vector4 my7 = V33;
Vector4 mz0 = my1 + my7;
Vector4 my3 = V13;
Vector4 mz2 = my3 + my7;
Vector4 my5 = V23;
Vector4 mz1 = my3 + my5;
Vector4 mz3 = my1 + my5;
Vector4 mz4 = ((mz0 + mz1) * _1_175876);
//z0 = y[1] + y[7]; z1 = y[3] + y[5]; z2 = y[3] + y[7]; z3 = y[1] + y[5];
//z4 = (z0 + z1) * r[3];
mz2 = mz2 * _1_961571 + mz4;
mz3 = mz3 * _0_390181 + mz4;
mz0 = mz0 * _0_899976;
mz1 = mz1 * _2_562915;
/*
-0.899976
-2.562915
-1.961571
-0.390181
z0 = z0 * (-r[3] + r[7]);
z1 = z1 * (-r[3] - r[1]);
z2 = z2 * (-r[3] - r[5]) + z4;
z3 = z3 * (-r[3] + r[5]) + z4;*/
Vector4 mb3 = my7 * _0_298631 + mz0 + mz2;
Vector4 mb2 = my5 * _2_053120 + mz1 + mz3;
Vector4 mb1 = my3 * _3_072711 + mz1 + mz2;
Vector4 mb0 = my1 * _1_501321 + mz0 + mz3;
/*
0.298631
2.053120
3.072711
1.501321
b3 = y[7] * (-r[1] + r[3] + r[5] - r[7]) + z0 + z2;
b2 = y[5] * ( r[1] + r[3] - r[5] + r[7]) + z1 + z3;
b1 = y[3] * ( r[1] + r[3] + r[5] - r[7]) + z1 + z2;
b0 = y[1] * ( r[1] + r[3] - r[5] - r[7]) + z0 + z3;
*/
Vector4 my2 = V11;
Vector4 my6 = V31;
mz4 = (my2 + my6) * _0_541196;
Vector4 my0 = V01;
Vector4 my4 = V21;
mz0 = my0 + my4;
mz1 = my0 - my4;
mz2 = mz4 + my6 * _1_847759;
mz3 = mz4 + my2 * _0_765367;
my0 = mz0 + mz3;
my3 = mz0 - mz3;
my1 = mz1 + mz2;
my2 = mz1 - mz2;
/*
1.847759
0.765367
z4 = (y[2] + y[6]) * r[6];
z0 = y[0] + y[4]; z1 = y[0] - y[4];
z2 = z4 - y[6] * (r[2] + r[6]);
z3 = z4 + y[2] * (r[2] - r[6]);
a0 = z0 + z3; a3 = z0 - z3;
a1 = z1 + z2; a2 = z1 - z2;
*/
d.V01 = my0 + mb0;
d.V33 = my0 - mb0;
d.V03 = my1 + mb1;
d.V31 = my1 - mb1;
d.V11 = my2 + mb2;
d.V23 = my2 - mb2;
d.V13 = my3 + mb3;
d.V21 = my3 - mb3;
/*
x[0] = a0 + b0; x[7] = a0 - b0;
x[1] = a1 + b1; x[6] = a1 - b1;
x[2] = a2 + b2; x[5] = a2 - b2;
x[3] = a3 + b3; x[4] = a3 - b3;
for(i = 0;i < 8;i++){ x[i] *= 0.353554f; }
*/
}
public static void SuchIDCT(ref Block block)
{
Buffer64 source = new Buffer64();
source.LoadFrom(block.Data);
Buffer64 dest = new Buffer64();
Buffer64 temp = new Buffer64();
source.TransformIDCTInto(ref dest, ref temp);
dest.CopyTo(block.Data);
}
}
}

61
src/ImageSharp46/Formats/Jpg/Components/MagicDCT.cs → src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs

@ -5,59 +5,13 @@ using System.Runtime.CompilerServices;
namespace ImageSharp.Formats
{
public struct Span<T>
where T : struct
{
public T[] Data;
public int Offset;
public Span(int size, int offset = 0)
{
Data = new T[size];
Offset = offset;
}
public Span(T[] data, int offset = 0)
{
Data = data;
Offset = offset;
}
public T this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Data[idx + Offset]; }
[MethodImpl(MethodImplOptions.AggressiveInlining)] set { Data[idx + Offset] = value; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> Slice(int offset)
{
return new Span<T>(Data, Offset + offset);
}
public static implicit operator Span<T>(T[] data) => new Span<T>(data, 0);
private static readonly ArrayPool<T> Pool = ArrayPool<T>.Create(128, 10);
public static Span<T> RentFromPool(int size, int offset = 0)
{
return new Span<T>(Pool.Rent(size), offset);
}
public void ReturnToPool()
{
Pool.Return(Data, true);
Data = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddOffset(int offset)
{
Offset += offset;
}
}
public static class MagicDCT
/// <summary>
/// Ported from https://github.com/norishigefukushima/dct_simd
/// In this form, its Slow in C#
/// Used as a reference implementation in test cases!
/// </summary>
// ReSharper disable once InconsistentNaming
public static class ReferenceDCT
{
private static readonly ArrayPool<float> FloatArrayPool = ArrayPool<float>.Create(Block.BlockSize, 50);
@ -425,6 +379,7 @@ namespace ImageSharp.Formats
6:
7: 0.275899
*/
Vector4 my1 = _mm_load_ps(y, 8);
Vector4 my7 = _mm_load_ps(y, 56);
Vector4 mz0 = my1 + my7;

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

@ -0,0 +1,100 @@
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace ImageSharp.Formats
{
public struct Span<T>
{
public T[] Data;
public int Offset;
public int TotalCount => Data.Length - Offset;
public Span(int size, int offset = 0)
{
Data = new T[size];
Offset = offset;
}
public Span(T[] data, int offset = 0)
{
Data = data;
Offset = offset;
}
public T this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Data[idx + Offset]; }
[MethodImpl(MethodImplOptions.AggressiveInlining)] set { Data[idx + Offset] = value; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> Slice(int offset)
{
return new Span<T>(Data, Offset + offset);
}
public static implicit operator Span<T>(T[] data) => new Span<T>(data, 0);
private static readonly ArrayPool<T> Pool = ArrayPool<T>.Create(128, 10);
public static Span<T> RentFromPool(int size, int offset = 0)
{
return new Span<T>(Pool.Rent(size), offset);
}
public void ReturnToPool()
{
Pool.Return(Data, true);
Data = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddOffset(int offset)
{
Offset += offset;
}
}
public static class SpanExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SaveTo(this Span<float> data, ref Vector4 v)
{
v.X = data[0];
v.Y = data[1];
v.Z = data[2];
v.W = data[3];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SaveTo(this Span<int> data, ref Vector4 v)
{
v.X = data[0];
v.Y = data[1];
v.Z = data[2];
v.W = data[3];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LoadFrom(this Span<float> data, ref Vector4 v)
{
data[0] = v.X;
data[1] = v.Y;
data[2] = v.Z;
data[3] = v.W;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LoadFrom(this Span<int> data, ref Vector4 v)
{
data[0] = (int)v.X;
data[1] = (int)v.Y;
data[2] = (int)v.Z;
data[3] = (int)v.W;
}
}
}

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

@ -1813,7 +1813,8 @@ namespace ImageSharp.Formats
//IDCT.Transform(ref b);
//FloatIDCT.Transform(ref b);
MagicDCT.IDCT(ref b);
//ReferenceDCT.IDCT(ref b);
Buffer64.SuchIDCT(ref b);
byte[] dst;
int offset;

4
src/ImageSharp46/ImageSharp46.csproj

@ -227,6 +227,7 @@
<Compile Include="Formats\IImageFormat.cs" />
<Compile Include="Formats\Jpg\Components\Bits.cs" />
<Compile Include="Formats\Jpg\Components\Block.cs" />
<Compile Include="Formats\Jpg\Components\Buffer64.cs" />
<Compile Include="Formats\Jpg\Components\Bytes.cs" />
<Compile Include="Formats\Jpg\Components\Component.cs" />
<Compile Include="Formats\Jpg\Components\FDCT.cs" />
@ -234,7 +235,8 @@
<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\MagicDCT.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" />
<Compile Include="Formats\Jpg\JpegDecoder.cs" />

97
tests/ImageSharp.Tests46/DctSandbox.cs

@ -1,97 +0,0 @@
using System.Numerics;
using System.Text;
using ImageSharp.Formats;
using Xunit;
using Xunit.Abstractions;
namespace ImageSharp.Tests
{
public class DctSandbox
{
private ITestOutputHelper Output { get; }
public DctSandbox(ITestOutputHelper output)
{
Output = output;
}
private float[] CreateTestData()
{
float[] result =new float[64];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
result[i*8 + j] = i*10 + j;
}
}
return result;
}
private void Print(float[] data)
{
StringBuilder bld = new StringBuilder();
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
bld.Append($"{data[i * 8 + j],3} ");
}
bld.AppendLine();
}
Output.WriteLine(bld.ToString());
}
[Fact]
public void Mennyi()
{
Output.WriteLine(Vector.IsHardwareAccelerated.ToString());
Output.WriteLine(Vector<float>.Count.ToString());
}
[Fact]
public void CheckTestData()
{
var data = CreateTestData();
Print(data);
}
[Fact]
public void Load_Store()
{
var data = CreateTestData();
var m = MagicDCT.Load(data, 1, 1);
m = Matrix4x4.Transpose(m);
MagicDCT.Store(m, data, 4, 4);
Print(data);
}
[Fact]
public void Transpose8x8()
{
var data = CreateTestData();
Span<float> result = new Span<float>(64);
MagicDCT.Transpose8x8(data, result);
Print(result.Data);
}
[Fact]
public void Transpose8x8_Inplace()
{
var data = CreateTestData();
MagicDCT.Transpose8x8(data);
Print(data);
}
}
}

180
tests/ImageSharp.Tests46/Formats/Jpg/Buffer64Tests.cs

@ -0,0 +1,180 @@
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using ImageSharp.Formats;
using Xunit;
using Xunit.Abstractions;
namespace ImageSharp.Tests.Formats.Jpg
{
public class Buffer64Tests : UtilityTestClassBase
{
public Buffer64Tests(ITestOutputHelper output) : base(output)
{
}
[Theory]
[InlineData(1)]
[InlineData(1000000)]
public void Load_Store_FloatArray(int times)
{
float[] data = new float[Buffer64.ScalarCount];
float[] mirror = new float[Buffer64.ScalarCount];
for (int i = 0; i < Buffer64.ScalarCount; i++)
{
data[i] = i;
}
Measure(times, () =>
{
Buffer64 v = new Buffer64();
v.LoadFrom(data);
v.CopyTo(mirror);
});
Assert.Equal(data, mirror);
PrintLinearData((Span<float>)mirror);
}
[Theory]
[InlineData(1)]
[InlineData(1000000)]
public void Load_Store_IntArray(int times)
{
int[] data = new int[Buffer64.ScalarCount];
int[] mirror = new int[Buffer64.ScalarCount];
for (int i = 0; i < Buffer64.ScalarCount; i++)
{
data[i] = i;
}
Measure(times, () =>
{
Buffer64 v = new Buffer64();
v.LoadFrom(data);
v.CopyTo(mirror);
});
Assert.Equal(data, mirror);
PrintLinearData((Span<int>)mirror);
}
[Fact]
public void TransposeInplace()
{
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Buffer64 buffer = new Buffer64();
buffer.LoadFrom(Create8x8FloatData());
buffer.TransposeInplace();
float[] actual = new float[64];
buffer.CopyTo(actual);
Assert.Equal(expected, actual);
}
[Fact]
public void TransposeInto()
{
float[] expected = Create8x8FloatData();
ReferenceDCT.Transpose8x8(expected);
Buffer64 source = new Buffer64();
source.LoadFrom(Create8x8FloatData());
Buffer64 dest = new Buffer64();
source.TranposeInto(ref dest);
float[] actual = new float[64];
dest.CopyTo(actual);
Assert.Equal(expected, actual);
}
[Fact]
public void iDCT2D8x4_LeftPart()
{
float[] sourceArray = Create8x8FloatData();
float[] expectedDestArray = new float[64];
ReferenceDCT.iDCT2D8x4_32f(sourceArray, expectedDestArray);
Buffer64 source = new Buffer64();
source.LoadFrom(sourceArray);
Buffer64 dest = new Buffer64();
source.iDCT2D8x4_LeftPart(ref dest);
float[] actualDestArray = new float[64];
dest.CopyTo(actualDestArray);
Print8x8Data(expectedDestArray);
Output.WriteLine("**************");
Print8x8Data(actualDestArray);
Assert.Equal(expectedDestArray, actualDestArray);
}
[Fact]
public void iDCT2D8x4_RightPart()
{
Span<float> sourceArray = Create8x8FloatData();
Span<float> expectedDestArray = new float[64];
ReferenceDCT.iDCT2D8x4_32f(sourceArray.Slice(4), expectedDestArray.Slice(4));
Buffer64 source = new Buffer64();
source.LoadFrom(sourceArray);
Buffer64 dest = new Buffer64();
source.iDCT2D8x4_RightPart(ref dest);
float[] actualDestArray = new float[64];
dest.CopyTo(actualDestArray);
Print8x8Data(expectedDestArray);
Output.WriteLine("**************");
Print8x8Data(actualDestArray);
Assert.Equal(expectedDestArray.Data, actualDestArray);
}
[Fact]
public void IDCT()
{
float[] sourceArray = Create8x8FloatData();
float[] expectedDestArray = new float[64];
float[] tempArray = new float[64];
ReferenceDCT.iDCT8x8_llm_sse(sourceArray, expectedDestArray, tempArray);
Buffer64 source = new Buffer64();
source.LoadFrom(sourceArray);
Buffer64 dest = new Buffer64();
Buffer64 tempBuffer = new Buffer64();
source.TransformIDCTInto(ref dest, ref tempBuffer);
float[] actualDestArray = new float[64];
dest.CopyTo(actualDestArray);
Print8x8Data(expectedDestArray);
Output.WriteLine("**************");
Print8x8Data(actualDestArray);
Assert.Equal(expectedDestArray, actualDestArray);
}
}
}

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

@ -0,0 +1,67 @@
using System.Numerics;
using ImageSharp.Formats;
using Xunit;
using Xunit.Abstractions;
namespace ImageSharp.Tests.Formats.Jpg
{
public class DctTests : UtilityTestClassBase
{
public DctTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void Mennyi()
{
Output.WriteLine(Vector.IsHardwareAccelerated.ToString());
Output.WriteLine(Vector<float>.Count.ToString());
}
[Fact]
public void CheckTestData()
{
var data = Create8x8FloatData();
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()
{
var data = Create8x8FloatData();
Span<float> result = new Span<float>(64);
ReferenceDCT.Transpose8x8(data, result);
Print8x8Data(result.Data);
}
[Fact]
public void Transpose8x8_Inplace()
{
var data = Create8x8FloatData();
ReferenceDCT.Transpose8x8(data);
Print8x8Data(data);
}
}
}

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

@ -0,0 +1,90 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
using ImageSharp.Formats;
using Xunit.Abstractions;
namespace ImageSharp.Tests.Formats.Jpg
{
public class UtilityTestClassBase
{
public UtilityTestClassBase(ITestOutputHelper output)
{
Output = output;
}
protected ITestOutputHelper Output { get; }
// ReSharper disable once InconsistentNaming
public static float[] Create8x8FloatData()
{
float[] result = new float[64];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
result[i * 8 + j] = i * 10 + j;
}
}
return result;
}
// ReSharper disable once InconsistentNaming
public static int[] Create8x8IntData()
{
int[] result = new int[64];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
result[i * 8 + j] = i * 10 + j;
}
}
return result;
}
protected void Print8x8Data<T>(Span<T> data) => Print8x8Data(data.Data);
protected void Print8x8Data<T>(T[] data)
{
StringBuilder bld = new StringBuilder();
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
bld.Append($"{data[i * 8 + j],3} ");
}
bld.AppendLine();
}
Output.WriteLine(bld.ToString());
}
protected void PrintLinearData<T>(Span<T> data, int count = -1)
{
if (count < 0) count = data.TotalCount;
StringBuilder bld = new StringBuilder();
for (int i = 0; i < count; i++)
{
bld.Append($"{data[i],3} ");
}
Output.WriteLine(bld.ToString());
}
protected void Measure(int times, Action action, [CallerMemberName] string operationName = null)
{
Output.WriteLine($"{operationName} X {times} ...");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++)
{
action();
}
sw.Stop();
Output.WriteLine($"{operationName} finished in {sw.ElapsedMilliseconds} ms");
}
}
}

4
tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj

@ -71,11 +71,13 @@
<Compile Include="Benchmark\DecodeJpegBenchmark.cs" />
<Compile Include="Colors\ColorConversionTests.cs" />
<Compile Include="Colors\ColorTests.cs" />
<Compile Include="DctSandbox.cs" />
<Compile Include="FileTestBase.cs" />
<Compile Include="Formats\Bmp\BitmapTests.cs" />
<Compile Include="Formats\GeneralFormatTests.cs" />
<Compile Include="Formats\Jpg\Buffer64Tests.cs" />
<Compile Include="Formats\Jpg\DctTests.cs" />
<Compile Include="Formats\Jpg\JpegTests.cs" />
<Compile Include="Formats\Jpg\UtilityTestClassBase.cs" />
<Compile Include="Formats\Png\PngTests.cs" />
<Compile Include="Helpers\GuardTests.cs" />
<Compile Include="Image\ImagePropertyTests.cs" />

Loading…
Cancel
Save