Browse Source

optimization: removed temporal buffer creation from ToVector4SimdAligned()

af/merge-core
Anton Firszov 9 years ago
parent
commit
d5e58192c8
  1. 14
      src/ImageSharp/Common/Memory/BufferSpan.cs
  2. 43
      src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs
  3. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
  4. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  5. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  6. 4
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
  7. 18
      tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs
  8. 12
      tests/ImageSharp.Tests/Colors/PixelOperationsTests.cs
  9. 16
      tests/ImageSharp.Tests/Common/BufferSpanTests.cs

14
src/ImageSharp/Common/Memory/BufferSpan.cs

@ -6,6 +6,7 @@
namespace ImageSharp
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -14,6 +15,19 @@ namespace ImageSharp
/// </summary>
internal static class BufferSpan
{
/// <summary>
/// Fetches a <see cref="Vector{T}"/> from the beginning of the span.
/// </summary>
/// <typeparam name="T">The value type</typeparam>
/// <param name="span">The span to fetch the vector from</param>
/// <returns>A <see cref="Vector{T}"/> reference to the beginning of the span</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref Vector<T> FetchVector<T>(this BufferSpan<T> span)
where T : struct
{
return ref Unsafe.As<T, Vector<T>>(ref span.DangerousGetPinnableReference());
}
/// <summary>
/// Copy 'count' number of elements of the same type from 'source' to 'dest'
/// </summary>

43
src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs

@ -61,38 +61,33 @@ namespace ImageSharp
int unpackedRawCount = count * 4;
ref uint src = ref Unsafe.As<Rgba32, uint>(ref sourceColors.DangerousGetPinnableReference());
ref uint bSource = ref Unsafe.As<Rgba32, uint>(ref sourceColors.DangerousGetPinnableReference());
ref UnpackedRGBA bDestUnpacked = ref Unsafe.As<Vector4, UnpackedRGBA>(ref destVectors.DangerousGetPinnableReference());
ref Vector<uint> bDestUint = ref Unsafe.As<UnpackedRGBA, Vector<uint>>(ref bDestUnpacked);
ref Vector<float> bDestFloat = ref Unsafe.As<UnpackedRGBA, Vector<float>>(ref bDestUnpacked);
using (Buffer<uint> tempBuf = new Buffer<uint>(
unpackedRawCount + Vector<uint>.Count))
for (int i = 0; i < count; i++)
{
uint[] temp = tempBuf.Array;
float[] fTemp = Unsafe.As<float[]>(temp);
ref UnpackedRGBA tempBase = ref Unsafe.As<uint, UnpackedRGBA>(ref tempBuf[0]);
uint sVal = Unsafe.Add(ref bSource, i);
ref UnpackedRGBA dst = ref Unsafe.Add(ref bDestUnpacked, i);
for (int i = 0; i < count; i++)
{
uint sVal = Unsafe.Add(ref src, i);
ref UnpackedRGBA dst = ref Unsafe.Add(ref tempBase, i);
// This call is the bottleneck now:
dst.Load(sVal);
}
// This call is the bottleneck now:
dst.Load(sVal);
}
int n = unpackedRawCount / vecSize;
for (int i = 0; i < unpackedRawCount; i += vecSize)
{
Vector<uint> vi = new Vector<uint>(temp, i);
for (int i = 0; i < n; i++)
{
Vector<uint> vi = Unsafe.Add(ref bDestUint, i);
vi &= mask;
vi |= magicInt;
vi &= mask;
vi |= magicInt;
Vector<float> vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
vf.CopyTo(fTemp, i);
}
Vector<float> vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
BufferSpan.Copy(tempBuf.Span.AsBytes(), destVectors.AsBytes(), unpackedRawCount * sizeof(uint));
Unsafe.Add(ref bDestFloat, i) = vf;
}
}

2
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs

@ -57,7 +57,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk
}
}
public class PackFromXyzw_Color : PackFromXyzw<Rgba32>
public class PackFromXyzw_Rgba32 : PackFromXyzw<Rgba32>
{
}
}

2
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs

@ -57,7 +57,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk
}
}
public class ToVector4_Color : ToVector4<Rgba32>
public class ToVector4_Rgba32 : ToVector4<Rgba32>
{
}
}

2
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs

@ -55,7 +55,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk
}
}
public class ToXyz_Color : ToXyz<Rgba32>
public class ToXyz_Rgba32 : ToXyz<Rgba32>
{
}
}

4
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs

@ -59,11 +59,11 @@ namespace ImageSharp.Benchmarks.Color.Bulk
}
}
public class ToXyzw_Color : ToXyzw<Rgba32>
public class ToXyzw_Rgba32 : ToXyzw<Rgba32>
{
}
public class ToXyzw_Argb : ToXyzw<Argb32>
public class ToXyzw_Argb32 : ToXyzw<Argb32>
{
}
}

18
tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs

@ -86,5 +86,23 @@ namespace ImageSharp.Benchmarks.General.Vectorization
a = a * v;
}
}
[Benchmark]
public void FetchWithBufferSpanUtility()
{
Vector<float> v = new Vector<float>(this.testValue);
BufferSpan<float> span = new BufferSpan<float>(this.data);
ref Vector<float> start = ref span.FetchVector();
int n = this.InputSize / Vector<uint>.Count;
for (int i = 0; i < n; i++)
{
ref Vector<float> a = ref Unsafe.Add(ref start, i);
a = a * v;
}
}
}
}

12
tests/ImageSharp.Tests/Colors/PixelOperationsTests.cs

@ -12,7 +12,7 @@ namespace ImageSharp.Tests.Colors
public class PixelOperationsTests
{
public class Color32 : BulkPixelOperationsTests<Rgba32>
public class Color32 : PixelOperationsTests<Rgba32>
{
public Color32(ITestOutputHelper output)
: base(output)
@ -20,7 +20,7 @@ namespace ImageSharp.Tests.Colors
}
// For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class:
//public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
[Fact]
public void IsSpecialImplementation()
@ -60,7 +60,7 @@ namespace ImageSharp.Tests.Colors
}
}
public class Argb : BulkPixelOperationsTests<Argb32>
public class Argb : PixelOperationsTests<Argb32>
{
// For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class:
public Argb(ITestOutputHelper output)
@ -68,7 +68,7 @@ namespace ImageSharp.Tests.Colors
{
}
//public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
}
[Theory]
@ -80,10 +80,10 @@ namespace ImageSharp.Tests.Colors
}
}
public abstract class BulkPixelOperationsTests<TPixel> : MeasureFixture
public abstract class PixelOperationsTests<TPixel> : MeasureFixture
where TPixel : struct, IPixel<TPixel>
{
protected BulkPixelOperationsTests(ITestOutputHelper output)
protected PixelOperationsTests(ITestOutputHelper output)
: base(output)
{
}

16
tests/ImageSharp.Tests/Common/BufferSpanTests.cs

@ -4,6 +4,7 @@
namespace ImageSharp.Tests.Common
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using ImageSharp.PixelFormats;
@ -25,6 +26,21 @@ namespace ImageSharp.Tests.Common
}
}
[Fact]
public void FetchVector()
{
float[] stuff = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
BufferSpan<float> span = new BufferSpan<float>(stuff);
ref Vector<float> v = ref span.FetchVector();
Assert.Equal(0, v[0]);
Assert.Equal(1, v[1]);
Assert.Equal(2, v[2]);
Assert.Equal(3, v[3]);
}
[Fact]
public void AsBytes()
{

Loading…
Cancel
Save