diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index e527c90c0..6b18aaa8f 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Memory /// The buffer to wrap /// The number of elements in a row /// The number of rows - public Buffer2D(Buffer wrappedBuffer, int width, int height) + public Buffer2D(IBuffer wrappedBuffer, int width, int height) { this.Buffer = wrappedBuffer; this.Width = width; @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Memory public Span Span => this.Buffer.Span; - public Buffer Buffer { get; } + public IBuffer Buffer { get; } /// /// Gets a reference to the element at the specified position. diff --git a/src/ImageSharp/Memory/Buffer{T}.cs b/src/ImageSharp/Memory/Buffer{T}.cs index 1ee1571c8..55eb44820 100644 --- a/src/ImageSharp/Memory/Buffer{T}.cs +++ b/src/ImageSharp/Memory/Buffer{T}.cs @@ -18,16 +18,6 @@ namespace SixLabors.ImageSharp.Memory { private MemoryManager memoryManager; - /// - /// A pointer to the first element of when pinned. - /// - private IntPtr pointer; - - /// - /// A handle that allows to access the managed as an unmanaged memory by pinning. - /// - private GCHandle handle; - // why is there such a rule? :S Protected should be fine for a field! #pragma warning disable SA1401 // Fields should be private /// @@ -36,22 +26,7 @@ namespace SixLabors.ImageSharp.Memory protected T[] array; #pragma warning restore SA1401 // Fields should be private - /// - /// Initializes a new instance of the class. - /// - /// The array to pin. - public Buffer(T[] array) - { - this.Length = array.Length; - this.array = array; - } - - /// - /// Initializes a new instance of the class. - /// - /// The array to pin. - /// The count of "relevant" elements in 'array'. - public Buffer(T[] array, int length) + internal Buffer(T[] array, int length, MemoryManager memoryManager) { if (array.Length < length) { @@ -60,22 +35,9 @@ namespace SixLabors.ImageSharp.Memory this.Length = length; this.array = array; - } - - internal Buffer(T[] array, int length, MemoryManager memoryManager) - : this(array, length) - { this.memoryManager = memoryManager; } - /// - /// Finalizes an instance of the class. - /// - ~Buffer() - { - this.UnPin(); - } - /// /// Gets a value indicating whether this instance is disposed, or has lost ownership of . /// @@ -140,7 +102,6 @@ namespace SixLabors.ImageSharp.Memory } this.IsDisposedOrLostArrayOwnership = true; - this.UnPin(); this.memoryManager?.Release(this); @@ -166,33 +127,10 @@ namespace SixLabors.ImageSharp.Memory } this.IsDisposedOrLostArrayOwnership = true; - this.UnPin(); - T[] array = this.array; + T[] a = this.array; this.array = null; this.memoryManager = null; - return array; - } - - /// - /// Pins . - /// - /// The pinned pointer - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public IntPtr Pin() - { - if (this.IsDisposedOrLostArrayOwnership) - { - throw new InvalidOperationException( - "Pin() is invalid on a buffer with IsDisposedOrLostArrayOwnership == true!"); - } - - if (this.pointer == IntPtr.Zero) - { - this.handle = GCHandle.Alloc(this.array, GCHandleType.Pinned); - this.pointer = this.handle.AddrOfPinnedObject(); - } - - return this.pointer; + return a; } /// @@ -202,20 +140,5 @@ namespace SixLabors.ImageSharp.Memory { return this.array; } - - /// - /// Unpins . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void UnPin() - { - if (this.pointer == IntPtr.Zero || !this.handle.IsAllocated) - { - return; - } - - this.handle.Free(); - this.pointer = IntPtr.Zero; - } } } \ No newline at end of file diff --git a/src/ImageSharp/Memory/SimpleManagedMemoryManager.cs b/src/ImageSharp/Memory/SimpleManagedMemoryManager.cs index 12d8582c7..ac4098c71 100644 --- a/src/ImageSharp/Memory/SimpleManagedMemoryManager.cs +++ b/src/ImageSharp/Memory/SimpleManagedMemoryManager.cs @@ -8,7 +8,7 @@ /// internal override Buffer Allocate(int length, bool clear) { - return new Buffer(new T[length], length); + return new Buffer(new T[length], length, this); } internal override IManagedByteBuffer AllocateManagedByteBuffer(int length, bool clear) diff --git a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs b/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs index 1ee61a9a6..399b3db84 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// /// The buffer containing the weights values. /// - private readonly Buffer buffer; + private readonly IBuffer buffer; /// /// Initializes a new instance of the struct. @@ -57,7 +57,8 @@ namespace SixLabors.ImageSharp.Processing.Processors [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref float GetStartReference() { - return ref this.buffer[this.flatStartIndex]; + Span span = this.buffer.Span; + return ref span[this.flatStartIndex]; } /// diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs deleted file mode 100644 index 8925fe903..000000000 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs +++ /dev/null @@ -1,77 +0,0 @@ -namespace SixLabors.ImageSharp.Benchmarks -{ - using System.Numerics; - using System.Runtime.CompilerServices; - - using BenchmarkDotNet.Attributes; - - using SixLabors.ImageSharp; - using SixLabors.ImageSharp.Memory; - - /// - /// Compares two implementation candidates for general BulkPixelOperations.ToVector4(): - /// - One iterating with pointers - /// - One iterating with ref locals - /// - public unsafe class PackFromVector4ReferenceVsPointer - { - private Buffer destination; - - private Buffer source; - - [Params(16, 128, 1024)] - public int Count { get; set; } - - [GlobalSetup] - public void Setup() - { - this.destination = Configuration.Default.MemoryManager.Allocate(this.Count); - this.source = Configuration.Default.MemoryManager.Allocate(this.Count * 4); - this.source.Pin(); - this.destination.Pin(); - } - - [GlobalCleanup] - public void Cleanup() - { - this.source.Dispose(); - this.destination.Dispose(); - } - - [Benchmark(Baseline = true)] - public void PackUsingPointers() - { - Vector4* sp = (Vector4*)this.source.Pin(); - byte* dp = (byte*)this.destination.Pin(); - int count = this.Count; - int size = sizeof(Rgba32); - - for (int i = 0; i < count; i++) - { - Vector4 v = Unsafe.Read(sp); - Rgba32 c = default(Rgba32); - c.PackFromVector4(v); - Unsafe.Write(dp, c); - - sp++; - dp += size; - } - } - - [Benchmark] - public void PackUsingReferences() - { - ref Vector4 sp = ref this.source.DangerousGetPinnableReference(); - ref Rgba32 dp = ref this.destination.DangerousGetPinnableReference(); - int count = this.Count; - - for (int i = 0; i < count; i++) - { - dp.PackFromVector4(sp); - - sp = Unsafe.Add(ref sp, 1); - dp = Unsafe.Add(ref dp, 1); - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/IterateArray.cs b/tests/ImageSharp.Benchmarks/General/IterateArray.cs deleted file mode 100644 index e06d71f4a..000000000 --- a/tests/ImageSharp.Benchmarks/General/IterateArray.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Numerics; - using System.Runtime.CompilerServices; - - using BenchmarkDotNet.Attributes; - - using SixLabors.ImageSharp.Memory; - - public class IterateArray - { - // Usual pinned stuff - private Buffer buffer; - - // An array that's not pinned by intent! - private Vector4[] array; - - [Params(64, 1024)] - public int Length { get; set; } - - [GlobalSetup] - public void Setup() - { - this.buffer = Configuration.Default.MemoryManager.Allocate(this.Length); - this.buffer.Pin(); - this.array = new Vector4[this.Length]; - } - - [Benchmark(Baseline = true)] - public Vector4 IterateIndexed() - { - Vector4 sum = new Vector4(); - Vector4[] a = this.array; - - for (int i = 0; i < a.Length; i++) - { - sum += a[i]; - } - return sum; - } - - [Benchmark] - public unsafe Vector4 IterateUsingPointers() - { - Vector4 sum = new Vector4(); - - Vector4* ptr = (Vector4*) this.buffer.Pin(); - Vector4* end = ptr + this.Length; - - for (; ptr < end; ptr++) - { - sum += *ptr; - } - - return sum; - } - - [Benchmark] - public Vector4 IterateUsingReferences() - { - Vector4 sum = new Vector4(); - - ref Vector4 start = ref this.array[0]; - - for (int i = 0; i < this.Length; i++) - { - sum += Unsafe.Add(ref start, i); - } - - return sum; - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index ffac1eafa..b5d4aaebe 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -289,7 +289,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } // no need to dispose when buffer is not array owner - buffers[i] = new Buffer2D(new Buffer(values, values.Length), values.Length, 1); + buffers[i] = new Buffer2D(new FakeBuffer(values), values.Length, 1); } return new JpegColorConverter.ComponentValues(buffers, 0); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs index 46d832883..4508c6863 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg this.Output.WriteLine($"Component{i}: {diff}"); averageDifference += diff.average; totalDifference += diff.total; - tolerance += libJpegComponent.SpectralBlocks.Buffer.Length; + tolerance += libJpegComponent.SpectralBlocks.Buffer.Span.Length; } averageDifference /= componentCount; diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 50c3ff005..6afce94fd 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -16,11 +16,11 @@ namespace SixLabors.ImageSharp.Tests.Memory // ReSharper disable once ClassNeverInstantiated.Local private class Assert : Xunit.Assert { - public static void SpanPointsTo(Span span, Buffer buffer, int bufferOffset = 0) + public static void SpanPointsTo(Span span, IBuffer buffer, int bufferOffset = 0) where T : struct { ref T actual = ref span.DangerousGetPinnableReference(); - ref T expected = ref Unsafe.Add(ref buffer[0], bufferOffset); + ref T expected = ref Unsafe.Add(ref buffer.DangerousGetPinnableReference(), bufferOffset); Assert.True(Unsafe.AreSame(ref expected, ref actual), "span does not point to the expected position"); } @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Memory { Assert.Equal(width, buffer.Width); Assert.Equal(height, buffer.Height); - Assert.Equal(width * height, buffer.Buffer.Length); + Assert.Equal(width * height, buffer.Buffer.Length()); } } @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.Memory using (Buffer2D buffer = Configuration.Default.MemoryManager.Allocate2D(42, 42, true)) { Span span = buffer.Span; - for (int j = 0; j < buffer.Buffer.Length; j++) + for (int j = 0; j < span.Length; j++) { Assert.Equal(0, span[j]); span[j] = 666; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 8787fba55..2ea06d724 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -333,25 +333,23 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats where TSource : struct where TDest : struct { - public Buffer SourceBuffer { get; } + public TSource[] SourceBuffer { get; } public Buffer ActualDestBuffer { get; } - public Buffer ExpectedDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } public Span Source => this.SourceBuffer; public Span ActualDest => this.ActualDestBuffer; public TestBuffers(TSource[] source, TDest[] expectedDest) { - this.SourceBuffer = new Buffer(source); - this.ExpectedDestBuffer = new Buffer(expectedDest); + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; this.ActualDestBuffer = Configuration.Default.MemoryManager.Allocate(expectedDest.Length); } public void Dispose() { - this.SourceBuffer.Dispose(); this.ActualDestBuffer.Dispose(); - this.ExpectedDestBuffer.Dispose(); } private const float Tolerance = 0.0001f; @@ -363,7 +361,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats if (typeof(TDest) == typeof(Vector4)) { - Span expected = this.ExpectedDestBuffer.Span.NonPortableCast(); + Span expected = this.ExpectedDestBuffer.AsSpan().NonPortableCast(); Span actual = this.ActualDestBuffer.Span.NonPortableCast(); for (int i = 0; i < count; i++) @@ -375,7 +373,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } else { - Span expected = this.ExpectedDestBuffer.Span; + Span expected = this.ExpectedDestBuffer.AsSpan(); Span actual = this.ActualDestBuffer.Span; for (int i = 0; i < count; i++) { @@ -388,7 +386,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats internal static void TestOperation( TSource[] source, TDest[] expected, - Action, Buffer> action) + Action> action) where TSource : struct where TDest : struct { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index d14a0165a..b8907e81e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -96,18 +96,20 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs var image = new Image(w, h); - using (var workBuffer = Configuration.Default.MemoryManager.Allocate(w)) + using (IBuffer workBuffer = Configuration.Default.MemoryManager.Allocate(w)) { - var destPtr = (Argb32*)workBuffer.Pin(); - for (int y = 0; y < h; y++) + fixed (Argb32* destPtr = &workBuffer.DangerousGetPinnableReference()) { - Span row = image.Frames.RootFrame.GetPixelRowSpan(y); + for (int y = 0; y < h; y++) + { + Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - byte* sourcePtr = sourcePtrBase + data.Stride * y; + byte* sourcePtr = sourcePtrBase + data.Stride * y; - Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); + Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - FromArgb32(workBuffer, row); + FromArgb32(workBuffer.Span, row); + } } } @@ -138,18 +140,20 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs var image = new Image(w, h); - using (var workBuffer = Configuration.Default.MemoryManager.Allocate(w)) + using (IBuffer workBuffer = Configuration.Default.MemoryManager.Allocate(w)) { - var destPtr = (Rgb24*)workBuffer.Pin(); - for (int y = 0; y < h; y++) + fixed (Rgb24* destPtr = &workBuffer.DangerousGetPinnableReference()) { - Span row = image.Frames.RootFrame.GetPixelRowSpan(y); + for (int y = 0; y < h; y++) + { + Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - byte* sourcePtr = sourcePtrBase + data.Stride * y; + byte* sourcePtr = sourcePtrBase + data.Stride * y; - Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); + Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - FromRgb24(workBuffer, row); + FromRgb24(workBuffer.Span, row); + } } } @@ -170,17 +174,19 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = data.Stride; long sourceRowByteCount = w * sizeof(Argb32); - using (var workBuffer = Configuration.Default.MemoryManager.Allocate(w)) + using (IBuffer workBuffer = image.GetConfiguration().MemoryManager.Allocate(w)) { - var sourcePtr = (Argb32*)workBuffer.Pin(); - - for (int y = 0; y < h; y++) + fixed (Argb32* sourcePtr = &workBuffer.DangerousGetPinnableReference()) { - Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - ToArgb32(row, workBuffer); - byte* destPtr = destPtrBase + data.Stride * y; - Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); + for (int y = 0; y < h; y++) + { + Span row = image.Frames.RootFrame.GetPixelRowSpan(y); + ToArgb32(row, workBuffer.Span); + byte* destPtr = destPtrBase + data.Stride * y; + + Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); + } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 54e55f7e5..b830acdef 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Tests bool appendPixelTypeToFileName = true) where TPixel : struct, IPixel { - using (Image firstFrameOnlyImage = new Image(image.Width, image.Height)) + using (var firstFrameOnlyImage = new Image(image.Width, image.Height)) using (Image referenceImage = GetReferenceOutputImage( provider, testOutputDetails, @@ -378,9 +378,11 @@ namespace SixLabors.ImageSharp.Tests Span pixels = image.Frames.RootFrame.GetPixelSpan(); - for (int i = 0; i < buffer.Buffer.Length; i++) + Span bufferSpan = buffer.Span; + + for (int i = 0; i < bufferSpan.Length; i++) { - float value = buffer.Buffer[i] * scale; + float value = bufferSpan[i] * scale; var v = new Vector4(value, value, value, 1f); pixels[i].PackFromVector4(v); }