diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 6bd65022e..a988e22b2 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Advanced /// public static IMemoryGroup GetPixelMemoryGroup(this ImageFrame source) where TPixel : struct, IPixel - => source?.PixelBuffer.MemoryGroup.View ?? throw new ArgumentNullException(nameof(source)); + => source?.PixelBuffer.FastMemoryGroup.View ?? throw new ArgumentNullException(nameof(source)); /// /// Gets the representation of the pixels as a containing the backing pixel data of the image diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index e6bcae45c..5c19a4239 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp { Buffer2D uninitializedMemoryBuffer = configuration.MemoryAllocator.Allocate2D(width, height); - return new Image(configuration, uninitializedMemoryBuffer.MemoryGroup, width, height, metadata); + return new Image(configuration, uninitializedMemoryBuffer.FastMemoryGroup, width, height, metadata); } /// diff --git a/src/ImageSharp/Image.LoadPixelData.cs b/src/ImageSharp/Image.LoadPixelData.cs index 1fd5984a1..c655a87d0 100644 --- a/src/ImageSharp/Image.LoadPixelData.cs +++ b/src/ImageSharp/Image.LoadPixelData.cs @@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp var image = new Image(config, width, height); data = data.Slice(0, count); - data.CopyTo(image.Frames.RootFrame.PixelBuffer.MemoryGroup); + data.CopyTo(image.Frames.RootFrame.PixelBuffer.FastMemoryGroup); return image; } diff --git a/src/ImageSharp/ImageFrame.LoadPixelData.cs b/src/ImageSharp/ImageFrame.LoadPixelData.cs index 5b4b3442a..837305d62 100644 --- a/src/ImageSharp/ImageFrame.LoadPixelData.cs +++ b/src/ImageSharp/ImageFrame.LoadPixelData.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp var image = new ImageFrame(configuration, width, height); data = data.Slice(0, count); - data.CopyTo(image.PixelBuffer.MemoryGroup); + data.CopyTo(image.PixelBuffer.FastMemoryGroup); return image; } diff --git a/src/ImageSharp/ImageFrameCollection{TPixel}.cs b/src/ImageSharp/ImageFrameCollection{TPixel}.cs index f6c19eb5c..b7f1d1bb6 100644 --- a/src/ImageSharp/ImageFrameCollection{TPixel}.cs +++ b/src/ImageSharp/ImageFrameCollection{TPixel}.cs @@ -351,7 +351,7 @@ namespace SixLabors.ImageSharp this.parent.GetConfiguration(), source.Size(), source.Metadata.DeepClone()); - source.CopyPixelsTo(result.PixelBuffer.MemoryGroup); + source.CopyPixelsTo(result.PixelBuffer.FastMemoryGroup); return result; } } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 180865834..85488c12d 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(source, nameof(source)); this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); - source.PixelBuffer.MemoryGroup.CopyTo(this.PixelBuffer.MemoryGroup); + source.PixelBuffer.FastMemoryGroup.CopyTo(this.PixelBuffer.FastMemoryGroup); } /// @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp throw new ArgumentException("ImageFrame.CopyTo(): target must be of the same size!", nameof(target)); } - this.PixelBuffer.MemoryGroup.CopyTo(target.MemoryGroup); + this.PixelBuffer.FastMemoryGroup.CopyTo(target.FastMemoryGroup); } /// @@ -222,7 +222,7 @@ namespace SixLabors.ImageSharp { if (typeof(TPixel) == typeof(TDestinationPixel)) { - this.PixelBuffer.MemoryGroup.TransformTo(destination, (s, d) => + this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d) => { Span d1 = MemoryMarshal.Cast(d); s.CopyTo(d1); @@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp return; } - this.PixelBuffer.MemoryGroup.TransformTo(destination, (s, d) => + this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d) => { PixelOperations.Instance.To(this.GetConfiguration(), s, d); }); @@ -291,7 +291,7 @@ namespace SixLabors.ImageSharp /// The value to initialize the bitmap with. internal void Clear(TPixel value) { - MemoryGroup group = this.PixelBuffer.MemoryGroup; + MemoryGroup group = this.PixelBuffer.FastMemoryGroup; if (value.Equals(default)) { diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index b9a3d1d24..8b0f3845e 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Memory where T : struct { Guard.NotNull(buffer, nameof(buffer)); - return buffer.MemoryGroup.View; + return buffer.FastMemoryGroup.View; } /// @@ -42,12 +42,12 @@ namespace SixLabors.ImageSharp.Memory where T : struct { Guard.NotNull(buffer, nameof(buffer)); - if (buffer.MemoryGroup.Count > 1) + if (buffer.FastMemoryGroup.Count > 1) { throw new InvalidOperationException("GetSingleSpan is only valid for a single-buffer group!"); } - return buffer.MemoryGroup.Single().Span; + return buffer.FastMemoryGroup.Single().Span; } /// @@ -65,12 +65,12 @@ namespace SixLabors.ImageSharp.Memory where T : struct { Guard.NotNull(buffer, nameof(buffer)); - if (buffer.MemoryGroup.Count > 1) + if (buffer.FastMemoryGroup.Count > 1) { throw new InvalidOperationException("GetSingleMemory is only valid for a single-buffer group!"); } - return buffer.MemoryGroup.Single(); + return buffer.FastMemoryGroup.Single(); } /// diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 831d40641..f22b9a875 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Memory /// The number of rows. internal Buffer2D(MemoryGroup memoryGroup, int width, int height) { - this.MemoryGroup = memoryGroup; + this.FastMemoryGroup = memoryGroup; this.Width = width; this.Height = height; @@ -49,14 +49,20 @@ namespace SixLabors.ImageSharp.Memory public int Height { get; private set; } /// - /// Gets the backing . + /// Gets the backing . + /// + /// The MemoryGroup. + public IMemoryGroup MemoryGroup => this.FastMemoryGroup.View; + + /// + /// Gets the backing without the view abstraction. /// /// /// This property has been kept internal intentionally. - /// It's public counterpart is , + /// It's public counterpart is , /// which only exposes the view of the MemoryGroup. /// - internal MemoryGroup MemoryGroup { get; } + internal MemoryGroup FastMemoryGroup { get; } /// /// Gets a reference to the element at the specified position. @@ -64,9 +70,10 @@ namespace SixLabors.ImageSharp.Memory /// The x coordinate (row) /// The y coordinate (position at row) /// A reference to the element. - internal ref T this[int x, int y] + /// When index is out of range of the buffer. + public ref T this[int x, int y] { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get { DebugGuard.MustBeGreaterThanOrEqualTo(x, 0, nameof(x)); @@ -83,7 +90,7 @@ namespace SixLabors.ImageSharp.Memory /// public void Dispose() { - this.MemoryGroup.Dispose(); + this.FastMemoryGroup.Dispose(); this.cachedMemory = default; } @@ -148,7 +155,7 @@ namespace SixLabors.ImageSharp.Memory { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); - return this.MemoryGroup.View.GetBoundedSlice(y * this.Width, this.Width); + return this.FastMemoryGroup.View.GetBoundedSlice(y * this.Width, this.Width); } /// @@ -157,12 +164,12 @@ namespace SixLabors.ImageSharp.Memory /// internal static void SwapOrCopyContent(Buffer2D destination, Buffer2D source) { - bool swap = MemoryGroup.SwapOrCopyContent(destination.MemoryGroup, source.MemoryGroup); + bool swap = MemoryGroup.SwapOrCopyContent(destination.FastMemoryGroup, source.FastMemoryGroup); SwapOwnData(destination, source, swap); } [MethodImpl(InliningOptions.ColdPath)] - private Memory GetRowMemorySlow(int y) => this.MemoryGroup.GetBoundedSlice(y * this.Width, this.Width); + private Memory GetRowMemorySlow(int y) => this.FastMemoryGroup.GetBoundedSlice(y * this.Width, this.Width); [MethodImpl(InliningOptions.ColdPath)] private ref T GetElementSlow(int x, int y) diff --git a/src/ImageSharp/Memory/BufferArea{T}.cs b/src/ImageSharp/Memory/BufferArea{T}.cs index b9210e301..f5cbc6953 100644 --- a/src/ImageSharp/Memory/BufferArea{T}.cs +++ b/src/ImageSharp/Memory/BufferArea{T}.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Memory int xx = this.Rectangle.X; int width = this.Rectangle.Width; - return this.DestinationBuffer.MemoryGroup.GetBoundedSlice(yy + xx, width).Span; + return this.DestinationBuffer.FastMemoryGroup.GetBoundedSlice(yy + xx, width).Span; } /// @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.Memory // Optimization for when the size of the area is the same as the buffer size. if (this.IsFullBufferArea) { - this.DestinationBuffer.MemoryGroup.Clear(); + this.DestinationBuffer.FastMemoryGroup.Clear(); return; } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs index 50987d2cd..f1fe4ed9c 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Memory internal abstract partial class MemoryGroup { // Analogous to the "consumed" variant of MemorySource - private class Consumed : MemoryGroup + private sealed class Consumed : MemoryGroup { private readonly Memory[] source; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index d7d484ceb..b42b90d28 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Memory // Analogous to the "owned" variant of MemorySource internal abstract partial class MemoryGroup { - private class Owned : MemoryGroup + private sealed class Owned : MemoryGroup { private IMemoryOwner[] memoryOwners; @@ -25,6 +25,8 @@ namespace SixLabors.ImageSharp.Memory public bool Swappable { get; } + private bool IsDisposed => this.memoryOwners == null; + public override int Count { get @@ -51,7 +53,7 @@ namespace SixLabors.ImageSharp.Memory public override void Dispose() { - if (this.memoryOwners == null) + if (this.IsDisposed) { return; } diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index ea3419741..ab04b3700 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -46,8 +46,8 @@ namespace SixLabors.ImageSharp.Tests.Memory { Assert.Equal(width, buffer.Width); Assert.Equal(height, buffer.Height); - Assert.Equal(width * height, buffer.MemoryGroup.TotalLength); - Assert.True(buffer.MemoryGroup.BufferLength % width == 0); + Assert.Equal(width * height, buffer.FastMemoryGroup.TotalLength); + Assert.True(buffer.FastMemoryGroup.BufferLength % width == 0); } } @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Memory { Assert.Equal(width, buffer.Width); Assert.Equal(height, buffer.Height); - Assert.Equal(0, buffer.MemoryGroup.TotalLength); + Assert.Equal(0, buffer.FastMemoryGroup.TotalLength); Assert.Equal(0, buffer.GetSingleSpan().Length); } } @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Memory this.MemoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity; using Buffer2D buffer = this.MemoryAllocator.Allocate2DOveraligned(width, height, alignmentMultiplier); - MemoryGroup memoryGroup = buffer.MemoryGroup; + MemoryGroup memoryGroup = buffer.FastMemoryGroup; int expectedAlignment = width * alignmentMultiplier; Assert.Equal(expectedAlignment, memoryGroup.BufferLength); @@ -113,8 +113,8 @@ namespace SixLabors.ImageSharp.Tests.Memory Assert.Equal(width, span.Length); - int expectedSubBufferOffset = (width * y) - (expectedBufferIndex * buffer.MemoryGroup.BufferLength); - Assert.SpanPointsTo(span, buffer.MemoryGroup[expectedBufferIndex], expectedSubBufferOffset); + int expectedSubBufferOffset = (width * y) - (expectedBufferIndex * buffer.FastMemoryGroup.BufferLength); + Assert.SpanPointsTo(span, buffer.FastMemoryGroup[expectedBufferIndex], expectedSubBufferOffset); } } @@ -172,10 +172,10 @@ namespace SixLabors.ImageSharp.Tests.Memory using (Buffer2D buffer = this.MemoryAllocator.Allocate2D(width, height)) { - int bufferIndex = (width * y) / buffer.MemoryGroup.BufferLength; - int subBufferStart = (width * y) - (bufferIndex * buffer.MemoryGroup.BufferLength); + int bufferIndex = (width * y) / buffer.FastMemoryGroup.BufferLength; + int subBufferStart = (width * y) - (bufferIndex * buffer.FastMemoryGroup.BufferLength); - Span span = buffer.MemoryGroup[bufferIndex].Span.Slice(subBufferStart); + Span span = buffer.FastMemoryGroup[bufferIndex].Span.Slice(subBufferStart); ref TestStructs.Foo actual = ref buffer[x, y]; @@ -194,13 +194,13 @@ namespace SixLabors.ImageSharp.Tests.Memory a[1, 3] = 666; b[1, 3] = 444; - Memory aa = a.MemoryGroup.Single(); - Memory bb = b.MemoryGroup.Single(); + Memory aa = a.FastMemoryGroup.Single(); + Memory bb = b.FastMemoryGroup.Single(); Buffer2D.SwapOrCopyContent(a, b); - Assert.Equal(bb, a.MemoryGroup.Single()); - Assert.Equal(aa, b.MemoryGroup.Single()); + Assert.Equal(bb, a.FastMemoryGroup.Single()); + Assert.Equal(aa, b.FastMemoryGroup.Single()); Assert.Equal(new Size(3, 7), a.Size()); Assert.Equal(new Size(10, 5), b.Size()); @@ -287,5 +287,18 @@ namespace SixLabors.ImageSharp.Tests.Memory } } } + + [Fact] + public void PublicMemoryGroup_IsMemoryGroupView() + { + using Buffer2D buffer1 = this.MemoryAllocator.Allocate2D(10, 10); + using Buffer2D buffer2 = this.MemoryAllocator.Allocate2D(10, 10); + IMemoryGroup mgBefore = buffer1.MemoryGroup; + + Buffer2D.SwapOrCopyContent(buffer1, buffer2); + + Assert.False(mgBefore.IsValid); + Assert.NotSame(mgBefore, buffer1.MemoryGroup); + } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 179680e1a..f8aa04827 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests Image image = base.GetImage(); Color color = new Rgba32(this.r, this.g, this.b, this.a); - image.GetRootFramePixelBuffer().MemoryGroup.Fill(color.ToPixel()); + image.GetRootFramePixelBuffer().FastMemoryGroup.Fill(color.ToPixel()); return image; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index e492efb25..576ae1d9f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { using var magickImage = new MagickImage(stream); var result = new Image(configuration, magickImage.Width, magickImage.Height); - MemoryGroup resultPixels = result.GetRootFramePixelBuffer().MemoryGroup; + MemoryGroup resultPixels = result.GetRootFramePixelBuffer().FastMemoryGroup; using (IPixelCollection pixels = magickImage.GetPixelsUnsafe()) {