mirror of https://github.com/SixLabors/ImageSharp
10 changed files with 857 additions and 153 deletions
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
@ -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"); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue