Browse Source

goodby MutableSpan!

pull/322/head
Anton Firszov 9 years ago
parent
commit
492c32ef45
  1. 39
      src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
  2. 6
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegPixelArea.cs
  3. 98
      src/ImageSharp/Formats/Jpeg/GolangPort/Utils/MutableSpan.cs
  4. 61
      src/ImageSharp/Formats/Jpeg/GolangPort/Utils/MutableSpanExtensions.cs
  5. 46
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
  6. 14
      tests/ImageSharp.Tests/Formats/Jpg/JpegUtilityTestFixture.cs
  7. 66
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementations.cs
  8. 28
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs

39
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs

@ -5,11 +5,12 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{
using SixLabors.ImageSharp.Memory;
/// <summary>
/// DCT code Ported from https://github.com/norishigefukushima/dct_simd
/// </summary>
@ -86,7 +87,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
}
}
}
/// <summary>
/// Pointer-based "Indexer" (getter part)
/// </summary>
@ -128,12 +129,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// </summary>
/// <param name="source">Source</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void LoadFrom(MutableSpan<float> source)
public void LoadFrom(Span<float> source)
{
fixed (void* ptr = &this.V0L)
{
Marshal.Copy(source.Data, source.Offset, (IntPtr)ptr, ScalarCount);
}
ref byte s = ref Unsafe.As<float, byte>(ref source.DangerousGetPinnableReference());
ref byte d = ref Unsafe.As<Block8x8F, byte>(ref this);
Unsafe.CopyBlock(ref d, ref s, ScalarCount * sizeof(float));
}
/// <summary>
@ -142,16 +143,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <param name="blockPtr">Block pointer</param>
/// <param name="source">Source</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void LoadFrom(Block8x8F* blockPtr, MutableSpan<float> source)
public static unsafe void LoadFrom(Block8x8F* blockPtr, Span<float> source)
{
Marshal.Copy(source.Data, source.Offset, (IntPtr)blockPtr, ScalarCount);
blockPtr->LoadFrom(source);
}
/// <summary>
/// Load raw 32bit floating point data from source
/// </summary>
/// <param name="source">Source</param>
public unsafe void LoadFrom(MutableSpan<int> source)
public unsafe void LoadFrom(Span<int> source)
{
fixed (Vector4* ptr = &this.V0L)
{
@ -168,12 +169,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// </summary>
/// <param name="dest">Destination</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void CopyTo(MutableSpan<float> dest)
public unsafe void CopyTo(Span<float> dest)
{
fixed (void* ptr = &this.V0L)
{
Marshal.Copy((IntPtr)ptr, dest.Data, dest.Offset, ScalarCount);
}
ref byte d = ref Unsafe.As<float, byte>(ref dest.DangerousGetPinnableReference());
ref byte s = ref Unsafe.As<Block8x8F, byte>(ref this);
Unsafe.CopyBlock(ref d, ref s, ScalarCount * sizeof(float));
}
/// <summary>
@ -182,7 +183,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <param name="blockPtr">Pointer to block</param>
/// <param name="dest">Destination</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void CopyTo(Block8x8F* blockPtr, MutableSpan<byte> dest)
public static unsafe void CopyTo(Block8x8F* blockPtr, Span<byte> dest)
{
float* fPtr = (float*)blockPtr;
for (int i = 0; i < ScalarCount; i++)
@ -198,9 +199,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <param name="blockPtr">Block pointer</param>
/// <param name="dest">Destination</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void CopyTo(Block8x8F* blockPtr, MutableSpan<float> dest)
public static unsafe void CopyTo(Block8x8F* blockPtr, Span<float> dest)
{
Marshal.Copy((IntPtr)blockPtr, dest.Data, dest.Offset, ScalarCount);
blockPtr->CopyTo(dest);
}
/// <summary>
@ -220,7 +221,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// Copy raw 32bit floating point data to dest
/// </summary>
/// <param name="dest">Destination</param>
public unsafe void CopyTo(MutableSpan<int> dest)
public unsafe void CopyTo(Span<int> dest)
{
fixed (Vector4* ptr = &this.V0L)
{

6
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegPixelArea.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils;
using SixLabors.ImageSharp.Memory;
using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F;
@ -59,9 +59,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public int Offset { get; }
/// <summary>
/// Gets a <see cref="MutableSpan{T}" /> of bytes to the pixel area
/// Gets a <see cref="Span{T}" /> of bytes to the pixel area
/// </summary>
public MutableSpan<byte> Span => new MutableSpan<byte>(this.Pixels.Array, this.Offset);
public Span<byte> Span => new Span<byte>(this.Pixels.Array, this.Offset);
/// <summary>
/// Returns the pixel at (x, y)

98
src/ImageSharp/Formats/Jpeg/GolangPort/Utils/MutableSpan.cs

@ -1,98 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
{
/// <summary>
/// Like corefxlab Span, but with an AddOffset() method for efficiency.
/// TODO: When Span will be official, consider replacing this class!
/// </summary>
/// <see>
/// <cref>https://github.com/dotnet/corefxlab/blob/master/src/System.Slices/System/Span.cs</cref>
/// </see>
/// <typeparam name="T">The type of the data in the span</typeparam>
internal struct MutableSpan<T>
{
/// <summary>
/// Data
/// </summary>
public T[] Data;
/// <summary>
/// Offset
/// </summary>
public int Offset;
/// <summary>
/// Initializes a new instance of the <see cref="MutableSpan{T}"/> struct.
/// </summary>
/// <param name="size">The size of the span</param>
/// <param name="offset">The offset (defaults to 0)</param>
public MutableSpan(int size, int offset = 0)
{
this.Data = new T[size];
this.Offset = offset;
}
/// <summary>
/// Initializes a new instance of the <see cref="MutableSpan{T}"/> struct.
/// </summary>
/// <param name="data">The data</param>
/// <param name="offset">The offset (defaults to 0)</param>
public MutableSpan(T[] data, int offset = 0)
{
this.Data = data;
this.Offset = offset;
}
/// <summary>
/// Gets the total count of data
/// </summary>
public int TotalCount => this.Data.Length - this.Offset;
/// <summary>
/// Index into the data
/// </summary>
/// <param name="idx">The data</param>
/// <returns>The value at the specified index</returns>
public T this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.Data[idx + this.Offset];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.Data[idx + this.Offset] = value;
}
}
public static implicit operator MutableSpan<T>(T[] data) => new MutableSpan<T>(data, 0);
/// <summary>
/// Slice the data
/// </summary>
/// <param name="offset">The offset</param>
/// <returns>The new <see cref="MutableSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public MutableSpan<T> Slice(int offset)
{
return new MutableSpan<T>(this.Data, this.Offset + offset);
}
/// <summary>
/// Add to the offset
/// </summary>
/// <param name="offset">The additional offset</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddOffset(int offset)
{
this.Offset += offset;
}
}
}

61
src/ImageSharp/Formats/Jpeg/GolangPort/Utils/MutableSpanExtensions.cs

@ -6,27 +6,20 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
{
using System;
/// <summary>
/// MutableSpan Extensions
/// </summary>
internal static class MutableSpanExtensions
{
/// <summary>
/// Slice <see cref="MutableSpan{T}"/>
/// </summary>
/// <typeparam name="T">The type of the data in the span</typeparam>
/// <param name="array">The data array</param>
/// <param name="offset">The offset</param>
/// <returns>The new <see cref="MutableSpan{T}"/></returns>
public static MutableSpan<T> Slice<T>(this T[] array, int offset) => new MutableSpan<T>(array, offset);
/// <summary>
/// Save to a Vector4
/// </summary>
/// <param name="data">The data</param>
/// <param name="v">The vector to save to</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SaveTo(this MutableSpan<float> data, ref Vector4 v)
public static void SaveTo(this Span<float> data, ref Vector4 v)
{
v.X = data[0];
v.Y = data[1];
@ -40,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
/// <param name="data">The data</param>
/// <param name="v">The vector to save to</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SaveTo(this MutableSpan<int> data, ref Vector4 v)
public static void SaveTo(this Span<int> data, ref Vector4 v)
{
v.X = data[0];
v.Y = data[1];
@ -54,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
/// <param name="data">The data</param>
/// <param name="v">The vector to load from</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LoadFrom(this MutableSpan<float> data, ref Vector4 v)
public static void LoadFrom(this Span<float> data, ref Vector4 v)
{
data[0] = v.X;
data[1] = v.Y;
@ -68,7 +61,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
/// <param name="data">The data</param>
/// <param name="v">The vector to load from</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LoadFrom(this MutableSpan<int> data, ref Vector4 v)
public static void LoadFrom(this Span<int> data, ref Vector4 v)
{
data[0] = (int)v.X;
data[1] = (int)v.Y;
@ -80,11 +73,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
/// Converts all int values of src to float
/// </summary>
/// <param name="src">Source</param>
/// <returns>A new <see cref="MutableSpan{T}"/> with float values</returns>
public static MutableSpan<float> ConvertToFloat32MutableSpan(this MutableSpan<int> src)
/// <returns>A new <see cref="Span{T}"/> with float values</returns>
public static float[] ConvertAllToFloat(this int[] src)
{
MutableSpan<float> result = new MutableSpan<float>(src.TotalCount);
for (int i = 0; i < src.TotalCount; i++)
float[] result = new float[src.Length];
for (int i = 0; i < src.Length; i++)
{
result[i] = (float)src[i];
}
@ -96,11 +89,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
/// Converts all float values of src to int
/// </summary>
/// <param name="src">Source</param>
/// <returns>A new <see cref="MutableSpan{T}"/> with float values</returns>
public static MutableSpan<int> ConvertToInt32MutableSpan(this MutableSpan<float> src)
/// <returns>A new <see cref="Span{T}"/> with float values</returns>
public static Span<int> ConvertToInt32MutableSpan(this Span<float> src)
{
MutableSpan<int> result = new MutableSpan<int>(src.TotalCount);
for (int i = 0; i < src.TotalCount; i++)
int[] result = new int[src.Length];
for (int i = 0; i < src.Length; i++)
{
result[i] = (int)src[i];
}
@ -113,11 +106,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
/// </summary>
/// <param name="src">The source</param>
/// <param name="scalar">The scalar value to add</param>
/// <returns>A new instance of <see cref="MutableSpan{T}"/></returns>
public static MutableSpan<float> AddScalarToAllValues(this MutableSpan<float> src, float scalar)
/// <returns>A new instance of <see cref="Span{T}"/></returns>
public static Span<float> AddScalarToAllValues(this Span<float> src, float scalar)
{
MutableSpan<float> result = new MutableSpan<float>(src.TotalCount);
for (int i = 0; i < src.TotalCount; i++)
float[] result = new float[src.Length];
for (int i = 0; i < src.Length; i++)
{
result[i] = src[i] + scalar;
}
@ -130,11 +123,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
/// </summary>
/// <param name="src">The source</param>
/// <param name="scalar">The scalar value to add</param>
/// <returns>A new instance of <see cref="MutableSpan{T}"/></returns>
public static MutableSpan<int> AddScalarToAllValues(this MutableSpan<int> src, int scalar)
/// <returns>A new instance of <see cref="Span{T}"/></returns>
public static Span<int> AddScalarToAllValues(this Span<int> src, int scalar)
{
MutableSpan<int> result = new MutableSpan<int>(src.TotalCount);
for (int i = 0; i < src.TotalCount; i++)
int[] result = new int[src.Length];
for (int i = 0; i < src.Length; i++)
{
result[i] = src[i] + scalar;
}
@ -143,15 +136,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils
}
/// <summary>
/// Copy all values in src to a new <see cref="MutableSpan{T}"/> instance
/// Copy all values in src to a new <see cref="Span{T}"/> instance
/// </summary>
/// <typeparam name="T">Element type</typeparam>
/// <param name="src">The source</param>
/// <returns>A new instance of <see cref="MutableSpan{T}"/></returns>
public static MutableSpan<T> Copy<T>(this MutableSpan<T> src)
/// <returns>A new instance of <see cref="Span{T}"/></returns>
public static Span<T> Copy<T>(this Span<T> src)
{
MutableSpan<T> result = new MutableSpan<T>(src.TotalCount);
for (int i = 0; i < src.TotalCount; i++)
T[] result = new T[src.Length];
for (int i = 0; i < src.Length; i++)
{
result[i] = src[i];
}

46
tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs

@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests
Assert.Equal(data, mirror);
// PrintLinearData((MutableSpan<float>)mirror);
// PrintLinearData((Span<float>)mirror);
}
[Fact]
@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Tests
Assert.Equal(data, mirror);
// PrintLinearData((MutableSpan<float>)mirror);
// PrintLinearData((Span<float>)mirror);
}
[Fact]
@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Tests
Assert.Equal(data, mirror);
// PrintLinearData((MutableSpan<int>)mirror);
// PrintLinearData((Span<int>)mirror);
}
[Fact]
@ -251,10 +251,10 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void iDCT2D8x4_RightPart()
{
MutableSpan<float> sourceArray = Create8x8FloatData();
MutableSpan<float> expectedDestArray = new float[64];
float[] sourceArray = Create8x8FloatData();
float[] expectedDestArray = new float[64];
ReferenceImplementations.iDCT2D8x4_32f(sourceArray.Slice(4), expectedDestArray.Slice(4));
ReferenceImplementations.iDCT2D8x4_32f(sourceArray.AsSpan().Slice(4), expectedDestArray.AsSpan().Slice(4));
Block8x8F source = new Block8x8F();
source.LoadFrom(sourceArray);
@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp.Tests
this.Output.WriteLine("**************");
this.Print8x8Data(actualDestArray);
Assert.Equal(expectedDestArray.Data, actualDestArray);
Assert.Equal(expectedDestArray, actualDestArray);
}
[Theory]
@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.Tests
[InlineData(3)]
public void TransformIDCT(int seed)
{
MutableSpan<float> sourceArray = Create8x8RandomFloatData(-200, 200, seed);
Span<float> sourceArray = Create8x8RandomFloatData(-200, 200, seed);
float[] expectedDestArray = new float[64];
float[] tempArray = new float[64];
@ -321,7 +321,7 @@ namespace SixLabors.ImageSharp.Tests
Block8x8F temp = new Block8x8F();
ReferenceImplementations.CopyColorsTo(ref block, new MutableSpan<byte>(colorsExpected, offset), stride);
ReferenceImplementations.CopyColorsTo(ref block, new Span<byte>(colorsExpected, offset), stride);
block.CopyColorsTo(new Span<byte>(colorsActual, offset), stride, &temp);
@ -372,21 +372,21 @@ namespace SixLabors.ImageSharp.Tests
[InlineData(2)]
public void FDCT8x4_LeftPart(int seed)
{
MutableSpan<float> src = Create8x8RandomFloatData(-200, 200, seed);
Span<float> src = Create8x8RandomFloatData(-200, 200, seed);
Block8x8F srcBlock = new Block8x8F();
srcBlock.LoadFrom(src);
Block8x8F destBlock = new Block8x8F();
MutableSpan<float> expectedDest = new MutableSpan<float>(64);
float[] expectedDest = new float[64];
ReferenceImplementations.fDCT2D8x4_32f(src, expectedDest);
DCT.FDCT8x4_LeftPart(ref srcBlock, ref destBlock);
MutableSpan<float> actualDest = new MutableSpan<float>(64);
float[] actualDest = new float[64];
destBlock.CopyTo(actualDest);
Assert.Equal(actualDest.Data, expectedDest.Data, new ApproximateFloatComparer(1f));
Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
}
[Theory]
@ -394,21 +394,21 @@ namespace SixLabors.ImageSharp.Tests
[InlineData(2)]
public void FDCT8x4_RightPart(int seed)
{
MutableSpan<float> src = Create8x8RandomFloatData(-200, 200, seed);
Span<float> src = Create8x8RandomFloatData(-200, 200, seed);
Block8x8F srcBlock = new Block8x8F();
srcBlock.LoadFrom(src);
Block8x8F destBlock = new Block8x8F();
MutableSpan<float> expectedDest = new MutableSpan<float>(64);
float[] expectedDest = new float[64];
ReferenceImplementations.fDCT2D8x4_32f(src.Slice(4), expectedDest.Slice(4));
ReferenceImplementations.fDCT2D8x4_32f(src.Slice(4), expectedDest.AsSpan().Slice(4));
DCT.FDCT8x4_RightPart(ref srcBlock, ref destBlock);
MutableSpan<float> actualDest = new MutableSpan<float>(64);
float[] actualDest = new float[64];
destBlock.CopyTo(actualDest);
Assert.Equal(actualDest.Data, expectedDest.Data, new ApproximateFloatComparer(1f));
Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
}
[Theory]
@ -416,23 +416,23 @@ namespace SixLabors.ImageSharp.Tests
[InlineData(2)]
public void TransformFDCT(int seed)
{
MutableSpan<float> src = Create8x8RandomFloatData(-200, 200, seed);
Span<float> src = Create8x8RandomFloatData(-200, 200, seed);
Block8x8F srcBlock = new Block8x8F();
srcBlock.LoadFrom(src);
Block8x8F destBlock = new Block8x8F();
MutableSpan<float> expectedDest = new MutableSpan<float>(64);
MutableSpan<float> temp1 = new MutableSpan<float>(64);
float[] expectedDest = new float[64];
float[] temp1 = new float[64];
Block8x8F temp2 = new Block8x8F();
ReferenceImplementations.fDCT2D_llm(src, expectedDest, temp1, downscaleBy8: true);
DCT.TransformFDCT(ref srcBlock, ref destBlock, ref temp2, false);
MutableSpan<float> actualDest = new MutableSpan<float>(64);
float[] actualDest = new float[64];
destBlock.CopyTo(actualDest);
Assert.Equal(actualDest.Data, expectedDest.Data, new ApproximateFloatComparer(1f));
Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f));
}
[Theory]

14
tests/ImageSharp.Tests/Formats/Jpg/JpegUtilityTestFixture.cs

@ -60,12 +60,12 @@ namespace SixLabors.ImageSharp.Tests
return result;
}
internal static MutableSpan<float> Create8x8RandomFloatData(int minValue, int maxValue, int seed = 42)
=> new MutableSpan<int>(Create8x8RandomIntData(minValue, maxValue, seed)).ConvertToFloat32MutableSpan();
internal static float[] Create8x8RandomFloatData(int minValue, int maxValue, int seed = 42)
=> Create8x8RandomIntData(minValue, maxValue, seed).ConvertAllToFloat();
internal void Print8x8Data<T>(MutableSpan<T> data) => this.Print8x8Data(data.Data);
internal void Print8x8Data<T>(T[] data) => this.Print8x8Data(new Span<T>(data));
internal void Print8x8Data<T>(T[] data)
internal void Print8x8Data<T>(Span<T> data)
{
StringBuilder bld = new StringBuilder();
for (int i = 0; i < 8; i++)
@ -80,11 +80,11 @@ namespace SixLabors.ImageSharp.Tests
this.Output.WriteLine(bld.ToString());
}
internal void PrintLinearData<T>(T[] data) => this.PrintLinearData(new MutableSpan<T>(data), data.Length);
internal void PrintLinearData<T>(T[] data) => this.PrintLinearData(new Span<T>(data), data.Length);
internal void PrintLinearData<T>(MutableSpan<T> data, int count = -1)
internal void PrintLinearData<T>(Span<T> data, int count = -1)
{
if (count < 0) count = data.TotalCount;
if (count < 0) count = data.Length;
StringBuilder bld = new StringBuilder();
for (int i = 0; i < count; i++)

66
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementations.cs

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests
/// Transpose 8x8 block stored linearly in a <see cref="MutableSpan{T}"/> (inplace)
/// </summary>
/// <param name="data"></param>
internal static void Transpose8x8(MutableSpan<float> data)
internal static void Transpose8x8(Span<float> data)
{
for (int i = 1; i < 8; i++)
{
@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests
/// <summary>
/// Transpose 8x8 block stored linearly in a <see cref="MutableSpan{T}"/>
/// </summary>
internal static void Transpose8x8(MutableSpan<float> src, MutableSpan<float> dest)
internal static void Transpose8x8(Span<float> src, Span<float> dest)
{
for (int i = 0; i < 8; i++)
{
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests
/// Leave results scaled up by an overall factor of 8.
/// </summary>
/// <param name="block">The block of coefficients.</param>
public static void TransformFDCTInplace(MutableSpan<int> block)
public static void TransformFDCTInplace(Span<int> block)
{
// Pass 1: process rows.
for (int y = 0; y < 8; y++)
@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.Tests
/// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984.
/// </summary>
/// <param name="src">The source block of coefficients</param>
public static void TransformIDCTInplace(MutableSpan<int> src)
public static void TransformIDCTInplace(Span<int> src)
{
// Horizontal 1-D IDCT.
for (int y = 0; y < 8; y++)
@ -364,7 +364,7 @@ namespace SixLabors.ImageSharp.Tests
/// </summary>
/// <param name="y"></param>
/// <param name="x"></param>
private static void iDCT1Dllm_32f(MutableSpan<float> y, MutableSpan<float> x)
private 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;
@ -421,7 +421,7 @@ namespace SixLabors.ImageSharp.Tests
/// <param name="s"></param>
/// <param name="d"></param>
/// <param name="temp"></param>
internal static void iDCT2D_llm(MutableSpan<float> s, MutableSpan<float> d, MutableSpan<float> temp)
internal static void iDCT2D_llm(Span<float> s, Span<float> d, Span<float> temp)
{
int j;
@ -453,7 +453,7 @@ namespace SixLabors.ImageSharp.Tests
/// </summary>
/// <param name="s">Source</param>
/// <param name="d">Destination</param>
public static void fDCT2D8x4_32f(MutableSpan<float> s, MutableSpan<float> d)
public static void fDCT2D8x4_32f(Span<float> s, Span<float> d)
{
Vector4 c0 = _mm_load_ps(s, 0);
Vector4 c1 = _mm_load_ps(s, 56);
@ -550,7 +550,7 @@ namespace SixLabors.ImageSharp.Tests
}*/
}
public static void fDCT8x8_llm_sse(MutableSpan<float> s, MutableSpan<float> d, MutableSpan<float> temp)
public static void fDCT8x8_llm_sse(Span<float> s, Span<float> d, Span<float> temp)
{
Transpose8x8(s, temp);
@ -566,33 +566,33 @@ namespace SixLabors.ImageSharp.Tests
Vector4 c = new Vector4(0.1250f);
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//0
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//1
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//2
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//3
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//4
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//5
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//6
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//7
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//8
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//9
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//10
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//11
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//12
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//13
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//14
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d.AddOffset(4);//15
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//0
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//1
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//2
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//3
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//4
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//5
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//6
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//7
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//8
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//9
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//10
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//11
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//12
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//13
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//14
_mm_store_ps(d, 0, (_mm_load_ps(d, 0) * c)); d = d.Slice(4);//15
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector4 _mm_load_ps(MutableSpan<float> src, int offset)
private static Vector4 _mm_load_ps(Span<float> src, int offset)
{
src = src.Slice(offset);
return new Vector4(src[0], src[1], src[2], src[3]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void _mm_store_ps(MutableSpan<float> dest, int offset, Vector4 src)
private static void _mm_store_ps(Span<float> dest, int offset, Vector4 src)
{
dest = dest.Slice(offset);
dest[0] = src.X;
@ -632,7 +632,7 @@ namespace SixLabors.ImageSharp.Tests
/// </summary>
/// <param name="y"></param>
/// <param name="x"></param>
internal static void iDCT2D8x4_32f(MutableSpan<float> y, MutableSpan<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;
@ -750,7 +750,7 @@ namespace SixLabors.ImageSharp.Tests
/// <param name="block"></param>
/// <param name="buffer"></param>
/// <param name="stride"></param>
internal static unsafe void CopyColorsTo(ref Block8x8F block, MutableSpan<byte> buffer, int stride)
internal static unsafe void CopyColorsTo(ref Block8x8F block, Span<byte> buffer, int stride)
{
fixed (Block8x8F* p = &block)
{
@ -784,7 +784,7 @@ namespace SixLabors.ImageSharp.Tests
}
}
internal static void fDCT1Dllm_32f(MutableSpan<float> x, MutableSpan<float> y)
internal static void fDCT1Dllm_32f(Span<float> x, Span<float> y)
{
float t0, t1, t2, t3, t4, t5, t6, t7;
float c0, c1, c2, c3;
@ -844,13 +844,13 @@ namespace SixLabors.ImageSharp.Tests
}
internal static void fDCT2D_llm(
MutableSpan<float> s,
MutableSpan<float> d,
MutableSpan<float> temp,
Span<float> s,
Span<float> d,
Span<float> temp,
bool downscaleBy8 = false,
bool offsetSourceByNeg128 = false)
{
MutableSpan<float> sWorker = offsetSourceByNeg128 ? s.AddScalarToAllValues(-128f) : s;
Span<float> sWorker = offsetSourceByNeg128 ? s.AddScalarToAllValues(-128f) : s;
for (int j = 0; j < 8; j++)
{

28
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs

@ -9,6 +9,8 @@ using Xunit.Abstractions;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using System;
public class ReferenceImplementationsTests : JpegUtilityTestFixture
{
public ReferenceImplementationsTests(ITestOutputHelper output)
@ -23,13 +25,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(2)]
public void Idct_FloatingPointReferenceImplementation_IsEquivalentToIntegerImplementation(int seed)
{
MutableSpan<int> intData = Create8x8RandomIntData(-200, 200, seed);
MutableSpan<float> floatSrc = intData.ConvertToFloat32MutableSpan();
int[] intData = Create8x8RandomIntData(-200, 200, seed);
Span<float> floatSrc = intData.ConvertAllToFloat();
ReferenceImplementations.IntegerReferenceDCT.TransformIDCTInplace(intData);
MutableSpan<float> dest = new MutableSpan<float>(64);
MutableSpan<float> temp = new MutableSpan<float>(64);
float[] dest = new float[64];
float[] temp = new float[64];
ReferenceImplementations.iDCT2D_llm(floatSrc, dest, temp);
@ -48,9 +50,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(2, 0)]
public void IntegerDCT_ForwardThenInverse(int seed, int startAt)
{
MutableSpan<int> original = Create8x8RandomIntData(-200, 200, seed);
Span<int> original = Create8x8RandomIntData(-200, 200, seed);
MutableSpan<int> block = original.AddScalarToAllValues(128);
Span<int> block = original.AddScalarToAllValues(128);
ReferenceImplementations.IntegerReferenceDCT.TransformFDCTInplace(block);
@ -78,9 +80,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void FloatingPointDCT_ReferenceImplementation_ForwardThenInverse(int seed, int startAt)
{
int[] data = Create8x8RandomIntData(-200, 200, seed);
MutableSpan<float> src = new MutableSpan<int>(data).ConvertToFloat32MutableSpan();
MutableSpan<float> dest = new MutableSpan<float>(64);
MutableSpan<float> temp = new MutableSpan<float>(64);
float[] src = data.ConvertAllToFloat();
float[] dest = new float[64];
float[] temp = new float[64];
ReferenceImplementations.fDCT2D_llm(src, dest, temp, true);
ReferenceImplementations.iDCT2D_llm(dest, src, temp);
@ -100,13 +102,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(2)]
public void Fdct_FloatingPointReferenceImplementation_IsEquivalentToIntegerImplementation(int seed)
{
MutableSpan<int> intData = Create8x8RandomIntData(-200, 200, seed);
MutableSpan<float> floatSrc = intData.ConvertToFloat32MutableSpan();
int[] intData = Create8x8RandomIntData(-200, 200, seed);
float[] floatSrc = intData.ConvertAllToFloat();
ReferenceImplementations.IntegerReferenceDCT.TransformFDCTInplace(intData);
MutableSpan<float> dest = new MutableSpan<float>(64);
MutableSpan<float> temp = new MutableSpan<float>(64);
float[] dest = new float[64];
float[] temp = new float[64];
ReferenceImplementations.fDCT2D_llm(floatSrc, dest, temp, offsetSourceByNeg128: true);

Loading…
Cancel
Save