diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs
index 154cd531d..5c040e04c 100644
--- a/src/ImageSharp/Colors/Color.BulkOperations.cs
+++ b/src/ImageSharp/Colors/Color.BulkOperations.cs
@@ -32,6 +32,10 @@ namespace ImageSharp
///
/// http://stackoverflow.com/a/5362789
///
+ /// TODO: We can replace this implementation in the future using new Vector API-s:
+ ///
+ /// https://github.com/dotnet/corefx/issues/15957
+ ///
///
internal static unsafe void ToVector4SimdAligned(
BufferPointer sourceColors,
@@ -56,8 +60,7 @@ namespace ImageSharp
uint* srcEnd = src + count;
using (PinnedBuffer tempBuf = new PinnedBuffer(
- unpackedRawCount + Vector.Count,
- PixelDataPool.Dirty))
+ unpackedRawCount + Vector.Count))
{
uint* tPtr = (uint*)tempBuf.Pointer;
uint[] temp = tempBuf.Array;
@@ -66,7 +69,7 @@ namespace ImageSharp
for (; src < srcEnd; src++, dst++)
{
- // TODO: This is the bottleneck now. We can improve it with future Vector API-s (https://github.com/dotnet/corefx/issues/15957)
+ // This call is the bottleneck now:
dst->Load(*src);
}
diff --git a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs
index 4e7a40078..441f6b8ce 100644
--- a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs
+++ b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs
@@ -130,7 +130,14 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear(int count)
{
-
+ if (count < 256)
+ {
+ Unsafe.InitBlock((void*)this.PointerAtOffset, 0, BufferPointer.USizeOf(count));
+ }
+ else
+ {
+ System.Array.Clear(this.Array, this.Offset, count);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs
index 6e0d1fcc6..2d3d44dda 100644
--- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs
+++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs
@@ -24,32 +24,23 @@ namespace ImageSharp
private GCHandle handle;
///
- /// The if the is pooled.
+ /// A value indicating wheter should be returned to
+ /// when disposing this instance.
///
- private PixelDataPool pool;
+ private bool isPoolingOwner;
///
/// Initializes a new instance of the class.
///
/// The desired count of elements. (Minimum size for )
- /// The to be used to rent the data.
- public PinnedBuffer(int count, PixelDataPool pool)
+ public PinnedBuffer(int count)
{
this.Count = count;
- this.pool = pool;
- this.Array = this.pool.Rent(count);
+ this.Array = PixelDataPool.Rent(count);
+ this.isPoolingOwner = true;
this.Pin();
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The desired count of elements. (Minimum size for )
- public PinnedBuffer(int count)
- : this(count, PixelDataPool.Clean)
- {
- }
-
///
/// Initializes a new instance of the class.
///
@@ -58,7 +49,7 @@ namespace ImageSharp
{
this.Count = array.Length;
this.Array = array;
- this.pool = null;
+ this.isPoolingOwner = false;
this.Pin();
}
@@ -76,7 +67,7 @@ namespace ImageSharp
this.Count = count;
this.Array = array;
- this.pool = null;
+ this.isPoolingOwner = false;
this.Pin();
}
@@ -153,8 +144,12 @@ namespace ImageSharp
this.IsDisposedOrLostArrayOwnership = true;
this.UnPin();
- this.pool?.Return(this.Array);
- this.pool = null;
+ if (this.isPoolingOwner)
+ {
+ PixelDataPool.Return(this.Array);
+ }
+
+ this.isPoolingOwner = false;
this.Array = null;
this.Count = 0;
@@ -178,9 +173,19 @@ namespace ImageSharp
this.UnPin();
T[] array = this.Array;
this.Array = null;
+ this.isPoolingOwner = false;
return array;
}
+ ///
+ /// Clears the buffer, filling elements between 0 and -1 with default(T)
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear()
+ {
+ this.Slice().Clear(this.Count);
+ }
+
///
/// Pins .
///
diff --git a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs
index a01a941bc..dcd031f6e 100644
--- a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs
+++ b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs
@@ -15,63 +15,32 @@ namespace ImageSharp
public class PixelDataPool
where T : struct
{
- ///
- /// The which will be always cleared.
- ///
- private static readonly ArrayPool CleanPool = ArrayPool.Create(CalculateMaxArrayLength(), 50);
-
///
/// The which is not kept clean.
///
- private static readonly ArrayPool DirtyPool = ArrayPool.Create(CalculateMaxArrayLength(), 50);
-
- ///
- /// The backing
- ///
- private ArrayPool arrayPool;
-
- ///
- /// A value indicating whether clearArray is requested on .
- ///
- private bool clearArray;
-
- private PixelDataPool(ArrayPool arrayPool, bool clearArray)
- {
- this.clearArray = clearArray;
- this.arrayPool = arrayPool;
- }
-
- ///
- /// Gets the which will always return arrays initialized to default(T)
- ///
- public static PixelDataPool Clean { get; } = new PixelDataPool(CleanPool, true);
-
- ///
- /// Gets the which does not keep the arrays clean on Rent/Return.
- ///
- public static PixelDataPool Dirty { get; } = new PixelDataPool(DirtyPool, false);
+ private static readonly ArrayPool ArrayPool = ArrayPool.Create(CalculateMaxArrayLength(), 50);
///
/// Rents the pixel array from the pool.
///
/// The minimum length of the array to return.
/// The
- public T[] Rent(int minimumLength)
+ public static T[] Rent(int minimumLength)
{
- return CleanPool.Rent(minimumLength);
+ return ArrayPool.Rent(minimumLength);
}
///
/// Returns the rented pixel array back to the pool.
///
/// The array to return to the buffer pool.
- public void Return(T[] array)
+ public static void Return(T[] array)
{
- CleanPool.Return(array, this.clearArray);
+ ArrayPool.Return(array);
}
///
- /// Heuristically calculates a reasonable maxArrayLength value for the backing .
+ /// Heuristically calculates a reasonable maxArrayLength value for the backing .
///
/// The maxArrayLength value
internal static int CalculateMaxArrayLength()
diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs
index 7d7fc843f..7afc27a6d 100644
--- a/src/ImageSharp/Image/ImageBase{TColor}.cs
+++ b/src/ImageSharp/Image/ImageBase{TColor}.cs
@@ -60,6 +60,7 @@ namespace ImageSharp
{
this.Configuration = configuration ?? Configuration.Default;
this.InitPixels(width, height);
+ this.ClearPixels();
}
///
@@ -221,7 +222,7 @@ namespace ImageSharp
///
private void RentPixels()
{
- this.pixelBuffer = PixelDataPool.Clean.Rent(this.Width * this.Height);
+ this.pixelBuffer = PixelDataPool.Rent(this.Width * this.Height);
}
///
@@ -229,8 +230,13 @@ namespace ImageSharp
///
private void ReturnPixels()
{
- PixelDataPool.Clean.Return(this.pixelBuffer);
+ PixelDataPool.Return(this.pixelBuffer);
this.pixelBuffer = null;
}
+
+ private void ClearPixels()
+ {
+ Array.Clear(this.pixelBuffer, 0, this.Width * this.Height);
+ }
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs
index c361fd6a1..467663a53 100644
--- a/tests/ImageSharp.Sandbox46/Program.cs
+++ b/tests/ImageSharp.Sandbox46/Program.cs
@@ -46,7 +46,7 @@ namespace ImageSharp.Sandbox46
private static void RunToVector4ProfilingTest()
{
- BulkPixelOperationsTests.Color tests = new BulkPixelOperationsTests.Color();
+ BulkPixelOperationsTests.Color tests = new BulkPixelOperationsTests.Color(new ConsoleOutput());
tests.Benchmark_ToVector4();
}
diff --git a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs
index 39d76d937..c82b63f11 100644
--- a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs
+++ b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs
@@ -146,6 +146,11 @@ namespace ImageSharp.Tests.Common
// Act:
ap.Clear(count);
+
+ Assert.NotEqual(default(Foo), array[offset-1]);
+ Assert.Equal(default(Foo), array[offset]);
+ Assert.Equal(default(Foo), array[offset + count-1]);
+ Assert.NotEqual(default(Foo), array[offset + count]);
}
}
diff --git a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs
index 65077ae7f..3688763b9 100644
--- a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs
+++ b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs
@@ -47,6 +47,21 @@
}
}
+ [Theory]
+ [InlineData(42)]
+ [InlineData(1111)]
+ public void Clear(int count)
+ {
+ Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } };
+ using (PinnedBuffer buffer = new PinnedBuffer(a))
+ {
+ buffer.Clear();
+
+ Assert.Equal(default(Foo), a[0]);
+ Assert.Equal(default(Foo), a[1]);
+ }
+ }
+
[Fact]
public void Dispose()
{
diff --git a/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs
index db560ba6b..ea747af7d 100644
--- a/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs
+++ b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs
@@ -15,17 +15,10 @@ namespace ImageSharp.Tests
///
public class PixelDataPoolTests
{
- private static PixelDataPool GetPool(bool clean)
- {
- return clean ? PixelDataPool.Clean : PixelDataPool.Dirty;
- }
-
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public void PixelDataPoolRentsMinimumSize(bool clean)
+ [Fact]
+ public void PixelDataPoolRentsMinimumSize()
{
- Color[] pixels = GetPool(clean).Rent(1024);
+ Color[] pixels = PixelDataPool.Rent(1024);
Assert.True(pixels.Length >= 1024);
}
@@ -35,31 +28,29 @@ namespace ImageSharp.Tests
{
for (int i = 16; i < 1024; i += 16)
{
- Color[] pixels = PixelDataPool.Clean.Rent(i);
+ Color[] pixels = PixelDataPool.Rent(i);
Assert.True(pixels.All(p => p == default(Color)));
- PixelDataPool.Clean.Return(pixels);
+ PixelDataPool.Return(pixels);
}
for (int i = 16; i < 1024; i += 16)
{
- Color[] pixels = PixelDataPool.Clean.Rent(i);
+ Color[] pixels = PixelDataPool.Rent(i);
Assert.True(pixels.All(p => p == default(Color)));
- PixelDataPool.Clean.Return(pixels);
+ PixelDataPool.Return(pixels);
}
}
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public void PixelDataPoolDoesNotThrowWhenReturningNonPooled(bool clean)
+ [Fact]
+ public void PixelDataPoolDoesNotThrowWhenReturningNonPooled()
{
Color[] pixels = new Color[1024];
- GetPool(clean).Return(pixels);
+ PixelDataPool.Return(pixels);
Assert.True(pixels.Length >= 1024);
}
@@ -67,7 +58,7 @@ namespace ImageSharp.Tests
[Fact]
public void PixelDataPool_Clean_CleansRentedArray()
{
- Color[] pixels = PixelDataPool.Clean.Rent(256);
+ Color[] pixels = PixelDataPool.Rent(256);
for (int i = 0; i < pixels.Length; i++)
{
@@ -76,7 +67,7 @@ namespace ImageSharp.Tests
Assert.True(pixels.All(p => p == Color.Azure));
- PixelDataPool.Clean.Return(pixels);
+ PixelDataPool.Return(pixels);
Assert.True(pixels.All(p => p == default(Color)));
}
@@ -95,7 +86,7 @@ namespace ImageSharp.Tests
[Fact]
public void RentNonIPixelData()
{
- byte[] data = PixelDataPool.Clean.Rent(16384);
+ byte[] data = PixelDataPool.Rent(16384);
Assert.True(data.Length >= 16384);
}