From 96b51193fd44ac390c309d3733457c0470cccae9 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 22 Jul 2018 17:01:39 +0200 Subject: [PATCH 1/8] introducing BufferManager --- ImageSharp.sln.DotSettings | 5 +- src/ImageSharp/Memory/BufferManager.cs | 73 ++++++++ src/ImageSharp/Memory/IBuffer{T}.cs | 8 +- .../Memory/MemoryAllocatorExtensions.cs | 11 +- .../ImageSharp.Tests/Memory/Buffer2DTests.cs | 50 ++---- .../Memory/BufferManagerTests.cs | 158 ++++++++++++++++++ .../Processors/Transforms/ResizeTests.cs | 3 +- .../TestUtilities/TestMemoryAllocator.cs | 55 ++++++ .../TestUtilities/TestMemoryManager.cs | 19 +-- .../TestUtilities/TestUtils.cs | 2 +- 10 files changed, 328 insertions(+), 56 deletions(-) create mode 100644 src/ImageSharp/Memory/BufferManager.cs create mode 100644 tests/ImageSharp.Tests/Memory/BufferManagerTests.cs create mode 100644 tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs diff --git a/ImageSharp.sln.DotSettings b/ImageSharp.sln.DotSettings index 435aad73b..432f4524a 100644 --- a/ImageSharp.sln.DotSettings +++ b/ImageSharp.sln.DotSettings @@ -343,8 +343,11 @@ <Entry DisplayName="All other members" /> </TypePattern> </Patterns> - True + False True + // Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + AC DC DCT diff --git a/src/ImageSharp/Memory/BufferManager.cs b/src/ImageSharp/Memory/BufferManager.cs new file mode 100644 index 000000000..f1cbb7512 --- /dev/null +++ b/src/ImageSharp/Memory/BufferManager.cs @@ -0,0 +1,73 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; + +namespace SixLabors.Memory +{ + /// + /// Holds a that is either OWNED or CONSUMED. + /// Implements content transfer logic in that depends on the ownership status. + /// This is needed to transfer the contents of a temporary to a persistent + /// + internal struct BufferManager : IDisposable + { + public BufferManager(IMemoryOwner memoryOwner) + { + this.MemoryOwner = memoryOwner; + this.Memory = memoryOwner.Memory; + } + + public BufferManager(Memory memory) + { + this.Memory = memory; + this.MemoryOwner = null; + } + + public IMemoryOwner MemoryOwner { get; private set; } + + public Memory Memory { get; private set; } + + public bool OwnsMemory => this.MemoryOwner != null; + + /// + /// Swaps the contents of 'destination' with 'source' if the buffers are owned (1), + /// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2! + /// + public static void SwapOrCopyContent(ref BufferManager destination, ref BufferManager source) + { + if (source.OwnsMemory && destination.OwnsMemory) + { + SwapContents(ref destination, ref source); + } + else + { + if (destination.Memory.Length != source.Memory.Length) + { + throw new InvalidOperationException("SwapOrCopyContents(): buffers should both owned or the same size!"); + } + + source.Memory.CopyTo(destination.Memory); + } + } + + /// + public void Dispose() + { + this.MemoryOwner?.Dispose(); + } + + private static void SwapContents(ref BufferManager a, ref BufferManager b) + { + IMemoryOwner tempOwner = a.MemoryOwner; + Memory tempMemory = a.Memory; + + a.MemoryOwner = b.MemoryOwner; + a.Memory = b.Memory; + + b.MemoryOwner = tempOwner; + b.Memory = tempMemory; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Memory/IBuffer{T}.cs b/src/ImageSharp/Memory/IBuffer{T}.cs index 847f2741d..73406971a 100644 --- a/src/ImageSharp/Memory/IBuffer{T}.cs +++ b/src/ImageSharp/Memory/IBuffer{T}.cs @@ -19,14 +19,14 @@ namespace SixLabors.Memory where T : struct { /// - /// Gets the ownerd/consumed by this buffer. + /// Gets a value indicating whether this instance is owning the . /// - Memory Memory { get; } + bool IsMemoryOwner { get; } /// - /// Gets a value indicating whether this instance is owning the . + /// Gets the ownerd/consumed by this buffer. /// - bool IsMemoryOwner { get; } + Memory Memory { get; } /// /// Gets the span to the memory "promised" by this buffer when it's OWNED (1). diff --git a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs index 2f296636d..899d2f0f6 100644 --- a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs +++ b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs @@ -7,7 +7,11 @@ namespace SixLabors.Memory /// internal static class MemoryAllocatorExtensions { - public static Buffer2D Allocate2D(this MemoryAllocator memoryAllocator, int width, int height, AllocationOptions options = AllocationOptions.None) + public static Buffer2D Allocate2D( + this MemoryAllocator memoryAllocator, + int width, + int height, + AllocationOptions options = AllocationOptions.None) where T : struct { IBuffer buffer = memoryAllocator.Allocate(width * height, options); @@ -15,7 +19,10 @@ namespace SixLabors.Memory return new Buffer2D(buffer, width, height); } - public static Buffer2D Allocate2D(this MemoryAllocator memoryAllocator, Size size, AllocationOptions options = AllocationOptions.None) + public static Buffer2D Allocate2D( + this MemoryAllocator memoryAllocator, + Size size, + AllocationOptions options = AllocationOptions.None) where T : struct => Allocate2D(memoryAllocator, size.Width, size.Height, options); diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 5dd8572dc..af9c8bd5b 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -1,20 +1,20 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Tests.Memory -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; - using SixLabors.ImageSharp.PixelFormats; - using SixLabors.Memory; - using SixLabors.ImageSharp.Tests.Common; - using SixLabors.Primitives; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.Primitives; - using Xunit; +using Xunit; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Tests.Memory +{ public class Buffer2DTests { // ReSharper disable once ClassNeverInstantiated.Local @@ -30,31 +30,7 @@ namespace SixLabors.ImageSharp.Tests.Memory } } - private MemoryAllocator MemoryAllocator { get; } = new MockMemoryAllocator(); - - private class MockMemoryAllocator : MemoryAllocator - { - internal override IBuffer Allocate(int length, AllocationOptions options) - { - var array = new T[length + 42]; - - if (options == AllocationOptions.None) - { - Span data = MemoryMarshal.Cast(array.AsSpan()); - for (int i = 0; i < data.Length; i++) - { - data[i] = 42; - } - } - - return new BasicArrayBuffer(array, length); - } - - internal override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options) - { - throw new NotImplementedException(); - } - } + private MemoryAllocator MemoryAllocator { get; } = new TestMemoryAllocator(); [Theory] [InlineData(7, 42)] @@ -134,7 +110,7 @@ namespace SixLabors.ImageSharp.Tests.Memory public class SwapOrCopyContent { - private MemoryAllocator MemoryAllocator { get; } = new MockMemoryAllocator(); + private MemoryAllocator MemoryAllocator { get; } = new TestMemoryAllocator(); [Fact] public void WhenBothBuffersAreMemoryOwners_ShouldSwap() diff --git a/tests/ImageSharp.Tests/Memory/BufferManagerTests.cs b/tests/ImageSharp.Tests/Memory/BufferManagerTests.cs new file mode 100644 index 000000000..d08e734e8 --- /dev/null +++ b/tests/ImageSharp.Tests/Memory/BufferManagerTests.cs @@ -0,0 +1,158 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; + +using Xunit; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Tests.Memory +{ + public class BufferManagerTests + { + public class Construction + { + [Fact] + public void InitializeAsOwner_MemoryOwner_IsPresent() + { + var data = new Rgba32[21]; + var mmg = new TestMemoryManager(data); + + var a = new BufferManager(mmg); + + Assert.Equal(mmg, a.MemoryOwner); + Assert.Equal(mmg.Memory, a.Memory); + Assert.True(a.OwnsMemory); + } + + [Fact] + public void InitializeAsObserver_MemoryOwner_IsNull() + { + var data = new Rgba32[21]; + var mmg = new TestMemoryManager(data); + + var a = new BufferManager(mmg.Memory); + + Assert.Null(a.MemoryOwner); + Assert.Equal(mmg.Memory, a.Memory); + Assert.False(a.OwnsMemory); + } + } + + public class Dispose + { + [Fact] + public void WhenOwnershipIsTransfered_ShouldDisposeMemoryOwner() + { + var mmg = new TestMemoryManager(new int[10]); + var bmg = new BufferManager(mmg); + + bmg.Dispose(); + Assert.True(mmg.IsDisposed); + } + + [Fact] + public void WhenMemoryObserver_ShouldNotDisposeAnything() + { + var mmg = new TestMemoryManager(new int[10]); + var bmg = new BufferManager(mmg.Memory); + + bmg.Dispose(); + Assert.False(mmg.IsDisposed); + } + } + + public class SwapOrCopyContent + { + private MemoryAllocator MemoryAllocator { get; } = new TestMemoryAllocator(); + + private BufferManager AllocateBufferManager(int length, AllocationOptions options = AllocationOptions.None) + where T : struct + { + var owner = (IMemoryOwner)this.MemoryAllocator.Allocate(length, options); + return new BufferManager(owner); + } + + [Fact] + public void WhenBothAreMemoryOwners_ShouldSwap() + { + BufferManager a = this.AllocateBufferManager(13); + BufferManager b = this.AllocateBufferManager(17); + + IMemoryOwner aa = a.MemoryOwner; + IMemoryOwner bb = b.MemoryOwner; + + Memory aaa = a.Memory; + Memory bbb = b.Memory; + + BufferManager.SwapOrCopyContent(ref a, ref b); + + Assert.Equal(bb, a.MemoryOwner); + Assert.Equal(aa, b.MemoryOwner); + + Assert.Equal(bbb, a.Memory); + Assert.Equal(aaa, b.Memory); + Assert.NotEqual(a.Memory, b.Memory); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void WhenDestIsNotMemoryOwner_SameSize_ShouldCopy(bool sourceIsOwner) + { + var data = new Rgba32[21]; + var color = new Rgba32(1, 2, 3, 4); + + var destOwner = new TestMemoryManager(data); + var dest = new BufferManager(destOwner.Memory); + + var sourceOwner = (IMemoryOwner)this.MemoryAllocator.Allocate(21); + + BufferManager source = sourceIsOwner + ? new BufferManager(sourceOwner) + : new BufferManager(sourceOwner.Memory); + + sourceOwner.Memory.Span[10] = color; + + // Act: + BufferManager.SwapOrCopyContent(ref dest, ref source); + + // Assert: + Assert.Equal(color, dest.Memory.Span[10]); + Assert.NotEqual(sourceOwner, dest.MemoryOwner); + Assert.NotEqual(destOwner, source.MemoryOwner); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void WhenDestIsNotMemoryOwner_DifferentSize_Throws(bool sourceIsOwner) + { + var data = new Rgba32[21]; + var color = new Rgba32(1, 2, 3, 4); + + var destOwner = new TestMemoryManager(data); + var dest = new BufferManager(destOwner.Memory); + + var sourceOwner = (IMemoryOwner)this.MemoryAllocator.Allocate(22); + + BufferManager source = sourceIsOwner + ? new BufferManager(sourceOwner) + : new BufferManager(sourceOwner.Memory); + sourceOwner.Memory.Span[10] = color; + + // Act: + Assert.ThrowsAny( + () => BufferManager.SwapOrCopyContent(ref dest, ref source) + ); + + Assert.Equal(color, source.Memory.Span[10]); + Assert.NotEqual(color, dest.Memory.Span[10]); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index c7efbb1e0..746d8da16 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -3,6 +3,7 @@ using System; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -91,7 +92,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { using (Image image0 = provider.GetImage()) { - var mmg = TestMemoryManager.CreateAsCopyOfPixelData(image0); + var mmg = TestMemoryManager.CreateAsCopyOf(image0.GetPixelSpan()); using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs new file mode 100644 index 000000000..7993b3e99 --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs @@ -0,0 +1,55 @@ +using System; +using System.Runtime.InteropServices; + +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.Tests.Memory +{ + internal class TestMemoryAllocator : MemoryAllocator + { + public TestMemoryAllocator(byte dirtyValue = 42) + { + this.DirtyValue = dirtyValue; + } + + /// + /// The value to initilazie the result buffer with, with non-clean options () + /// + public byte DirtyValue { get; } + + internal override IBuffer Allocate(int length, AllocationOptions options = AllocationOptions.None) + { + T[] array = this.AllocateArray(length, options); + + return new BasicArrayBuffer(array, length); + } + + internal override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None) + { + byte[] array = this.AllocateArray(length, options); + return new ManagedByteBuffer(array); + } + + private T[] AllocateArray(int length, AllocationOptions options) + where T : struct + { + var array = new T[length + 42]; + + if (options == AllocationOptions.None) + { + Span data = MemoryMarshal.Cast(array.AsSpan()); + data.Fill(this.DirtyValue); + } + + return array; + } + + private class ManagedByteBuffer : BasicArrayBuffer, IManagedByteBuffer + { + public ManagedByteBuffer(byte[] array) + : base(array) + { + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs b/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs index e7ecb2dda..ce3cfbc9e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs @@ -7,18 +7,16 @@ namespace SixLabors.ImageSharp.Tests using SixLabors.ImageSharp.PixelFormats; class TestMemoryManager : MemoryManager - where T : struct, IPixel + where T : struct { public TestMemoryManager(T[] pixelArray) { this.PixelArray = pixelArray; } - public T[] PixelArray { get; } + public T[] PixelArray { get; private set; } - protected override void Dispose(bool disposing) - { - } + public bool IsDisposed { get; private set; } public override Span GetSpan() { @@ -35,16 +33,17 @@ namespace SixLabors.ImageSharp.Tests throw new NotImplementedException(); } - public static TestMemoryManager CreateAsCopyOfPixelData(Span pixelData) + public static TestMemoryManager CreateAsCopyOf(Span copyThisBuffer) { - var pixelArray = new T[pixelData.Length]; - pixelData.CopyTo(pixelArray); + var pixelArray = new T[copyThisBuffer.Length]; + copyThisBuffer.CopyTo(pixelArray); return new TestMemoryManager(pixelArray); } - public static TestMemoryManager CreateAsCopyOfPixelData(Image image) + protected override void Dispose(bool disposing) { - return CreateAsCopyOfPixelData(image.GetPixelSpan()); + this.IsDisposed = true; + this.PixelArray = null; } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 03ab422e5..a6ea76f2d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.Tests using (Image image0 = provider.GetImage()) { - var mmg = TestMemoryManager.CreateAsCopyOfPixelData(image0.GetPixelSpan()); + var mmg = TestMemoryManager.CreateAsCopyOf(image0.GetPixelSpan()); using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) { From 12bcdbb49aa294054bb9e8d6fcd42578cc8f6d39 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 22 Jul 2018 19:10:46 +0200 Subject: [PATCH 2/8] replace IBuffer with IMemoryOwner --- .../Primitives/ShapeRegion.cs | 3 +- .../Processing/BrushApplicator.cs | 6 +- .../Processing/ImageBrush{TPixel}.cs | 5 +- .../Processing/PatternBrush{TPixel}.cs | 5 +- .../Processors/Drawing/DrawImageProcessor.cs | 3 +- .../Processors/Drawing/FillProcessor.cs | 4 +- .../Processors/Drawing/FillRegionProcessor.cs | 6 +- .../Processors/Text/DrawTextProcessor.cs | 5 +- .../Processing/RecolorBrush{TPixel}.cs | 5 +- .../Processing/SolidBrush{TPixel}.cs | 6 +- src/ImageSharp/Common/Helpers/ParallelFor.cs | 9 +- src/ImageSharp/Formats/Gif/LzwDecoder.cs | 7 +- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 5 +- .../Decoder/JpegBlockPostProcessor.cs | 2 +- .../Decoder/JpegImagePostProcessor.cs | 3 +- .../PdfJsPort/Components/PdfJsHuffmanTable.cs | 3 +- src/ImageSharp/Image.WrapMemory.cs | 3 +- src/ImageSharp/ImageFrameCollection.cs | 2 +- src/ImageSharp/ImageFrame{TPixel}.cs | 7 +- src/ImageSharp/Image{TPixel}.cs | 4 +- .../ArrayPoolMemoryAllocator.Buffer{T}.cs | 1 - .../Memory/ArrayPoolMemoryAllocator.cs | 2 +- src/ImageSharp/Memory/BasicArrayBuffer.cs | 2 +- src/ImageSharp/Memory/Buffer2D{T}.cs | 54 ++++------ src/ImageSharp/Memory/BufferExtensions.cs | 20 ++-- src/ImageSharp/Memory/BufferManager.cs | 9 ++ src/ImageSharp/Memory/ConsumedBuffer.cs | 34 ------ src/ImageSharp/Memory/IBuffer{T}.cs | 38 ------- src/ImageSharp/Memory/IManagedByteBuffer.cs | 4 +- src/ImageSharp/Memory/ManagedBufferBase.cs | 4 +- src/ImageSharp/Memory/MemoryAllocator.cs | 6 +- .../Memory/MemoryAllocatorExtensions.cs | 6 +- .../Memory/SimpleGcMemoryAllocator.cs | 6 +- .../DefaultPixelBlenders.Generated.cs | 52 ++++----- .../DefaultPixelBlenders.Generated.tt | 12 +-- .../HistogramEqualizationProcessor.cs | 5 +- .../Overlays/BackgroundColorProcessor.cs | 5 +- .../Processors/Overlays/GlowProcessor.cs | 5 +- .../Processors/Overlays/VignetteProcessor.cs | 5 +- .../Quantization/QuantizedFrame{TPixel}.cs | 4 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 45 ++++---- .../Processors/Transforms/ResizeProcessor.cs | 3 +- .../Processors/Transforms/WeightsWindow.cs | 5 +- .../Color/Bulk/PackFromVector4.cs | 23 ++-- .../Color/Bulk/PackFromXyzw.cs | 18 ++-- .../Color/Bulk/ToVector4.cs | 20 ++-- .../ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs | 19 ++-- .../Color/Bulk/ToXyzw.cs | 18 ++-- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 8 +- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 4 +- .../Image/ImageTests.WrapMemory.cs | 7 -- .../Memory/ArrayPoolMemoryManagerTests.cs | 16 +-- .../ImageSharp.Tests/Memory/Buffer2DTests.cs | 101 +++--------------- .../Memory/BufferTestSuite.cs | 27 ++--- .../PixelFormats/PixelOperationsTests.cs | 9 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 7 +- .../TestUtilities/TestMemoryAllocator.cs | 3 +- .../TestUtilities/TestMemoryManager.cs | 3 - 58 files changed, 298 insertions(+), 405 deletions(-) delete mode 100644 src/ImageSharp/Memory/ConsumedBuffer.cs delete mode 100644 src/ImageSharp/Memory/IBuffer{T}.cs diff --git a/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs b/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs index 9f5611dc0..fddd283e0 100644 --- a/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs +++ b/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using SixLabors.Memory; using SixLabors.Primitives; using SixLabors.Shapes; @@ -45,7 +46,7 @@ namespace SixLabors.ImageSharp.Primitives var start = new PointF(this.Bounds.Left - 1, y); var end = new PointF(this.Bounds.Right + 1, y); - using (IBuffer tempBuffer = configuration.MemoryAllocator.Allocate(buffer.Length)) + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(buffer.Length)) { Span innerBuffer = tempBuffer.GetSpan(); int count = this.Shape.FindIntersections(start, end, innerBuffer); diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index 0ac4e4dd1..64f37eeab 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; + using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -65,8 +67,8 @@ namespace SixLabors.ImageSharp.Processing { MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; - using (IBuffer amountBuffer = memoryAllocator.Allocate(scanline.Length)) - using (IBuffer overlay = memoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner overlay = memoryAllocator.Allocate(scanline.Length)) { Span amountSpan = amountBuffer.GetSpan(); Span overlaySpan = overlay.GetSpan(); diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs index 7e24dbbe2..5ebad0f32 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -118,8 +119,8 @@ namespace SixLabors.ImageSharp.Processing internal override void Apply(Span scanline, int x, int y) { // Create a span for colors - using (IBuffer amountBuffer = this.Target.MemoryAllocator.Allocate(scanline.Length)) - using (IBuffer overlay = this.Target.MemoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner amountBuffer = this.Target.MemoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner overlay = this.Target.MemoryAllocator.Allocate(scanline.Length)) { Span amountSpan = amountBuffer.GetSpan(); Span overlaySpan = overlay.GetSpan(); diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs index 30d78bc83..ab48a185b 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; @@ -153,8 +154,8 @@ namespace SixLabors.ImageSharp.Processing int patternY = y % this.pattern.Rows; MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; - using (IBuffer amountBuffer = memoryAllocator.Allocate(scanline.Length)) - using (IBuffer overlay = memoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner overlay = memoryAllocator.Allocate(scanline.Length)) { Span amountSpan = amountBuffer.GetSpan(); Span overlaySpan = overlay.GetSpan(); diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index e4b2eadb4..4a59dfe3e 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; @@ -134,7 +135,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; - using (IBuffer amount = memoryAllocator.Allocate(width)) + using (IMemoryOwner amount = memoryAllocator.Allocate(width)) { amount.GetSpan().Fill(this.Opacity); diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index 595c94687..e40ba5316 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -2,10 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SixLabors.Memory; using SixLabors.Primitives; @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing startY = 0; } - using (IBuffer amount = source.MemoryAllocator.Allocate(width)) + using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) using (BrushApplicator applicator = this.brush.CreateApplicator( source, sourceRectangle, diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 1cc954dd9..b9db3f067 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Utils; @@ -94,8 +96,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing using (BrushApplicator applicator = this.Brush.CreateApplicator(source, rect, this.Options)) { int scanlineWidth = maxX - minX; - using (IBuffer bBuffer = source.MemoryAllocator.Allocate(maxIntersections)) - using (IBuffer bScanline = source.MemoryAllocator.Allocate(scanlineWidth)) + using (IMemoryOwner bBuffer = source.MemoryAllocator.Allocate(maxIntersections)) + using (IMemoryOwner bScanline = source.MemoryAllocator.Allocate(scanlineWidth)) { bool scanlineDirty = true; float subpixelFraction = 1f / subpixelCount; diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 8909ca453..048c4440d 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Collections.Generic; using SixLabors.Fonts; using SixLabors.ImageSharp.Advanced; @@ -336,8 +337,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text // take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it. Buffer2D fullBuffer = this.MemoryAllocator.Allocate2D(size.Width + 1, size.Height + 1, AllocationOptions.Clean); - using (IBuffer bufferBacking = this.MemoryAllocator.Allocate(path.MaxIntersections)) - using (IBuffer rowIntersectionBuffer = this.MemoryAllocator.Allocate(size.Width)) + using (IMemoryOwner bufferBacking = this.MemoryAllocator.Allocate(path.MaxIntersections)) + using (IMemoryOwner rowIntersectionBuffer = this.MemoryAllocator.Allocate(size.Width)) { float subpixelFraction = 1f / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount; diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs index 058b03d62..e1b11637d 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; @@ -138,8 +139,8 @@ namespace SixLabors.ImageSharp.Processing { MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; - using (IBuffer amountBuffer = memoryAllocator.Allocate(scanline.Length)) - using (IBuffer overlay = memoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner overlay = memoryAllocator.Allocate(scanline.Length)) { Span amountSpan = amountBuffer.GetSpan(); Span overlaySpan = overlay.GetSpan(); diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 8a2d47c6c..3904f3d9b 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; + using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -65,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing /// /// Gets the colors. /// - protected IBuffer Colors { get; } + protected IMemoryOwner Colors { get; } /// /// Gets the color for a single pixel. @@ -96,7 +98,7 @@ namespace SixLabors.ImageSharp.Processing } else { - using (IBuffer amountBuffer = memoryAllocator.Allocate(scanline.Length)) + using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) { Span amountSpan = amountBuffer.GetSpan(); diff --git a/src/ImageSharp/Common/Helpers/ParallelFor.cs b/src/ImageSharp/Common/Helpers/ParallelFor.cs index 7061475a7..02c6deda3 100644 --- a/src/ImageSharp/Common/Helpers/ParallelFor.cs +++ b/src/ImageSharp/Common/Helpers/ParallelFor.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Threading.Tasks; using SixLabors.Memory; @@ -32,23 +33,23 @@ namespace SixLabors.ImageSharp int toExclusive, Configuration configuration, int bufferLength, - Action> body) + Action> body) where T : struct { MemoryAllocator memoryAllocator = configuration.MemoryAllocator; ParallelOptions parallelOptions = configuration.ParallelOptions; - IBuffer InitBuffer() + IMemoryOwner InitBuffer() { return memoryAllocator.Allocate(bufferLength); } - void CleanUpBuffer(IBuffer buffer) + void CleanUpBuffer(IMemoryOwner buffer) { buffer.Dispose(); } - IBuffer BodyFunc(int i, ParallelLoopState state, IBuffer buffer) + IMemoryOwner BodyFunc(int i, ParallelLoopState state, IMemoryOwner buffer) { body(i, buffer); return buffer; diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs index 2884abfe8..7a2aef180 100644 --- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -32,17 +33,17 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The prefix buffer. /// - private readonly IBuffer prefix; + private readonly IMemoryOwner prefix; /// /// The suffix buffer. /// - private readonly IBuffer suffix; + private readonly IMemoryOwner suffix; /// /// The pixel stack buffer. /// - private readonly IBuffer pixelStack; + private readonly IMemoryOwner pixelStack; /// /// Initializes a new instance of the class diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index 5a588a671..002457db3 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -66,12 +67,12 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The hash table. /// - private readonly IBuffer hashTable; + private readonly IMemoryOwner hashTable; /// /// The code table. /// - private readonly IBuffer codeTable; + private readonly IMemoryOwner codeTable; /// /// Define the storage for the packet accumulator. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs index 2baefff9b..87f675491 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs @@ -9,7 +9,7 @@ using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { /// - /// Encapsulates the implementation of processing "raw" -s into Jpeg image channels. + /// Encapsulates the implementation of processing "raw" jpeg buffers into Jpeg image channels. /// [StructLayout(LayoutKind.Sequential)] internal struct JpegBlockPostProcessor diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 99408cf57..1b513c612 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Linq; using System.Numerics; using SixLabors.ImageSharp.Advanced; @@ -37,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Temporal buffer to store a row of colors. /// - private readonly IBuffer rgbaBuffer; + private readonly IMemoryOwner rgbaBuffer; /// /// The corresponding to the current determined by . diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs index 15ae56331..59992e52c 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.Memory; @@ -48,7 +49,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components public PdfJsHuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan count, ReadOnlySpan values) { const int Length = 257; - using (IBuffer huffcode = memoryAllocator.Allocate(Length)) + using (IMemoryOwner huffcode = memoryAllocator.Allocate(Length)) { ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan()); diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index 3988120e6..3ccd809f4 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -34,8 +34,7 @@ namespace SixLabors.ImageSharp ImageMetaData metaData) where TPixel : struct, IPixel { - var buffer = new ConsumedBuffer(pixelMemory); - return new Image(config, buffer, width, height, metaData); + return new Image(config, pixelMemory, width, height, metaData); } /// diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 14a16b691..4b8f90e9b 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, backgroundColor)); } - internal ImageFrameCollection(Image parent, int width, int height, IBuffer consumedBuffer) + internal ImageFrameCollection(Image parent, int width, int height, Memory consumedBuffer) { Guard.NotNull(parent, nameof(parent)); diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index aa650d380..2fa35f1e5 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Threading.Tasks; @@ -94,7 +95,7 @@ namespace SixLabors.ImageSharp /// /// Initializes a new instance of the class wrapping an existing buffer. /// - internal ImageFrame(Configuration configuration, int width, int height, IBuffer consumedBuffer) + internal ImageFrame(Configuration configuration, int width, int height, Memory consumedBuffer) : this(configuration, width, height, consumedBuffer, new ImageFrameMetaData()) { } @@ -106,7 +107,7 @@ namespace SixLabors.ImageSharp Configuration configuration, int width, int height, - IBuffer consumedBuffer, + Memory consumedBuffer, ImageFrameMetaData metaData) { Guard.NotNull(configuration, nameof(configuration)); @@ -272,7 +273,7 @@ namespace SixLabors.ImageSharp this.Height, this.configuration, this.Width, - (int y, IBuffer tempRowBuffer) => + (int y, IMemoryOwner tempRowBuffer) => { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index ad754bc75..9126812dd 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the class /// consuming an external buffer instance. /// - internal Image(Configuration configuration, IBuffer consumedBuffer, int width, int height) + internal Image(Configuration configuration, Memory consumedBuffer, int width, int height) : this(configuration, consumedBuffer, width, height, new ImageMetaData()) { } @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the class /// consuming an external buffer instance. /// - internal Image(Configuration configuration, IBuffer consumedBuffer, int width, int height, ImageMetaData metadata) + internal Image(Configuration configuration, Memory consumedBuffer, int width, int height, ImageMetaData metadata) { this.configuration = configuration; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs index d0f68c9c6..adc8843a3 100644 --- a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs +++ b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs @@ -14,7 +14,6 @@ namespace SixLabors.Memory { /// /// The buffer implementation of . - /// In this implementation is owned. /// private class Buffer : ManagedBufferBase where T : struct diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs index 08f28c5b3..32c1c6d1d 100644 --- a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs +++ b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs @@ -89,7 +89,7 @@ namespace SixLabors.Memory } /// - internal override IBuffer Allocate(int length, AllocationOptions options) + internal override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None) { int itemSizeBytes = Unsafe.SizeOf(); int bufferSizeInBytes = length * itemSizeBytes; diff --git a/src/ImageSharp/Memory/BasicArrayBuffer.cs b/src/ImageSharp/Memory/BasicArrayBuffer.cs index 5e3893d08..f40df7604 100644 --- a/src/ImageSharp/Memory/BasicArrayBuffer.cs +++ b/src/ImageSharp/Memory/BasicArrayBuffer.cs @@ -7,7 +7,7 @@ using System.Runtime.CompilerServices; namespace SixLabors.Memory { /// - /// Wraps an array as an instance. In this implementation is owned. + /// Wraps an array as an instance. /// internal class BasicArrayBuffer : ManagedBufferBase where T : struct diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index b76c06df8..7d331b46d 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Runtime.CompilerServices; using SixLabors.Primitives; @@ -15,19 +16,31 @@ namespace SixLabors.Memory internal sealed class Buffer2D : IDisposable where T : struct { + private BufferManager buffer; + /// /// Initializes a new instance of the class. /// /// The buffer to wrap /// The number of elements in a row /// The number of rows - public Buffer2D(IBuffer wrappedBuffer, int width, int height) + public Buffer2D(BufferManager wrappedBuffer, int width, int height) { - this.Buffer = wrappedBuffer; + this.buffer = wrappedBuffer; this.Width = width; this.Height = height; } + public Buffer2D(IMemoryOwner ownedMemory, int width, int height) + : this(new BufferManager(ownedMemory), width, height) + { + } + + public Buffer2D(Memory observedMemory, int width, int height) + : this(new BufferManager(observedMemory), width, height) + { + } + /// /// Gets the width. /// @@ -39,13 +52,13 @@ namespace SixLabors.Memory public int Height { get; private set; } /// - /// Gets the backing + /// Gets the backing /// - public IBuffer Buffer { get; private set; } + public BufferManager Buffer => this.buffer; public Memory Memory => this.Buffer.Memory; - public Span Span => this.Buffer.GetSpan(); + public Span Span => this.Memory.Span; /// /// Gets a reference to the element at the specified position. @@ -60,7 +73,7 @@ namespace SixLabors.Memory { ImageSharp.DebugGuard.MustBeLessThan(x, this.Width, nameof(x)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); - Span span = this.Buffer.GetSpan(); + Span span = this.Span; return ref span[(this.Width * y) + x]; } } @@ -70,7 +83,7 @@ namespace SixLabors.Memory /// public void Dispose() { - this.Buffer?.Dispose(); + this.Buffer.Dispose(); } /// @@ -79,36 +92,15 @@ namespace SixLabors.Memory /// public static void SwapOrCopyContent(Buffer2D destination, Buffer2D source) { - if (source.Buffer.IsMemoryOwner && destination.Buffer.IsMemoryOwner) - { - SwapContents(destination, source); - } - else - { - if (destination.Size() != source.Size()) - { - throw new InvalidOperationException("SwapOrCopyContents(): buffers should both owned or the same size!"); - } - - source.Span.CopyTo(destination.Span); - } + BufferManager.SwapOrCopyContent(ref destination.buffer, ref source.buffer); + SwapDimensionData(destination, source); } - /// - /// Swap the contents (, , ) of the two buffers. - /// Useful to transfer the contents of a temporary to a persistent - /// - /// The first buffer - /// The second buffer - private static void SwapContents(Buffer2D a, Buffer2D b) + private static void SwapDimensionData(Buffer2D a, Buffer2D b) { Size aSize = a.Size(); Size bSize = b.Size(); - IBuffer temp = a.Buffer; - a.Buffer = b.Buffer; - b.Buffer = temp; - b.Width = aSize.Width; b.Height = aSize.Height; diff --git a/src/ImageSharp/Memory/BufferExtensions.cs b/src/ImageSharp/Memory/BufferExtensions.cs index 8ebf866bc..800e0d975 100644 --- a/src/ImageSharp/Memory/BufferExtensions.cs +++ b/src/ImageSharp/Memory/BufferExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -11,8 +12,12 @@ namespace SixLabors.Memory internal static class BufferExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Length(this IBuffer buffer) - where T : struct => buffer.GetSpan().Length; + public static Span GetSpan(this IMemoryOwner buffer) + => buffer.Memory.Span; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Length(this IMemoryOwner buffer) + => buffer.GetSpan().Length; /// /// Gets a to an offseted position inside the buffer. @@ -21,8 +26,7 @@ namespace SixLabors.Memory /// The start /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span Slice(this IBuffer buffer, int start) - where T : struct + public static Span Slice(this IMemoryOwner buffer, int start) { return buffer.GetSpan().Slice(start); } @@ -35,8 +39,7 @@ namespace SixLabors.Memory /// The length of the slice /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span Slice(this IBuffer buffer, int start, int length) - where T : struct + public static Span Slice(this IMemoryOwner buffer, int start, int length) { return buffer.GetSpan().Slice(start, length); } @@ -46,13 +49,12 @@ namespace SixLabors.Memory /// /// The buffer [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Clear(this IBuffer buffer) - where T : struct + public static void Clear(this IMemoryOwner buffer) { buffer.GetSpan().Clear(); } - public static ref T GetReference(this IBuffer buffer) + public static ref T GetReference(this IMemoryOwner buffer) where T : struct => ref MemoryMarshal.GetReference(buffer.GetSpan()); diff --git a/src/ImageSharp/Memory/BufferManager.cs b/src/ImageSharp/Memory/BufferManager.cs index f1cbb7512..1a53890d4 100644 --- a/src/ImageSharp/Memory/BufferManager.cs +++ b/src/ImageSharp/Memory/BufferManager.cs @@ -11,6 +11,11 @@ namespace SixLabors.Memory /// Implements content transfer logic in that depends on the ownership status. /// This is needed to transfer the contents of a temporary to a persistent /// + /// + /// For a deeper understanding of the owner/consumer model, check out the following docs:
+ /// https://gist.github.com/GrabYourPitchforks/4c3e1935fd4d9fa2831dbfcab35dffc6 + /// https://www.codemag.com/Article/1807051/Introducing-.NET-Core-2.1-Flagship-Types-Span-T-and-Memory-T + ///
internal struct BufferManager : IDisposable { public BufferManager(IMemoryOwner memoryOwner) @@ -31,6 +36,10 @@ namespace SixLabors.Memory public bool OwnsMemory => this.MemoryOwner != null; + public Span GetSpan() => this.Memory.Span; + + public void Clear() => this.Memory.Span.Clear(); + /// /// Swaps the contents of 'destination' with 'source' if the buffers are owned (1), /// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2! diff --git a/src/ImageSharp/Memory/ConsumedBuffer.cs b/src/ImageSharp/Memory/ConsumedBuffer.cs deleted file mode 100644 index 73468a381..000000000 --- a/src/ImageSharp/Memory/ConsumedBuffer.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; - -namespace SixLabors.Memory -{ - /// - /// A buffer implementation that consumes an existing instance. - /// The ownership of the memory remains external. - /// - /// The value type - internal sealed class ConsumedBuffer : IBuffer - where T : struct - { - public ConsumedBuffer(Memory memory) - { - this.Memory = memory; - } - - public Memory Memory { get; } - - public bool IsMemoryOwner => false; - - public Span GetSpan() - { - return this.Memory.Span; - } - - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Memory/IBuffer{T}.cs b/src/ImageSharp/Memory/IBuffer{T}.cs deleted file mode 100644 index 73406971a..000000000 --- a/src/ImageSharp/Memory/IBuffer{T}.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; - -namespace SixLabors.Memory -{ - /// - /// Represents a contigous memory buffer of value-type items. - /// Depending on it's implementation, an can (1) OWN or (2) CONSUME the instance it wraps. - /// For a deeper understanding of the owner/consumer model, read the following docs:
- /// https://gist.github.com/GrabYourPitchforks/4c3e1935fd4d9fa2831dbfcab35dffc6 - /// TODO: We need more SOC here! For owned buffers we should use . - /// For the consumption case we should not use buffers at all. We need to refactor Buffer2D{T} for this. - ///
- /// The value type - internal interface IBuffer : IDisposable - where T : struct - { - /// - /// Gets a value indicating whether this instance is owning the . - /// - bool IsMemoryOwner { get; } - - /// - /// Gets the ownerd/consumed by this buffer. - /// - Memory Memory { get; } - - /// - /// Gets the span to the memory "promised" by this buffer when it's OWNED (1). - /// Gets `this.Memory.Span` when the buffer CONSUMED (2). - /// - /// The - Span GetSpan(); - } -} \ No newline at end of file diff --git a/src/ImageSharp/Memory/IManagedByteBuffer.cs b/src/ImageSharp/Memory/IManagedByteBuffer.cs index a977eb68f..91c61424b 100644 --- a/src/ImageSharp/Memory/IManagedByteBuffer.cs +++ b/src/ImageSharp/Memory/IManagedByteBuffer.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Buffers; + namespace SixLabors.Memory { /// /// Represents a byte buffer backed by a managed array. Useful for interop with classic .NET API-s. /// - internal interface IManagedByteBuffer : IBuffer + internal interface IManagedByteBuffer : IMemoryOwner { /// /// Gets the managed array backing this buffer instance. diff --git a/src/ImageSharp/Memory/ManagedBufferBase.cs b/src/ImageSharp/Memory/ManagedBufferBase.cs index 8de2f5392..8aaf199ff 100644 --- a/src/ImageSharp/Memory/ManagedBufferBase.cs +++ b/src/ImageSharp/Memory/ManagedBufferBase.cs @@ -7,9 +7,9 @@ using System.Runtime.InteropServices; namespace SixLabors.Memory { /// - /// Provides a base class for implementations by implementing pinning logic for adaption. + /// Provides a base class for implementations by implementing pinning logic for adaption. /// - internal abstract class ManagedBufferBase : MemoryManager, IBuffer + internal abstract class ManagedBufferBase : MemoryManager where T : struct { private GCHandle pinHandle; diff --git a/src/ImageSharp/Memory/MemoryAllocator.cs b/src/ImageSharp/Memory/MemoryAllocator.cs index 4a65848fc..57b721e48 100644 --- a/src/ImageSharp/Memory/MemoryAllocator.cs +++ b/src/ImageSharp/Memory/MemoryAllocator.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Buffers; + namespace SixLabors.Memory { /// @@ -9,13 +11,13 @@ namespace SixLabors.Memory public abstract class MemoryAllocator { /// - /// Allocates an of size . + /// Allocates an , holding a of length . /// /// Type of the data stored in the buffer /// Size of the buffer to allocate /// The allocation options. /// A buffer of values of type . - internal abstract IBuffer Allocate(int length, AllocationOptions options = AllocationOptions.None) + internal abstract IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None) where T : struct; /// diff --git a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs index 899d2f0f6..327bc8bbf 100644 --- a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs +++ b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs @@ -1,4 +1,6 @@ -using SixLabors.Primitives; +using System.Buffers; + +using SixLabors.Primitives; namespace SixLabors.Memory { @@ -14,7 +16,7 @@ namespace SixLabors.Memory AllocationOptions options = AllocationOptions.None) where T : struct { - IBuffer buffer = memoryAllocator.Allocate(width * height, options); + IMemoryOwner buffer = memoryAllocator.Allocate(width * height, options); return new Buffer2D(buffer, width, height); } diff --git a/src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs b/src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs index 8cb057366..612b53820 100644 --- a/src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs +++ b/src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs @@ -1,4 +1,6 @@ -namespace SixLabors.Memory +using System.Buffers; + +namespace SixLabors.Memory { /// /// Implements by newing up arrays by the GC on every allocation requests. @@ -6,7 +8,7 @@ public sealed class SimpleGcMemoryAllocator : MemoryAllocator { /// - internal override IBuffer Allocate(int length, AllocationOptions options) + internal override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None) { return new BasicArrayBuffer(new T[length]); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 84e528d24..c96a05255 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -2,13 +2,13 @@ // Licensed under the Apache License, Version 2.0. // +using System; +using System.Numerics; +using System.Buffers; +using SixLabors.Memory; + namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { - using System; - using System.Numerics; - using SixLabors.Memory; - - /// /// Collection of Porter Duff alpha blending functions applying different composition models. /// @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -239,7 +239,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -278,7 +278,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -317,7 +317,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -356,7 +356,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -395,7 +395,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -434,7 +434,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -473,7 +473,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -512,7 +512,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -551,7 +551,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -590,7 +590,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -629,7 +629,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -668,7 +668,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -707,7 +707,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -746,7 +746,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -785,7 +785,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -824,7 +824,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index cf16f9705..4f627764f 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -12,13 +12,13 @@ // Licensed under the Apache License, Version 2.0. // +using System; +using System.Numerics; +using System.Buffers; +using SixLabors.Memory; + namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { - using System; - using System.Numerics; - using SixLabors.Memory; - - /// /// Collection of Porter Duff alpha blending functions applying different composition models. /// @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs index b834b8968..7b6209c30 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; @@ -43,8 +44,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization Span pixels = source.GetPixelSpan(); // Build the histogram of the grayscale levels. - using (IBuffer histogramBuffer = memoryAllocator.Allocate(this.LuminanceLevels, AllocationOptions.Clean)) - using (IBuffer cdfBuffer = memoryAllocator.Allocate(this.LuminanceLevels, AllocationOptions.Clean)) + using (IMemoryOwner histogramBuffer = memoryAllocator.Allocate(this.LuminanceLevels, AllocationOptions.Clean)) + using (IMemoryOwner cdfBuffer = memoryAllocator.Allocate(this.LuminanceLevels, AllocationOptions.Clean)) { Span histogram = histogramBuffer.GetSpan(); for (int i = 0; i < pixels.Length; i++) diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 797d388c0..d2e89fcd0 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; @@ -65,8 +66,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays int width = maxX - minX; - using (IBuffer colors = source.MemoryAllocator.Allocate(width)) - using (IBuffer amount = source.MemoryAllocator.Allocate(width)) + using (IMemoryOwner colors = source.MemoryAllocator.Allocate(width)) + using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) { // Be careful! Do not capture colorSpan & amountSpan in the lambda below! Span colorSpan = colors.GetSpan(); diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 023643520..17d131413 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; @@ -111,7 +112,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } int width = maxX - minX; - using (IBuffer rowColors = source.MemoryAllocator.Allocate(width)) + using (IMemoryOwner rowColors = source.MemoryAllocator.Allocate(width)) { // Be careful! Do not capture rowColorsSpan in the lambda below! Span rowColorsSpan = rowColors.GetSpan(); @@ -127,7 +128,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays configuration.ParallelOptions, y => { - using (IBuffer amounts = source.MemoryAllocator.Allocate(width)) + using (IMemoryOwner amounts = source.MemoryAllocator.Allocate(width)) { Span amountsSpan = amounts.GetSpan(); int offsetY = y - startY; diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 3789e6bf8..a306459d1 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; @@ -113,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } int width = maxX - minX; - using (IBuffer rowColors = source.MemoryAllocator.Allocate(width)) + using (IMemoryOwner rowColors = source.MemoryAllocator.Allocate(width)) { // Be careful! Do not capture rowColorsSpan in the lambda below! Span rowColorsSpan = rowColors.GetSpan(); @@ -129,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays configuration.ParallelOptions, y => { - using (IBuffer amounts = source.MemoryAllocator.Allocate(width)) + using (IMemoryOwner amounts = source.MemoryAllocator.Allocate(width)) { Span amountsSpan = amounts.GetSpan(); int offsetY = y - startY; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index 6c2e6173f..d0d79093c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -15,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public class QuantizedFrame : IDisposable where TPixel : struct, IPixel { - private IBuffer pixels; + private IMemoryOwner pixels; /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 9a2a84e81..80eefa9b3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; @@ -70,37 +71,37 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Moment of P(c). /// - private IBuffer vwt; + private IMemoryOwner vwt; /// /// Moment of r*P(c). /// - private IBuffer vmr; + private IMemoryOwner vmr; /// /// Moment of g*P(c). /// - private IBuffer vmg; + private IMemoryOwner vmg; /// /// Moment of b*P(c). /// - private IBuffer vmb; + private IMemoryOwner vmb; /// /// Moment of a*P(c). /// - private IBuffer vma; + private IMemoryOwner vma; /// /// Moment of c^2*P(c). /// - private IBuffer m2; + private IMemoryOwner m2; /// /// Color space tag. /// - private IBuffer tag; + private IMemoryOwner tag; /// /// Maximum allowed color depth @@ -467,18 +468,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Span vmaSpan = this.vma.GetSpan(); Span m2Span = this.m2.GetSpan(); - using (IBuffer volume = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) - using (IBuffer volumeR = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) - using (IBuffer volumeG = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) - using (IBuffer volumeB = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) - using (IBuffer volumeA = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) - using (IBuffer volume2 = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) - using (IBuffer area = memoryAllocator.Allocate(IndexAlphaCount)) - using (IBuffer areaR = memoryAllocator.Allocate(IndexAlphaCount)) - using (IBuffer areaG = memoryAllocator.Allocate(IndexAlphaCount)) - using (IBuffer areaB = memoryAllocator.Allocate(IndexAlphaCount)) - using (IBuffer areaA = memoryAllocator.Allocate(IndexAlphaCount)) - using (IBuffer area2 = memoryAllocator.Allocate(IndexAlphaCount)) + using (IMemoryOwner volume = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) + using (IMemoryOwner volumeR = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) + using (IMemoryOwner volumeG = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) + using (IMemoryOwner volumeB = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) + using (IMemoryOwner volumeA = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) + using (IMemoryOwner volume2 = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) + using (IMemoryOwner area = memoryAllocator.Allocate(IndexAlphaCount)) + using (IMemoryOwner areaR = memoryAllocator.Allocate(IndexAlphaCount)) + using (IMemoryOwner areaG = memoryAllocator.Allocate(IndexAlphaCount)) + using (IMemoryOwner areaB = memoryAllocator.Allocate(IndexAlphaCount)) + using (IMemoryOwner areaA = memoryAllocator.Allocate(IndexAlphaCount)) + using (IMemoryOwner area2 = memoryAllocator.Allocate(IndexAlphaCount)) { Span volumeSpan = volume.GetSpan(); Span volumeRSpan = volumeR.GetSpan(); @@ -791,7 +792,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.colorCube = new Box[this.colors]; float[] vv = new float[this.colors]; - ref var cube = ref this.colorCube[0]; + ref Box cube = ref this.colorCube[0]; cube.R0 = cube.G0 = cube.B0 = cube.A0 = 0; cube.R1 = cube.G1 = cube.B1 = IndexCount - 1; cube.A1 = IndexAlphaCount - 1; @@ -800,8 +801,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization for (int i = 1; i < this.colors; i++) { - ref var nextCube = ref this.colorCube[next]; - ref var currentCube = ref this.colorCube[i]; + ref Box nextCube = ref this.colorCube[next]; + ref Box currentCube = ref this.colorCube[i]; if (this.Cut(ref nextCube, ref currentCube)) { vv[next] = nextCube.Volume > 1 ? this.Variance(ref nextCube) : 0F; diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 8c9ab9a23..7f18faec3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -303,7 +304,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms sourceRectangle.Bottom, configuration, source.Width, - (int y, IBuffer tempRowBuffer) => + (int y, IMemoryOwner tempRowBuffer) => { ref Vector4 firstPassRow = ref MemoryMarshal.GetReference(firstPassPixels.GetRowSpan(y)); Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs b/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs index ebf2db4bf..19909aaba 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -32,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The buffer containing the weights values. /// - private readonly IBuffer buffer; + private readonly BufferManager buffer; /// /// Initializes a new instance of the struct. @@ -66,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span GetWindowSpan() => this.buffer.Slice(this.flatStartIndex, this.Length); + public Span GetWindowSpan() => this.buffer.GetSpan().Slice(this.flatStartIndex, this.Length); /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index ac396d42e..6f4195d6f 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -1,21 +1,24 @@ // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk -{ - using System.Numerics; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - using BenchmarkDotNet.Attributes; - using SixLabors.Memory; - using SixLabors.ImageSharp.PixelFormats; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; +using SixLabors.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ [Config(typeof(Config.ShortClr))] public abstract class PackFromVector4 where TPixel : struct, IPixel { - private IBuffer source; + private IMemoryOwner source; - private IBuffer destination; + private IMemoryOwner destination; [Params(16, 128, 512)] public int Count { get; set; } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs index c4c09f67c..33ad9203c 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs @@ -1,19 +1,21 @@ // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk -{ - using System; - using BenchmarkDotNet.Attributes; +using System.Buffers; +using System; + +using BenchmarkDotNet.Attributes; - using SixLabors.Memory; - using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ public abstract class PackFromXyzw where TPixel : struct, IPixel { - private IBuffer destination; + private IMemoryOwner destination; - private IBuffer source; + private IMemoryOwner source; [Params(16, 128, 1024)] public int Count { get; set; } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 3b988757d..75ca1206e 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -1,20 +1,22 @@ // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk -{ - using System; - using System.Numerics; - using BenchmarkDotNet.Attributes; +using System.Buffers; +using System; +using System.Numerics; + +using BenchmarkDotNet.Attributes; - using SixLabors.Memory; - using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ public abstract class ToVector4 where TPixel : struct, IPixel { - private IBuffer source; + private IMemoryOwner source; - private IBuffer destination; + private IMemoryOwner destination; [Params(64, 300, 1024)] public int Count { get; set; } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs index 16743eb73..be1ff72d5 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs @@ -1,20 +1,21 @@ // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk -{ - using System; - using System.Numerics; - using BenchmarkDotNet.Attributes; +using System.Buffers; +using System; + +using BenchmarkDotNet.Attributes; - using SixLabors.Memory; - using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ public abstract class ToXyz where TPixel : struct, IPixel { - private IBuffer source; + private IMemoryOwner source; - private IBuffer destination; + private IMemoryOwner destination; [Params(16, 128, 1024)] public int Count { get; set; } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index f947b6e8d..799be60cc 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -1,22 +1,20 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Buffers; +using BenchmarkDotNet.Attributes; + +using SixLabors.Memory; +using SixLabors.ImageSharp.PixelFormats; + // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - using BenchmarkDotNet.Attributes; - - using SixLabors.Memory; - using SixLabors.ImageSharp.PixelFormats; - public abstract class ToXyzw where TPixel : struct, IPixel { - private IBuffer source; + private IMemoryOwner source; - private IBuffer destination; + private IMemoryOwner destination; [Params(16, 128, 1024)] public int Count { get; set; } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 5fe8b2785..af16c5d74 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -3,6 +3,8 @@ // Licensed under the Apache License, Version 2.0. // +using System.Buffers; + namespace SixLabors.ImageSharp.Benchmarks { using System; @@ -24,7 +26,7 @@ namespace SixLabors.ImageSharp.Benchmarks Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IBuffer buffer = Configuration.Default.MemoryAllocator.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = Configuration.Default.MemoryAllocator.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); @@ -59,7 +61,7 @@ namespace SixLabors.ImageSharp.Benchmarks { using (var image = new Image(800, 800)) { - using (IBuffer amounts = Configuration.Default.MemoryAllocator.Allocate(image.Width)) + using (IMemoryOwner amounts = Configuration.Default.MemoryAllocator.Allocate(image.Width)) { amounts.GetSpan().Fill(1); @@ -80,7 +82,7 @@ namespace SixLabors.ImageSharp.Benchmarks { using (var image = new Image(800, 800)) { - using (IBuffer amounts = Configuration.Default.MemoryAllocator.Allocate(image.Width)) + using (IMemoryOwner amounts = Configuration.Default.MemoryAllocator.Allocate(image.Width)) { amounts.GetSpan().Fill(1); Buffer2D pixels = image.GetRootFramePixelBuffer(); diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index 85c4fdd7c..f7f54f4eb 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -3,6 +3,8 @@ // Licensed under the Apache License, Version 2.0. // +using System.Buffers; + namespace SixLabors.ImageSharp.Benchmarks { @@ -102,7 +104,7 @@ namespace SixLabors.ImageSharp.Benchmarks } int width = maxX - minX; - using (IBuffer rowColors = Configuration.Default.MemoryAllocator.Allocate(width)) + using (IMemoryOwner rowColors = Configuration.Default.MemoryAllocator.Allocate(width)) { Buffer2D sourcePixels = source.PixelBuffer; rowColors.GetSpan().Fill(glowColor); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 066be4a73..252dbc869 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -12,13 +12,6 @@ namespace SixLabors.ImageSharp.Tests { public class WrapMemory { - [Fact] - public void ConsumedBuffer_IsMemoryOwner_ReturnsFalse() - { - var memory = new Memory(new int[55]); - var buffer = new ConsumedBuffer(memory); - Assert.False(buffer.IsMemoryOwner); - } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs b/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs index 14fbe8225..89bb9d95f 100644 --- a/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs +++ b/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs @@ -3,6 +3,8 @@ // ReSharper disable InconsistentNaming +using System.Buffers; + using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.Memory @@ -30,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Memory private bool CheckIsRentingPooledBuffer(int length) where T : struct { - IBuffer buffer = this.MemoryAllocator.Allocate(length); + IMemoryOwner buffer = this.MemoryAllocator.Allocate(length); ref T ptrToPrevPosition0 = ref buffer.GetReference(); buffer.Dispose(); @@ -130,12 +132,12 @@ namespace SixLabors.ImageSharp.Tests.Memory [InlineData(AllocationOptions.Clean)] public void CleaningRequests_AreControlledByAllocationParameter_Clean(AllocationOptions options) { - using (IBuffer firstAlloc = this.MemoryAllocator.Allocate(42)) + using (IMemoryOwner firstAlloc = this.MemoryAllocator.Allocate(42)) { firstAlloc.GetSpan().Fill(666); } - using (IBuffer secondAlloc = this.MemoryAllocator.Allocate(42, options)) + using (IMemoryOwner secondAlloc = this.MemoryAllocator.Allocate(42, options)) { int expected = options == AllocationOptions.Clean ? 0 : 666; Assert.Equal(expected, secondAlloc.GetSpan()[0]); @@ -147,7 +149,7 @@ namespace SixLabors.ImageSharp.Tests.Memory [InlineData(true)] public void ReleaseRetainedResources_ReplacesInnerArrayPool(bool keepBufferAlive) { - IBuffer buffer = this.MemoryAllocator.Allocate(32); + IMemoryOwner buffer = this.MemoryAllocator.Allocate(32); ref int ptrToPrev0 = ref MemoryMarshal.GetReference(buffer.GetSpan()); if (!keepBufferAlive) @@ -165,7 +167,7 @@ namespace SixLabors.ImageSharp.Tests.Memory [Fact] public void ReleaseRetainedResources_DisposingPreviouslyAllocatedBuffer_IsAllowed() { - IBuffer buffer = this.MemoryAllocator.Allocate(32); + IMemoryOwner buffer = this.MemoryAllocator.Allocate(32); this.MemoryAllocator.ReleaseRetainedResources(); buffer.Dispose(); } @@ -181,11 +183,11 @@ namespace SixLabors.ImageSharp.Tests.Memory int arrayLengthThreshold = PoolSelectorThresholdInBytes / sizeof(int); - IBuffer small = this.MemoryAllocator.Allocate(arrayLengthThreshold - 1); + IMemoryOwner small = this.MemoryAllocator.Allocate(arrayLengthThreshold - 1); ref int ptr2Small = ref small.GetReference(); small.Dispose(); - IBuffer large = this.MemoryAllocator.Allocate(arrayLengthThreshold + 1); + IMemoryOwner large = this.MemoryAllocator.Allocate(arrayLengthThreshold + 1); Assert.False(Unsafe.AreSame(ref ptr2Small, ref large.GetReference())); } diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index af9c8bd5b..52d3929f6 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Memory // ReSharper disable once ClassNeverInstantiated.Local private class Assert : Xunit.Assert { - public static void SpanPointsTo(Span span, IBuffer buffer, int bufferOffset = 0) + public static void SpanPointsTo(Span span, IMemoryOwner buffer, int bufferOffset = 0) where T : struct { ref T actual = ref MemoryMarshal.GetReference(span); @@ -41,7 +42,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.Memory.Length); } } @@ -70,7 +71,7 @@ namespace SixLabors.ImageSharp.Tests.Memory // Assert.Equal(width * y, span.Start); Assert.Equal(width, span.Length); - Assert.SpanPointsTo(span, buffer.Buffer, width * y); + Assert.SpanPointsTo(span, buffer.Buffer.MemoryOwner, width * y); } } @@ -86,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Memory // Assert.Equal(width * y + x, span.Start); Assert.Equal(width - x, span.Length); - Assert.SpanPointsTo(span, buffer.Buffer, width * y + x); + Assert.SpanPointsTo(span, buffer.Buffer.MemoryOwner, width * y + x); } } @@ -107,92 +108,24 @@ namespace SixLabors.ImageSharp.Tests.Memory Assert.True(Unsafe.AreSame(ref expected, ref actual)); } } - - public class SwapOrCopyContent - { - private MemoryAllocator MemoryAllocator { get; } = new TestMemoryAllocator(); - - [Fact] - public void WhenBothBuffersAreMemoryOwners_ShouldSwap() - { - using (Buffer2D a = this.MemoryAllocator.Allocate2D(10, 5)) - using (Buffer2D b = this.MemoryAllocator.Allocate2D(3, 7)) - { - IBuffer aa = a.Buffer; - IBuffer bb = b.Buffer; - Buffer2D.SwapOrCopyContent(a, b); - - Assert.Equal(bb, a.Buffer); - Assert.Equal(aa, b.Buffer); - - Assert.Equal(new Size(3, 7), a.Size()); - Assert.Equal(new Size(10, 5), b.Size()); - } - } - - [Fact] - public void WhenDestIsNotMemoryOwner_SameSize_ShouldCopy() + [Fact] + public void SwapOrCopyContent() + { + using (Buffer2D a = this.MemoryAllocator.Allocate2D(10, 5)) + using (Buffer2D b = this.MemoryAllocator.Allocate2D(3, 7)) { - var data = new Rgba32[3 * 7]; - var color = new Rgba32(1, 2, 3, 4); - - var mmg = new TestMemoryManager(data); - var aBuff = new ConsumedBuffer(mmg.Memory); - - using (Buffer2D a = new Buffer2D(aBuff, 3, 7)) - { - IBuffer aa = a.Buffer; + IMemoryOwner aa = a.Buffer.MemoryOwner; + IMemoryOwner bb = b.Buffer.MemoryOwner; - // Precondition: - Assert.Equal(aBuff, aa); + Buffer2D.SwapOrCopyContent(a, b); - using (Buffer2D b = this.MemoryAllocator.Allocate2D(3, 7)) - { - IBuffer bb = b.Buffer; - bb.GetSpan()[10] = color; + Assert.Equal(bb, a.Buffer.MemoryOwner); + Assert.Equal(aa, b.Buffer.MemoryOwner); - // Act: - Buffer2D.SwapOrCopyContent(a, b); - - // Assert: - Assert.Equal(aBuff, a.Buffer); - Assert.Equal(bb, b.Buffer); - } - - // Assert: - Assert.Equal(color, a.Buffer.GetSpan()[10]); - } + Assert.Equal(new Size(3, 7), a.Size()); + Assert.Equal(new Size(10, 5), b.Size()); } - - [Fact] - public void WhenDestIsNotMemoryOwner_DifferentSize_Throws() - { - var data = new Rgba32[3 * 7]; - var color = new Rgba32(1, 2, 3, 4); - data[10] = color; - - var mmg = new TestMemoryManager(data); - var aBuff = new ConsumedBuffer(mmg.Memory); - - using (Buffer2D a = new Buffer2D(aBuff, 3, 7)) - { - IBuffer aa = a.Buffer; - using (Buffer2D b = this.MemoryAllocator.Allocate2D(3, 8)) - { - IBuffer bb = b.Buffer; - - Assert.ThrowsAny( - () => - { - Buffer2D.SwapOrCopyContent(a, b); - }); - } - - Assert.Equal(color, a.Buffer.GetSpan()[10]); - } - } - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Memory/BufferTestSuite.cs b/tests/ImageSharp.Tests/Memory/BufferTestSuite.cs index fd3331288..e57c13164 100644 --- a/tests/ImageSharp.Tests/Memory/BufferTestSuite.cs +++ b/tests/ImageSharp.Tests/Memory/BufferTestSuite.cs @@ -63,15 +63,6 @@ namespace SixLabors.ImageSharp.Tests.Memory public static readonly TheoryData LenthValues = new TheoryData { 0, 1, 7, 1023, 1024 }; - [Fact] - public void IsMemoryOwner() - { - using (IBuffer buffer = this.MemoryAllocator.Allocate(42)) - { - Assert.True(buffer.IsMemoryOwner); - } - } - [Theory] [MemberData(nameof(LenthValues))] public void HasCorrectLength_byte(int desiredLength) @@ -96,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Memory private void TestHasCorrectLength(int desiredLength) where T : struct { - using (IBuffer buffer = this.MemoryAllocator.Allocate(desiredLength)) + using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(desiredLength)) { Assert.Equal(desiredLength, buffer.GetSpan().Length); } @@ -124,12 +115,12 @@ namespace SixLabors.ImageSharp.Tests.Memory this.TestCanAllocateCleanBuffer(desiredLength); } - private IBuffer Allocate(int desiredLength, AllocationOptions options, bool managedByteBuffer) + private IMemoryOwner Allocate(int desiredLength, AllocationOptions options, bool managedByteBuffer) where T : struct { if (managedByteBuffer) { - if (!(this.MemoryAllocator.AllocateManagedByteBuffer(desiredLength, options) is IBuffer buffer)) + if (!(this.MemoryAllocator.AllocateManagedByteBuffer(desiredLength, options) is IMemoryOwner buffer)) { throw new InvalidOperationException("typeof(T) != typeof(byte)"); } @@ -147,7 +138,7 @@ namespace SixLabors.ImageSharp.Tests.Memory for (int i = 0; i < 10; i++) { - using (IBuffer buffer = this.Allocate(desiredLength, AllocationOptions.Clean, testManagedByteBuffer)) + using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.Clean, testManagedByteBuffer)) { Assert.True(buffer.GetSpan().SequenceEqual(expected)); } @@ -172,7 +163,7 @@ namespace SixLabors.ImageSharp.Tests.Memory private void TestSpanPropertyIsAlwaysTheSame(int desiredLength, bool testManagedByteBuffer = false) where T : struct { - using (IBuffer buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer)) + using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer)) { ref T a = ref MemoryMarshal.GetReference(buffer.GetSpan()); ref T b = ref MemoryMarshal.GetReference(buffer.GetSpan()); @@ -201,7 +192,7 @@ namespace SixLabors.ImageSharp.Tests.Memory private void TestWriteAndReadElements(int desiredLength, Func getExpectedValue, bool testManagedByteBuffer = false) where T : struct { - using (IBuffer buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer)) + using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer)) { T[] expectedVals = new T[buffer.Length()]; @@ -247,7 +238,7 @@ namespace SixLabors.ImageSharp.Tests.Memory { var dummy = default(T); - using (IBuffer buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer)) + using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer)) { Assert.ThrowsAny( () => @@ -294,7 +285,7 @@ namespace SixLabors.ImageSharp.Tests.Memory [Fact] public void GetMemory_ReturnsValidMemory() { - using (IBuffer buffer = this.MemoryAllocator.Allocate(42)) + using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(42)) { Span span0 = buffer.GetSpan(); span0[10].A = 30; @@ -311,7 +302,7 @@ namespace SixLabors.ImageSharp.Tests.Memory [Fact] public unsafe void GetMemory_ResultIsPinnable() { - using (IBuffer buffer = this.MemoryAllocator.Allocate(42)) + using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(42)) { Span span0 = buffer.GetSpan(); span0[10] = 30; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index c0e69a902..ca7e48d0b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -57,8 +58,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats int times = 200000; int count = 1024; - using (IBuffer source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IBuffer dest = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) { this.Measure( times, @@ -537,7 +538,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats where TDest : struct { public TSource[] SourceBuffer { get; } - public IBuffer ActualDestBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } public TDest[] ExpectedDestBuffer { get; } public TestBuffers(TSource[] source, TDest[] expectedDest) @@ -586,7 +587,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats internal static void TestOperation( TSource[] source, TDest[] expected, - Action> 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 f0daa0abb..7cc369244 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Drawing; using System.Drawing.Imaging; @@ -43,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs var image = new Image(w, h); - using (IBuffer workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) + using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { fixed (Bgra32* destPtr = &workBuffer.GetReference()) { @@ -89,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs var image = new Image(w, h); - using (IBuffer workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) + using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { fixed (Bgr24* destPtr = &workBuffer.GetReference()) { @@ -122,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = data.Stride; long sourceRowByteCount = w * sizeof(Bgra32); - using (IBuffer workBuffer = image.GetConfiguration().MemoryAllocator.Allocate(w)) + using (IMemoryOwner workBuffer = image.GetConfiguration().MemoryAllocator.Allocate(w)) { fixed (Bgra32* sourcePtr = &workBuffer.GetReference()) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs index 7993b3e99..a580fc7ad 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Runtime.InteropServices; using SixLabors.Memory; @@ -17,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Memory /// public byte DirtyValue { get; } - internal override IBuffer Allocate(int length, AllocationOptions options = AllocationOptions.None) + internal override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None) { T[] array = this.AllocateArray(length, options); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs b/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs index ce3cfbc9e..9274e5727 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs @@ -3,9 +3,6 @@ using System.Buffers; namespace SixLabors.ImageSharp.Tests { - using SixLabors.ImageSharp.Advanced; - using SixLabors.ImageSharp.PixelFormats; - class TestMemoryManager : MemoryManager where T : struct { From 3ed641f660cc7c99b80cb825ff25ef0c2cecb056 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 22 Jul 2018 19:29:25 +0200 Subject: [PATCH 3/8] FillRegion_WorksOnWrappedMemoryImage --- src/ImageSharp/ImageFrameCollection.cs | 4 ++-- src/ImageSharp/ImageFrame{TPixel}.cs | 8 ++++---- src/ImageSharp/Image{TPixel}.cs | 8 ++++---- .../Advanced/AdvancedImageExtensionsTests.cs | 3 +-- .../Drawing/FillSolidBrushTests.cs | 17 +++++++++++++++++ .../Drawing/SolidBezierTests.cs | 1 + .../ImageSharp.Tests/TestUtilities/TestUtils.cs | 4 ++++ 7 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 4b8f90e9b..3c1062df3 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -30,14 +30,14 @@ namespace SixLabors.ImageSharp this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, backgroundColor)); } - internal ImageFrameCollection(Image parent, int width, int height, Memory consumedBuffer) + internal ImageFrameCollection(Image parent, int width, int height, Memory consumedMemory) { Guard.NotNull(parent, nameof(parent)); this.parent = parent; // Frames are already cloned within the caller - this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, consumedBuffer)); + this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, consumedMemory)); } internal ImageFrameCollection(Image parent, IEnumerable> frames) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 2fa35f1e5..370b3763c 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -95,8 +95,8 @@ namespace SixLabors.ImageSharp /// /// Initializes a new instance of the class wrapping an existing buffer. /// - internal ImageFrame(Configuration configuration, int width, int height, Memory consumedBuffer) - : this(configuration, width, height, consumedBuffer, new ImageFrameMetaData()) + internal ImageFrame(Configuration configuration, int width, int height, Memory consumedMemory) + : this(configuration, width, height, consumedMemory, new ImageFrameMetaData()) { } @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp Configuration configuration, int width, int height, - Memory consumedBuffer, + Memory consumedMemory, ImageFrameMetaData metaData) { Guard.NotNull(configuration, nameof(configuration)); @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp this.configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; - this.PixelBuffer = new Buffer2D(consumedBuffer, width, height); + this.PixelBuffer = new Buffer2D(consumedMemory, width, height); this.MetaData = metaData; } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 9126812dd..316c381c4 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -86,8 +86,8 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the class /// consuming an external buffer instance. /// - internal Image(Configuration configuration, Memory consumedBuffer, int width, int height) - : this(configuration, consumedBuffer, width, height, new ImageMetaData()) + internal Image(Configuration configuration, Memory consumedMemory, int width, int height) + : this(configuration, consumedMemory, width, height, new ImageMetaData()) { } @@ -95,12 +95,12 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the class /// consuming an external buffer instance. /// - internal Image(Configuration configuration, Memory consumedBuffer, int width, int height, ImageMetaData metadata) + internal Image(Configuration configuration, Memory consumedMemory, int width, int height, ImageMetaData metadata) { this.configuration = configuration; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata; - this.frames = new ImageFrameCollection(this, width, height, consumedBuffer); + this.frames = new ImageFrameCollection(this, width, height, consumedMemory); } /// diff --git a/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs b/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs index 366266652..974099991 100644 --- a/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced Memory externalMemory = managerOfExeternalMemory.Memory; - using (Image image1 = Image.WrapMemory(externalMemory, image0.Width, image0.Height)) + using (var image1 = Image.WrapMemory(externalMemory, image0.Width, image0.Height)) { Memory internalMemory = image1.GetPixelMemory(); Assert.Equal(targetBuffer.Length, internalMemory.Length); @@ -72,7 +72,6 @@ namespace SixLabors.ImageSharp.Tests.Advanced image0.ComparePixelBufferTo(externalMemory.Span); } } - } [Theory] diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index 1f01d54f4..45f1340be 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -81,6 +81,23 @@ namespace SixLabors.ImageSharp.Tests.Drawing provider.RunValidatingProcessorTest(c => c.Fill(color, region), testDetails, ImageComparer.Exact); } + [Theory] + [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 5, 7, 3, 8)] + [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 8, 5, 6, 4)] + public void FillRegion_WorksOnWrappedMemoryImage(TestImageProvider provider, int x0, int y0, int w, int h) + where TPixel : struct, IPixel + { + FormattableString testDetails = $"(x{x0},y{y0},w{w},h{h})"; + var region = new RectangleF(x0, y0, w, h); + TPixel color = TestUtils.GetPixelOfNamedColor("Blue"); + + provider.RunValidatingProcessorTestOnWrappedMemoryImage( + c => c.Fill(color, region), + testDetails, + ImageComparer.Exact, + useReferenceOutputFrom: nameof(this.FillRegion)); + } + public static readonly TheoryData BlendData = new TheoryData() { diff --git a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs index 94d3d49ff..23acc1a44 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs @@ -38,6 +38,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing } } + [Theory] [WithBlankImages(500, 500, PixelTypes.Rgba32)] public void OverlayByFilledPolygonOpacity(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index a6ea76f2d..81310c1a0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -228,6 +228,8 @@ namespace SixLabors.ImageSharp.Tests // TODO: Investigate the cause of pixel inaccuracies under Linux if (TestEnvironment.IsWindows) { + string testNameBackup = provider.Utility.TestName; + if (useReferenceOutputFrom != null) { provider.Utility.TestName = useReferenceOutputFrom; @@ -239,6 +241,8 @@ namespace SixLabors.ImageSharp.Tests testOutputDetails, appendPixelTypeToFileName: appendPixelTypeToFileName, appendSourceFileOrDescription: appendSourceFileOrDescription); + + provider.Utility.TestName = testNameBackup; } } } From 7c53bc17850be15b98a77daa0dddb7b00a029213 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 22 Jul 2018 19:54:37 +0200 Subject: [PATCH 4/8] made WrapMemory() public + test case demonstrating using Image.WrapMemory() to draw over a System.Drawing.Bitmap instance --- src/ImageSharp/Image.WrapMemory.cs | 4 +- src/ImageSharp/PixelFormats/Bgra32.cs | 1 + .../Image/ImageTests.WrapMemory.cs | 74 +++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index 3ccd809f4..7f0c4ae2e 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp /// The height of the memory image /// The /// An instance - internal static Image WrapMemory( + public static Image WrapMemory( Configuration config, Memory pixelMemory, int width, @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp /// The width of the memory image /// The height of the memory image /// An instance - internal static Image WrapMemory( + public static Image WrapMemory( Memory pixelMemory, int width, int height) diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index f951be881..14b2da07c 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255. /// The color components are stored in blue, green, red, and alpha order (least significant to most significant byte). + /// The format is binary compatible with System.Drawing.Imaging.PixelFormat.Format32bppArgb /// /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 252dbc869..57f757176 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -2,7 +2,14 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; +using System.Drawing; +using System.Drawing.Imaging; + +using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; +using SixLabors.Shapes; +using SixLabors.ImageSharp.Processing; using Xunit; // ReSharper disable InconsistentNaming @@ -12,6 +19,73 @@ namespace SixLabors.ImageSharp.Tests { public class WrapMemory { + class BitmapMemoryManager : MemoryManager + { + private System.Drawing.Bitmap bitmap; + + private BitmapData bmpData; + + private int length; + + public BitmapMemoryManager(Bitmap bitmap) + { + if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) + { + throw new ArgumentException("bitmap.PixelFormat != PixelFormat.Format32bppArgb", nameof(bitmap)); + } + + this.bitmap = bitmap; + var rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height); + this.bmpData = bitmap.LockBits(rectangle, ImageLockMode.ReadWrite, bitmap.PixelFormat); + this.length = bitmap.Width * bitmap.Height; + } + + protected override void Dispose(bool disposing) + { + this.bitmap.UnlockBits(this.bmpData); + } + + public override unsafe Span GetSpan() + { + void* ptr = (void*) this.bmpData.Scan0; + return new Span(ptr, this.length); + } + + public override unsafe MemoryHandle Pin(int elementIndex = 0) + { + void* ptr = (void*)this.bmpData.Scan0; + return new MemoryHandle(ptr); + } + + public override void Unpin() + { + } + } + + [Fact] + public void WrapSystemDrawingBitmap() + { + using (var bmp = new Bitmap(51, 23)) + { + using (var memoryManager = new BitmapMemoryManager(bmp)) + { + Memory memory = memoryManager.Memory; + Bgra32 bg = NamedColors.Red; + Bgra32 fg = NamedColors.Green; + + using (var image = Image.WrapMemory(memory, bmp.Width, bmp.Height)) + { + image.Mutate(c => c.Fill(bg).Fill(fg, new RectangularPolygon(10, 10, 10, 10))); + } + } + + string fn = System.IO.Path.Combine( + TestEnvironment.ActualOutputDirectoryFullPath, + "WrapSystemDrawingBitmap.bmp"); + + bmp.Save(fn, ImageFormat.Bmp); + } + } } } } \ No newline at end of file From 7f48800cef2b77bc2378ca8a9f5ca7cc9ed871e7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 23 Jul 2018 00:20:14 +0200 Subject: [PATCH 5/8] kick AppVeyor --- build.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 4c5a36cae..35b8344dc 100644 --- a/build.ps1 +++ b/build.ps1 @@ -8,7 +8,7 @@ $tagRegex = '^v?(\d+\.\d+\.\d+)(-([a-zA-Z]+)\.?(\d*))?$' # we are running on the build server $isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex - if($isVersionTag){ + if($isVersionTag) { Write-Debug "Building commit tagged with a compatable version number" @@ -26,7 +26,8 @@ $isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex $version = "${version}${padded}" } - }else { + } + else { Write-Debug "Untagged" $lastTag = (git tag --list --sort=-taggerdate) | Out-String From f1cb97270e57a242e8f51ac292575b38fa193d50 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 24 Jul 2018 00:39:47 +0200 Subject: [PATCH 6/8] renamed BufferManager to MemorySource + enable consuming external IMemoryOwner --- .../Advanced/AdvancedImageExtensions.cs | 2 +- src/ImageSharp/Image.WrapMemory.cs | 5 +- src/ImageSharp/ImageFrameCollection.cs | 4 +- src/ImageSharp/ImageFrame{TPixel}.cs | 8 +-- src/ImageSharp/Image{TPixel}.cs | 15 +--- src/ImageSharp/Memory/Buffer2DExtensions.cs | 4 +- src/ImageSharp/Memory/Buffer2D{T}.cs | 28 +++----- .../Memory/MemoryAllocatorExtensions.cs | 3 +- .../{BufferManager.cs => MemorySource.cs} | 34 ++++++--- .../Processors/Transforms/ResizeProcessor.cs | 2 +- .../Processors/Transforms/WeightsWindow.cs | 4 +- .../Formats/Jpg/JpegColorConverterTests.cs | 3 +- .../Formats/Jpg/SpectralJpegTests.cs | 2 +- .../ImageSharp.Tests/Memory/Buffer2DTests.cs | 14 ++-- ...erManagerTests.cs => MemorySourceTests.cs} | 69 ++++++++++--------- 15 files changed, 101 insertions(+), 96 deletions(-) rename src/ImageSharp/Memory/{BufferManager.cs => MemorySource.cs} (57%) rename tests/ImageSharp.Tests/Memory/{BufferManagerTests.cs => MemorySourceTests.cs} (60%) diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 18b1d994b..1c73b5ed1 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Advanced internal static Memory GetPixelMemory(this ImageFrame source) where TPixel : struct, IPixel { - return source.PixelBuffer.Buffer.Memory; + return source.PixelBuffer.MemorySource.Memory; } /// diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index 7f0c4ae2e..c24a932e1 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -13,8 +13,6 @@ namespace SixLabors.ImageSharp /// public static partial class Image { - // TODO: This is a WIP API, should be public when finished. - /// /// Wraps an existing contigous memory area of 'width'x'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. @@ -34,7 +32,8 @@ namespace SixLabors.ImageSharp ImageMetaData metaData) where TPixel : struct, IPixel { - return new Image(config, pixelMemory, width, height, metaData); + var memorySource = new MemorySource(pixelMemory); + return new Image(config, memorySource, width, height, metaData); } /// diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 3c1062df3..154ef5014 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -30,14 +30,14 @@ namespace SixLabors.ImageSharp this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, backgroundColor)); } - internal ImageFrameCollection(Image parent, int width, int height, Memory consumedMemory) + internal ImageFrameCollection(Image parent, int width, int height, MemorySource memorySource) { Guard.NotNull(parent, nameof(parent)); this.parent = parent; // Frames are already cloned within the caller - this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, consumedMemory)); + this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, memorySource)); } internal ImageFrameCollection(Image parent, IEnumerable> frames) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 370b3763c..6c04d5aea 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -95,8 +95,8 @@ namespace SixLabors.ImageSharp /// /// Initializes a new instance of the class wrapping an existing buffer. /// - internal ImageFrame(Configuration configuration, int width, int height, Memory consumedMemory) - : this(configuration, width, height, consumedMemory, new ImageFrameMetaData()) + internal ImageFrame(Configuration configuration, int width, int height, MemorySource memorySource) + : this(configuration, width, height, memorySource, new ImageFrameMetaData()) { } @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp Configuration configuration, int width, int height, - Memory consumedMemory, + MemorySource memorySource, ImageFrameMetaData metaData) { Guard.NotNull(configuration, nameof(configuration)); @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp this.configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; - this.PixelBuffer = new Buffer2D(consumedMemory, width, height); + this.PixelBuffer = new Buffer2D(memorySource, width, height); this.MetaData = metaData; } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 316c381c4..5a5928d6b 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -84,23 +84,14 @@ namespace SixLabors.ImageSharp /// /// Initializes a new instance of the class - /// consuming an external buffer instance. + /// wrapping an external /// - internal Image(Configuration configuration, Memory consumedMemory, int width, int height) - : this(configuration, consumedMemory, width, height, new ImageMetaData()) - { - } - - /// - /// Initializes a new instance of the class - /// consuming an external buffer instance. - /// - internal Image(Configuration configuration, Memory consumedMemory, int width, int height, ImageMetaData metadata) + internal Image(Configuration configuration, MemorySource memorySource, int width, int height, ImageMetaData metadata) { this.configuration = configuration; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata; - this.frames = new ImageFrameCollection(this, width, height, consumedMemory); + this.frames = new ImageFrameCollection(this, width, height, memorySource); } /// diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index c27752570..be4f0ef15 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -18,7 +18,7 @@ namespace SixLabors.Memory internal static Span GetSpan(this Buffer2D buffer) where T : struct { - return buffer.Buffer.GetSpan(); + return buffer.MemorySource.GetSpan(); } /// @@ -61,7 +61,7 @@ namespace SixLabors.Memory public static Memory GetRowMemory(this Buffer2D buffer, int y) where T : struct { - return buffer.Buffer.Memory.Slice(y * buffer.Width, buffer.Width); + return buffer.MemorySource.Memory.Slice(y * buffer.Width, buffer.Width); } /// diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 7d331b46d..844ca1ad1 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -16,31 +16,21 @@ namespace SixLabors.Memory internal sealed class Buffer2D : IDisposable where T : struct { - private BufferManager buffer; + private MemorySource memorySource; /// /// Initializes a new instance of the class. /// - /// The buffer to wrap + /// The buffer to wrap /// The number of elements in a row /// The number of rows - public Buffer2D(BufferManager wrappedBuffer, int width, int height) + public Buffer2D(MemorySource memorySource, int width, int height) { - this.buffer = wrappedBuffer; + this.memorySource = memorySource; this.Width = width; this.Height = height; } - public Buffer2D(IMemoryOwner ownedMemory, int width, int height) - : this(new BufferManager(ownedMemory), width, height) - { - } - - public Buffer2D(Memory observedMemory, int width, int height) - : this(new BufferManager(observedMemory), width, height) - { - } - /// /// Gets the width. /// @@ -52,11 +42,11 @@ namespace SixLabors.Memory public int Height { get; private set; } /// - /// Gets the backing + /// Gets the backing /// - public BufferManager Buffer => this.buffer; + public MemorySource MemorySource => this.memorySource; - public Memory Memory => this.Buffer.Memory; + public Memory Memory => this.MemorySource.Memory; public Span Span => this.Memory.Span; @@ -83,7 +73,7 @@ namespace SixLabors.Memory /// public void Dispose() { - this.Buffer.Dispose(); + this.MemorySource.Dispose(); } /// @@ -92,7 +82,7 @@ namespace SixLabors.Memory /// public static void SwapOrCopyContent(Buffer2D destination, Buffer2D source) { - BufferManager.SwapOrCopyContent(ref destination.buffer, ref source.buffer); + MemorySource.SwapOrCopyContent(ref destination.memorySource, ref source.memorySource); SwapDimensionData(destination, source); } diff --git a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs index 327bc8bbf..d8c1f51f4 100644 --- a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs +++ b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs @@ -17,8 +17,9 @@ namespace SixLabors.Memory where T : struct { IMemoryOwner buffer = memoryAllocator.Allocate(width * height, options); + var memorySource = new MemorySource(buffer, true); - return new Buffer2D(buffer, width, height); + return new Buffer2D(memorySource, width, height); } public static Buffer2D Allocate2D( diff --git a/src/ImageSharp/Memory/BufferManager.cs b/src/ImageSharp/Memory/MemorySource.cs similarity index 57% rename from src/ImageSharp/Memory/BufferManager.cs rename to src/ImageSharp/Memory/MemorySource.cs index 1a53890d4..27bca11c1 100644 --- a/src/ImageSharp/Memory/BufferManager.cs +++ b/src/ImageSharp/Memory/MemorySource.cs @@ -9,32 +9,50 @@ namespace SixLabors.Memory /// /// Holds a that is either OWNED or CONSUMED. /// Implements content transfer logic in that depends on the ownership status. - /// This is needed to transfer the contents of a temporary to a persistent + /// This is needed to transfer the contents of a temporary + /// to a persistent without copying the buffer. /// /// /// For a deeper understanding of the owner/consumer model, check out the following docs:
/// https://gist.github.com/GrabYourPitchforks/4c3e1935fd4d9fa2831dbfcab35dffc6 /// https://www.codemag.com/Article/1807051/Introducing-.NET-Core-2.1-Flagship-Types-Span-T-and-Memory-T ///
- internal struct BufferManager : IDisposable + internal struct MemorySource : IDisposable { - public BufferManager(IMemoryOwner memoryOwner) + /// + /// Initializes a new instance of the struct + /// by wrapping an existing . + /// + /// The to wrap + /// + /// A value indicating whether is an internal memory source managed by ImageSharp. + /// Eg. allocated by a . + /// + public MemorySource(IMemoryOwner memoryOwner, bool isInternalMemorySource) { this.MemoryOwner = memoryOwner; this.Memory = memoryOwner.Memory; + this.HasSwappableContents = isInternalMemorySource; } - public BufferManager(Memory memory) + public MemorySource(Memory memory) { this.Memory = memory; this.MemoryOwner = null; + this.HasSwappableContents = false; } public IMemoryOwner MemoryOwner { get; private set; } public Memory Memory { get; private set; } - public bool OwnsMemory => this.MemoryOwner != null; + /// + /// Gets a value indicating whether we are allowed to swap the contents of this buffer + /// with an other instance. + /// The value is true only and only if is present, + /// and it's coming from an internal source managed by ImageSharp (). + /// + public bool HasSwappableContents { get; } public Span GetSpan() => this.Memory.Span; @@ -44,9 +62,9 @@ namespace SixLabors.Memory /// Swaps the contents of 'destination' with 'source' if the buffers are owned (1), /// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2! ///
- public static void SwapOrCopyContent(ref BufferManager destination, ref BufferManager source) + public static void SwapOrCopyContent(ref MemorySource destination, ref MemorySource source) { - if (source.OwnsMemory && destination.OwnsMemory) + if (source.HasSwappableContents && destination.HasSwappableContents) { SwapContents(ref destination, ref source); } @@ -67,7 +85,7 @@ namespace SixLabors.Memory this.MemoryOwner?.Dispose(); } - private static void SwapContents(ref BufferManager a, ref BufferManager b) + private static void SwapContents(ref MemorySource a, ref MemorySource b) { IMemoryOwner tempOwner = a.MemoryOwner; Memory tempMemory = a.Memory; diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 7f18faec3..9c09b6a22 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed! using (Buffer2D firstPassPixels = source.MemoryAllocator.Allocate2D(width, source.Height)) { - firstPassPixels.Buffer.Clear(); + firstPassPixels.MemorySource.Clear(); ParallelFor.WithTemporaryBuffer( 0, diff --git a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs b/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs index 19909aaba..6a2b6fbd1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The buffer containing the weights values. /// - private readonly BufferManager buffer; + private readonly MemorySource buffer; /// /// Initializes a new instance of the struct. @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { this.flatStartIndex = (index * buffer.Width) + left; this.Left = left; - this.buffer = buffer.Buffer; + this.buffer = buffer.MemorySource; this.Length = length; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index aed650b8e..8048dd424 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -290,7 +290,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } // no need to dispose when buffer is not array owner - buffers[i] = new Buffer2D(new BasicArrayBuffer(values), values.Length, 1); + var source = new MemorySource(new BasicArrayBuffer(values), true); + buffers[i] = new Buffer2D(source, 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 46a688b49..9ffd42211 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg this.Output.WriteLine($"Component{i}: {diff}"); averageDifference += diff.average; totalDifference += diff.total; - tolerance += libJpegComponent.SpectralBlocks.Buffer.GetSpan().Length; + tolerance += libJpegComponent.SpectralBlocks.MemorySource.GetSpan().Length; } averageDifference /= componentCount; diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 52d3929f6..5753d92b3 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Tests.Memory // Assert.Equal(width * y, span.Start); Assert.Equal(width, span.Length); - Assert.SpanPointsTo(span, buffer.Buffer.MemoryOwner, width * y); + Assert.SpanPointsTo(span, buffer.MemorySource.MemoryOwner, width * y); } } @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Memory // Assert.Equal(width * y + x, span.Start); Assert.Equal(width - x, span.Length); - Assert.SpanPointsTo(span, buffer.Buffer.MemoryOwner, width * y + x); + Assert.SpanPointsTo(span, buffer.MemorySource.MemoryOwner, width * y + x); } } @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Tests.Memory { using (Buffer2D buffer = this.MemoryAllocator.Allocate2D(width, height)) { - Span span = buffer.Buffer.GetSpan(); + Span span = buffer.MemorySource.GetSpan(); ref TestStructs.Foo actual = ref buffer[x, y]; @@ -115,13 +115,13 @@ namespace SixLabors.ImageSharp.Tests.Memory using (Buffer2D a = this.MemoryAllocator.Allocate2D(10, 5)) using (Buffer2D b = this.MemoryAllocator.Allocate2D(3, 7)) { - IMemoryOwner aa = a.Buffer.MemoryOwner; - IMemoryOwner bb = b.Buffer.MemoryOwner; + IMemoryOwner aa = a.MemorySource.MemoryOwner; + IMemoryOwner bb = b.MemorySource.MemoryOwner; Buffer2D.SwapOrCopyContent(a, b); - Assert.Equal(bb, a.Buffer.MemoryOwner); - Assert.Equal(aa, b.Buffer.MemoryOwner); + Assert.Equal(bb, a.MemorySource.MemoryOwner); + Assert.Equal(aa, b.MemorySource.MemoryOwner); Assert.Equal(new Size(3, 7), a.Size()); Assert.Equal(new Size(10, 5), b.Size()); diff --git a/tests/ImageSharp.Tests/Memory/BufferManagerTests.cs b/tests/ImageSharp.Tests/Memory/MemorySourceTests.cs similarity index 60% rename from tests/ImageSharp.Tests/Memory/BufferManagerTests.cs rename to tests/ImageSharp.Tests/Memory/MemorySourceTests.cs index d08e734e8..9cdfb5635 100644 --- a/tests/ImageSharp.Tests/Memory/BufferManagerTests.cs +++ b/tests/ImageSharp.Tests/Memory/MemorySourceTests.cs @@ -12,21 +12,23 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Memory { - public class BufferManagerTests + public class MemorySourceTests { public class Construction { - [Fact] - public void InitializeAsOwner_MemoryOwner_IsPresent() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void InitializeAsOwner(bool isInternalMemorySource) { var data = new Rgba32[21]; var mmg = new TestMemoryManager(data); - var a = new BufferManager(mmg); + var a = new MemorySource(mmg, isInternalMemorySource); Assert.Equal(mmg, a.MemoryOwner); Assert.Equal(mmg.Memory, a.Memory); - Assert.True(a.OwnsMemory); + Assert.Equal(isInternalMemorySource, a.HasSwappableContents); } [Fact] @@ -35,21 +37,23 @@ namespace SixLabors.ImageSharp.Tests.Memory var data = new Rgba32[21]; var mmg = new TestMemoryManager(data); - var a = new BufferManager(mmg.Memory); + var a = new MemorySource(mmg.Memory); Assert.Null(a.MemoryOwner); Assert.Equal(mmg.Memory, a.Memory); - Assert.False(a.OwnsMemory); + Assert.False(a.HasSwappableContents); } } public class Dispose { - [Fact] - public void WhenOwnershipIsTransfered_ShouldDisposeMemoryOwner() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void WhenOwnershipIsTransfered_ShouldDisposeMemoryOwner(bool isInternalMemorySource) { var mmg = new TestMemoryManager(new int[10]); - var bmg = new BufferManager(mmg); + var bmg = new MemorySource(mmg, isInternalMemorySource); bmg.Dispose(); Assert.True(mmg.IsDisposed); @@ -59,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.Memory public void WhenMemoryObserver_ShouldNotDisposeAnything() { var mmg = new TestMemoryManager(new int[10]); - var bmg = new BufferManager(mmg.Memory); + var bmg = new MemorySource(mmg.Memory); bmg.Dispose(); Assert.False(mmg.IsDisposed); @@ -70,18 +74,18 @@ namespace SixLabors.ImageSharp.Tests.Memory { private MemoryAllocator MemoryAllocator { get; } = new TestMemoryAllocator(); - private BufferManager AllocateBufferManager(int length, AllocationOptions options = AllocationOptions.None) + private MemorySource AllocateMemorySource(int length, AllocationOptions options = AllocationOptions.None) where T : struct { - var owner = (IMemoryOwner)this.MemoryAllocator.Allocate(length, options); - return new BufferManager(owner); + IMemoryOwner owner = this.MemoryAllocator.Allocate(length, options); + return new MemorySource(owner, true); } [Fact] public void WhenBothAreMemoryOwners_ShouldSwap() { - BufferManager a = this.AllocateBufferManager(13); - BufferManager b = this.AllocateBufferManager(17); + MemorySource a = this.AllocateMemorySource(13); + MemorySource b = this.AllocateMemorySource(17); IMemoryOwner aa = a.MemoryOwner; IMemoryOwner bb = b.MemoryOwner; @@ -89,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests.Memory Memory aaa = a.Memory; Memory bbb = b.Memory; - BufferManager.SwapOrCopyContent(ref a, ref b); + MemorySource.SwapOrCopyContent(ref a, ref b); Assert.Equal(bb, a.MemoryOwner); Assert.Equal(aa, b.MemoryOwner); @@ -100,26 +104,27 @@ namespace SixLabors.ImageSharp.Tests.Memory } [Theory] - [InlineData(false)] - [InlineData(true)] - public void WhenDestIsNotMemoryOwner_SameSize_ShouldCopy(bool sourceIsOwner) + [InlineData(false, false)] + [InlineData(true, true)] + [InlineData(true, false)] + public void WhenDestIsNotMemoryOwner_SameSize_ShouldCopy(bool sourceIsOwner, bool isInternalMemorySource) { var data = new Rgba32[21]; var color = new Rgba32(1, 2, 3, 4); var destOwner = new TestMemoryManager(data); - var dest = new BufferManager(destOwner.Memory); + var dest = new MemorySource(destOwner.Memory); - var sourceOwner = (IMemoryOwner)this.MemoryAllocator.Allocate(21); + IMemoryOwner sourceOwner = this.MemoryAllocator.Allocate(21); - BufferManager source = sourceIsOwner - ? new BufferManager(sourceOwner) - : new BufferManager(sourceOwner.Memory); + MemorySource source = sourceIsOwner + ? new MemorySource(sourceOwner, isInternalMemorySource) + : new MemorySource(sourceOwner.Memory); sourceOwner.Memory.Span[10] = color; // Act: - BufferManager.SwapOrCopyContent(ref dest, ref source); + MemorySource.SwapOrCopyContent(ref dest, ref source); // Assert: Assert.Equal(color, dest.Memory.Span[10]); @@ -136,18 +141,18 @@ namespace SixLabors.ImageSharp.Tests.Memory var color = new Rgba32(1, 2, 3, 4); var destOwner = new TestMemoryManager(data); - var dest = new BufferManager(destOwner.Memory); + var dest = new MemorySource(destOwner.Memory); - var sourceOwner = (IMemoryOwner)this.MemoryAllocator.Allocate(22); + IMemoryOwner sourceOwner = this.MemoryAllocator.Allocate(22); - BufferManager source = sourceIsOwner - ? new BufferManager(sourceOwner) - : new BufferManager(sourceOwner.Memory); + MemorySource source = sourceIsOwner + ? new MemorySource(sourceOwner, true) + : new MemorySource(sourceOwner.Memory); sourceOwner.Memory.Span[10] = color; // Act: Assert.ThrowsAny( - () => BufferManager.SwapOrCopyContent(ref dest, ref source) + () => MemorySource.SwapOrCopyContent(ref dest, ref source) ); Assert.Equal(color, source.Memory.Span[10]); From f3d41f71a37bf33b2df201595b13adb2263ce3f0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 24 Jul 2018 01:08:41 +0200 Subject: [PATCH 7/8] WrapMemory(IMemoryOwner) + additional System.Drawing test case --- src/ImageSharp/Image.WrapMemory.cs | 95 ++++++++++++++++++- src/ImageSharp/Memory/MemorySource.cs | 1 + .../Image/ImageTests.WrapMemory.cs | 79 +++++++++++++-- 3 files changed, 167 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index c24a932e1..77432c3ad 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; + using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -41,6 +43,27 @@ namespace SixLabors.ImageSharp /// allowing to view/manipulate it as an ImageSharp instance. /// /// The pixel type + /// The + /// The pixel memory + /// The width of the memory image + /// The height of the memory image + /// An instance + public static Image WrapMemory( + Configuration config, + Memory pixelMemory, + int width, + int height) + where TPixel : struct, IPixel + { + return WrapMemory(config, pixelMemory, width, height, new ImageMetaData()); + } + + /// + /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// allowing to view/manipulate it as an ImageSharp instance. + /// The memory is being observed, the caller remains responsible for managing it's lifecycle. + /// + /// The pixel type /// The pixel memory /// The width of the memory image /// The height of the memory image @@ -51,7 +74,77 @@ namespace SixLabors.ImageSharp int height) where TPixel : struct, IPixel { - return WrapMemory(Configuration.Default, pixelMemory, width, height, new ImageMetaData()); + return WrapMemory(Configuration.Default, pixelMemory, width, height); + } + + /// + /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// allowing to view/manipulate it as an ImageSharp instance. + /// The ownership of the is being transfered to the new instance, + /// meaning that the caller is not allowed to dispose . + /// It will be disposed together with the result image. + /// + /// The pixel type + /// The + /// The that is being transfered to the image + /// The width of the memory image + /// The height of the memory image + /// The + /// An instance + public static Image WrapMemory( + Configuration config, + IMemoryOwner pixelMemoryOwner, + int width, + int height, + ImageMetaData metaData) + where TPixel : struct, IPixel + { + var memorySource = new MemorySource(pixelMemoryOwner, false); + return new Image(config, memorySource, width, height, metaData); + } + + /// + /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// allowing to view/manipulate it as an ImageSharp instance. + /// The ownership of the is being transfered to the new instance, + /// meaning that the caller is not allowed to dispose . + /// It will be disposed together with the result image. + /// + /// The pixel type + /// The + /// The that is being transfered to the image + /// The width of the memory image + /// The height of the memory image + /// An instance + public static Image WrapMemory( + Configuration config, + IMemoryOwner pixelMemoryOwner, + int width, + int height) + where TPixel : struct, IPixel + { + return WrapMemory(config, pixelMemoryOwner, width, height, new ImageMetaData()); + } + + /// + /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// allowing to view/manipulate it as an ImageSharp instance. + /// The ownership of the is being transfered to the new instance, + /// meaning that the caller is not allowed to dispose . + /// It will be disposed together with the result image. + /// + /// The pixel type + /// The that is being transfered to the image + /// The width of the memory image + /// The height of the memory image + /// An instance + public static Image WrapMemory( + IMemoryOwner pixelMemoryOwner, + int width, + int height) + where TPixel : struct, IPixel + { + return WrapMemory(Configuration.Default, pixelMemoryOwner, width, height); } } } \ No newline at end of file diff --git a/src/ImageSharp/Memory/MemorySource.cs b/src/ImageSharp/Memory/MemorySource.cs index 27bca11c1..4253307ef 100644 --- a/src/ImageSharp/Memory/MemorySource.cs +++ b/src/ImageSharp/Memory/MemorySource.cs @@ -8,6 +8,7 @@ namespace SixLabors.Memory { /// /// Holds a that is either OWNED or CONSUMED. + /// When the memory is being owned, the instance is also known. /// Implements content transfer logic in that depends on the ownership status. /// This is needed to transfer the contents of a temporary /// to a persistent without copying the buffer. diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 57f757176..815684d84 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -5,9 +5,11 @@ using System; using System.Buffers; using System.Drawing; using System.Drawing.Imaging; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; using SixLabors.Shapes; using SixLabors.ImageSharp.Processing; using Xunit; @@ -19,13 +21,17 @@ namespace SixLabors.ImageSharp.Tests { public class WrapMemory { + /// + /// A exposing the locked pixel memory of a instance. + /// TODO: This should be an example in https://github.com/SixLabors/Samples + /// class BitmapMemoryManager : MemoryManager { - private System.Drawing.Bitmap bitmap; + private readonly Bitmap bitmap; - private BitmapData bmpData; + private readonly BitmapData bmpData; - private int length; + private readonly int length; public BitmapMemoryManager(Bitmap bitmap) { @@ -40,9 +46,21 @@ namespace SixLabors.ImageSharp.Tests this.length = bitmap.Width * bitmap.Height; } + public bool IsDisposed { get; private set; } + protected override void Dispose(bool disposing) { - this.bitmap.UnlockBits(this.bmpData); + if (this.IsDisposed) + { + return; + } + + if (disposing) + { + this.bitmap.UnlockBits(this.bmpData); + } + + this.IsDisposed = true; } public override unsafe Span GetSpan() @@ -63,7 +81,26 @@ namespace SixLabors.ImageSharp.Tests } [Fact] - public void WrapSystemDrawingBitmap() + public void WrapMemory_CreatedImageIsCorrect() + { + Configuration cfg = Configuration.Default.ShallowCopy(); + var metaData = new ImageMetaData(); + + var array = new Rgba32[25]; + var memory = new Memory(array); + + using (var image = Image.WrapMemory(cfg, memory, 5, 5, metaData)) + { + ref Rgba32 pixel0 = ref image.GetPixelSpan()[0]; + Assert.True(Unsafe.AreSame(ref array[0], ref pixel0)); + + Assert.Equal(cfg, image.GetConfiguration()); + Assert.Equal(metaData, image.MetaData); + } + } + + [Fact] + public void WrapSystemDrawingBitmap_WhenObserved() { using (var bmp = new Bitmap(51, 23)) { @@ -75,13 +112,41 @@ namespace SixLabors.ImageSharp.Tests using (var image = Image.WrapMemory(memory, bmp.Width, bmp.Height)) { + Assert.Equal(memory, image.GetPixelMemory()); image.Mutate(c => c.Fill(bg).Fill(fg, new RectangularPolygon(10, 10, 10, 10))); } + + Assert.False(memoryManager.IsDisposed); } string fn = System.IO.Path.Combine( TestEnvironment.ActualOutputDirectoryFullPath, - "WrapSystemDrawingBitmap.bmp"); + $"{nameof(this.WrapSystemDrawingBitmap_WhenObserved)}.bmp"); + + bmp.Save(fn, ImageFormat.Bmp); + } + } + + [Fact] + public void WrapSystemDrawingBitmap_WhenOwned() + { + using (var bmp = new Bitmap(51, 23)) + { + var memoryManager = new BitmapMemoryManager(bmp); + Bgra32 bg = NamedColors.Red; + Bgra32 fg = NamedColors.Green; + + using (var image = Image.WrapMemory(memoryManager, bmp.Width, bmp.Height)) + { + Assert.Equal(memoryManager.Memory, image.GetPixelMemory()); + image.Mutate(c => c.Fill(bg).Fill(fg, new RectangularPolygon(10, 10, 10, 10))); + } + + Assert.True(memoryManager.IsDisposed); + + string fn = System.IO.Path.Combine( + TestEnvironment.ActualOutputDirectoryFullPath, + $"{nameof(this.WrapSystemDrawingBitmap_WhenOwned)}.bmp"); bmp.Save(fn, ImageFormat.Bmp); } From bb2c06718d6fab1fa19654c72ba7dd01f833cae9 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 24 Jul 2018 01:21:24 +0200 Subject: [PATCH 8/8] WhitespaceCop --- src/ImageSharp/Memory/MemorySource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/MemorySource.cs b/src/ImageSharp/Memory/MemorySource.cs index 4253307ef..c0a74b5f8 100644 --- a/src/ImageSharp/Memory/MemorySource.cs +++ b/src/ImageSharp/Memory/MemorySource.cs @@ -21,7 +21,7 @@ namespace SixLabors.Memory internal struct MemorySource : IDisposable { /// - /// Initializes a new instance of the struct + /// Initializes a new instance of the struct /// by wrapping an existing . /// /// The to wrap