From 1cd2f2bbf51b7422a7f938d5a714fffa441e589f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 12 Nov 2016 13:39:25 +0100 Subject: [PATCH] Buffer64 --- .../Formats/Jpg/Components/Buffer64.cs | 404 ++++++++++++++++++ .../{MagicDCT.cs => ReferenceDCT.cs} | 61 +-- .../Formats/Jpg/Components/Span.cs | 100 +++++ .../Formats/Jpg/JpegDecoderCore.cs | 3 +- src/ImageSharp46/ImageSharp46.csproj | 4 +- tests/ImageSharp.Tests46/DctSandbox.cs | 97 ----- .../Formats/Jpg/Buffer64Tests.cs | 180 ++++++++ .../Formats/Jpg/DctTests.cs | 67 +++ .../Formats/Jpg/UtilityTestClassBase.cs | 90 ++++ .../ImageSharp.Tests46.csproj | 4 +- 10 files changed, 857 insertions(+), 153 deletions(-) create mode 100644 src/ImageSharp46/Formats/Jpg/Components/Buffer64.cs rename src/ImageSharp46/Formats/Jpg/Components/{MagicDCT.cs => ReferenceDCT.cs} (92%) create mode 100644 src/ImageSharp46/Formats/Jpg/Components/Span.cs delete mode 100644 tests/ImageSharp.Tests46/DctSandbox.cs create mode 100644 tests/ImageSharp.Tests46/Formats/Jpg/Buffer64Tests.cs create mode 100644 tests/ImageSharp.Tests46/Formats/Jpg/DctTests.cs create mode 100644 tests/ImageSharp.Tests46/Formats/Jpg/UtilityTestClassBase.cs diff --git a/src/ImageSharp46/Formats/Jpg/Components/Buffer64.cs b/src/ImageSharp46/Formats/Jpg/Components/Buffer64.cs new file mode 100644 index 000000000..f3b47e3a4 --- /dev/null +++ b/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 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 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 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 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); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp46/Formats/Jpg/Components/MagicDCT.cs b/src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs similarity index 92% rename from src/ImageSharp46/Formats/Jpg/Components/MagicDCT.cs rename to src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs index 6c71ec92e..a83ec5d4c 100644 --- a/src/ImageSharp46/Formats/Jpg/Components/MagicDCT.cs +++ b/src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs @@ -5,59 +5,13 @@ using System.Runtime.CompilerServices; namespace ImageSharp.Formats { - public struct Span - 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 Slice(int offset) - { - return new Span(Data, Offset + offset); - } - - public static implicit operator Span(T[] data) => new Span(data, 0); - - private static readonly ArrayPool Pool = ArrayPool.Create(128, 10); - - public static Span RentFromPool(int size, int offset = 0) - { - return new Span(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 + /// + /// Ported from https://github.com/norishigefukushima/dct_simd + /// In this form, its Slow in C# + /// Used as a reference implementation in test cases! + /// + // ReSharper disable once InconsistentNaming + public static class ReferenceDCT { private static readonly ArrayPool FloatArrayPool = ArrayPool.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; diff --git a/src/ImageSharp46/Formats/Jpg/Components/Span.cs b/src/ImageSharp46/Formats/Jpg/Components/Span.cs new file mode 100644 index 000000000..8ef747125 --- /dev/null +++ b/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 + { + 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 Slice(int offset) + { + return new Span(Data, Offset + offset); + } + + public static implicit operator Span(T[] data) => new Span(data, 0); + + private static readonly ArrayPool Pool = ArrayPool.Create(128, 10); + + public static Span RentFromPool(int size, int offset = 0) + { + return new Span(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 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 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 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 data, ref Vector4 v) + { + data[0] = (int)v.X; + data[1] = (int)v.Y; + data[2] = (int)v.Z; + data[3] = (int)v.W; + } + + + } +} \ No newline at end of file diff --git a/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs index 2f0b22829..08368a31a 100644 --- a/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs +++ b/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; diff --git a/src/ImageSharp46/ImageSharp46.csproj b/src/ImageSharp46/ImageSharp46.csproj index fdb1b7293..64b931c0d 100644 --- a/src/ImageSharp46/ImageSharp46.csproj +++ b/src/ImageSharp46/ImageSharp46.csproj @@ -227,6 +227,7 @@ + @@ -234,7 +235,8 @@ - + + diff --git a/tests/ImageSharp.Tests46/DctSandbox.cs b/tests/ImageSharp.Tests46/DctSandbox.cs deleted file mode 100644 index d3b1bacb2..000000000 --- a/tests/ImageSharp.Tests46/DctSandbox.cs +++ /dev/null @@ -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.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 result = new Span(64); - - MagicDCT.Transpose8x8(data, result); - - Print(result.Data); - } - - [Fact] - public void Transpose8x8_Inplace() - { - var data = CreateTestData(); - - MagicDCT.Transpose8x8(data); - - Print(data); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests46/Formats/Jpg/Buffer64Tests.cs b/tests/ImageSharp.Tests46/Formats/Jpg/Buffer64Tests.cs new file mode 100644 index 000000000..be57d22d4 --- /dev/null +++ b/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)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)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 sourceArray = Create8x8FloatData(); + Span 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); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests46/Formats/Jpg/DctTests.cs b/tests/ImageSharp.Tests46/Formats/Jpg/DctTests.cs new file mode 100644 index 000000000..a25988bc5 --- /dev/null +++ b/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.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 result = new Span(64); + + ReferenceDCT.Transpose8x8(data, result); + + Print8x8Data(result.Data); + } + + [Fact] + public void Transpose8x8_Inplace() + { + var data = Create8x8FloatData(); + + ReferenceDCT.Transpose8x8(data); + + Print8x8Data(data); + } + + + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests46/Formats/Jpg/UtilityTestClassBase.cs b/tests/ImageSharp.Tests46/Formats/Jpg/UtilityTestClassBase.cs new file mode 100644 index 000000000..1e205655d --- /dev/null +++ b/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(Span data) => Print8x8Data(data.Data); + + protected void Print8x8Data(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(Span 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"); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj b/tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj index ab80f3d93..07b7cf407 100644 --- a/tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj +++ b/tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj @@ -71,11 +71,13 @@ - + + +