Browse Source

optimization: removed temporal buffer creation from ToVector4SimdAligned()

pull/210/head
Anton Firszov 9 years ago
parent
commit
67bc1f7ab9
  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 namespace ImageSharp
{ {
using System; using System;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -14,6 +15,19 @@ namespace ImageSharp
/// </summary> /// </summary>
internal static class BufferSpan 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> /// <summary>
/// Copy 'count' number of elements of the same type from 'source' to 'dest' /// Copy 'count' number of elements of the same type from 'source' to 'dest'
/// </summary> /// </summary>

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

@ -61,38 +61,33 @@ namespace ImageSharp
int unpackedRawCount = count * 4; 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>( for (int i = 0; i < count; i++)
unpackedRawCount + Vector<uint>.Count))
{ {
uint[] temp = tempBuf.Array; uint sVal = Unsafe.Add(ref bSource, i);
float[] fTemp = Unsafe.As<float[]>(temp); ref UnpackedRGBA dst = ref Unsafe.Add(ref bDestUnpacked, i);
ref UnpackedRGBA tempBase = ref Unsafe.As<uint, UnpackedRGBA>(ref tempBuf[0]);
for (int i = 0; i < count; i++) // This call is the bottleneck now:
{ dst.Load(sVal);
uint sVal = Unsafe.Add(ref src, i); }
ref UnpackedRGBA dst = ref Unsafe.Add(ref tempBase, i);
// This call is the bottleneck now: int n = unpackedRawCount / vecSize;
dst.Load(sVal);
}
for (int i = 0; i < unpackedRawCount; i += vecSize) for (int i = 0; i < n; i++)
{ {
Vector<uint> vi = new Vector<uint>(temp, i); Vector<uint> vi = Unsafe.Add(ref bDestUint, i);
vi &= mask; vi &= mask;
vi |= magicInt; vi |= magicInt;
Vector<float> vf = Vector.AsVectorSingle(vi); Vector<float> vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec; vf = (vf - magicFloat) * bVec;
vf.CopyTo(fTemp, i);
}
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; 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 PixelOperationsTests
{ {
public class Color32 : BulkPixelOperationsTests<Rgba32> public class Color32 : PixelOperationsTests<Rgba32>
{ {
public Color32(ITestOutputHelper output) public Color32(ITestOutputHelper output)
: base(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: // 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] [Fact]
public void IsSpecialImplementation() 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: // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class:
public Argb(ITestOutputHelper output) 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] [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> where TPixel : struct, IPixel<TPixel>
{ {
protected BulkPixelOperationsTests(ITestOutputHelper output) protected PixelOperationsTests(ITestOutputHelper output)
: base(output) : base(output)
{ {
} }

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

@ -4,6 +4,7 @@
namespace ImageSharp.Tests.Common namespace ImageSharp.Tests.Common
{ {
using System; using System;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using ImageSharp.PixelFormats; 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] [Fact]
public void AsBytes() public void AsBytes()
{ {

Loading…
Cancel
Save