Browse Source

Improve robustness of discontiguous Buffer2D

pull/1109/head
Anton Firszov 6 years ago
parent
commit
8bd19cb564
  1. 4
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  2. 6
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  3. 2
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  4. 2
      src/ImageSharp/ImageFrameCollection{TPixel}.cs
  5. 8
      src/ImageSharp/ImageFrame{TPixel}.cs
  6. 62
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  7. 45
      src/ImageSharp/Memory/Buffer2D{T}.cs
  8. 8
      src/ImageSharp/Memory/BufferArea{T}.cs
  9. 10
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
  10. 2
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
  11. 4
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  12. 2
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
  13. 2
      tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs
  14. 2
      tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs
  15. 34
      tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
  16. 2
      tests/ImageSharp.Tests/Memory/BufferAreaTests.cs
  17. 12
      tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs
  18. 2
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

4
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.Advanced
internal static Memory<TPixel> GetPixelMemory<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return source.PixelBuffer.GetMemory();
return source.PixelBuffer.GetSingleMemory();
}
/// <summary>
@ -185,6 +185,6 @@ namespace SixLabors.ImageSharp.Advanced
/// <returns>A reference to the element.</returns>
private static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(IPixelSource<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> ref MemoryMarshal.GetReference(source.PixelBuffer.GetSpan());
=> ref MemoryMarshal.GetReference(source.PixelBuffer.GetSingleSpan());
}
}

6
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -301,11 +301,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
Span<bool> rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span;
if (compression == BmpCompression.RLE8)
{
this.UncompressRle8(width, buffer.GetSpan(), undefinedPixels.GetSpan(), rowsWithUndefinedPixelsSpan);
this.UncompressRle8(width, buffer.GetSingleSpan(), undefinedPixels.GetSingleSpan(), rowsWithUndefinedPixelsSpan);
}
else
{
this.UncompressRle4(width, buffer.GetSpan(), undefinedPixels.GetSpan(), rowsWithUndefinedPixelsSpan);
this.UncompressRle4(width, buffer.GetSingleSpan(), undefinedPixels.GetSingleSpan(), rowsWithUndefinedPixelsSpan);
}
for (int y = 0; y < height; y++)
@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
Span<bool> rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span;
Span<byte> bufferSpan = buffer.GetSpan();
this.UncompressRle24(width, bufferSpan, undefinedPixels.GetSpan(), rowsWithUndefinedPixelsSpan);
this.UncompressRle24(width, bufferSpan, undefinedPixels.GetSingleSpan(), rowsWithUndefinedPixelsSpan);
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);

2
src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
{
Rgba32 color = default;
Buffer2D<TPixel> pixels = image.PixelBuffer;
Span<TPixel> pixelSpan = pixels.GetSpan();
Span<TPixel> pixelSpan = pixels.GetSingleSpan();
int totalPixels = image.Width * image.Height;
int encodedPixels = 0;
while (encodedPixels < totalPixels)

2
src/ImageSharp/ImageFrameCollection{TPixel}.cs

@ -351,7 +351,7 @@ namespace SixLabors.ImageSharp
this.parent.GetConfiguration(),
source.Size(),
source.Metadata.DeepClone());
source.CopyPixelsTo(result.PixelBuffer.GetSpan());
source.CopyPixelsTo(result.PixelBuffer.GetSingleSpan());
return result;
}
}

8
src/ImageSharp/ImageFrame{TPixel}.cs

@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(source, nameof(source));
this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan());
source.PixelBuffer.GetSingleSpan().CopyTo(this.PixelBuffer.GetSingleSpan());
}
/// <summary>
@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp
throw new ArgumentException("ImageFrame<TPixel>.CopyTo(): target must be of the same size!", nameof(target));
}
this.GetPixelSpan().CopyTo(target.GetSpan());
this.GetPixelSpan().CopyTo(target.GetSingleSpan());
}
/// <summary>
@ -216,10 +216,10 @@ namespace SixLabors.ImageSharp
if (typeof(TPixel) == typeof(TDestinationPixel))
{
Span<TPixel> dest1 = MemoryMarshal.Cast<TDestinationPixel, TPixel>(destination);
this.PixelBuffer.GetSpan().CopyTo(dest1);
this.PixelBuffer.GetSingleSpan().CopyTo(dest1);
}
PixelOperations<TPixel>.Instance.To(this.GetConfiguration(), this.PixelBuffer.GetSpan(), destination);
PixelOperations<TPixel>.Instance.To(this.GetConfiguration(), this.PixelBuffer.GetSingleSpan(), destination);
}
/// <inheritdoc/>

62
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -15,59 +15,49 @@ namespace SixLabors.ImageSharp.Memory
public static class Buffer2DExtensions
{
/// <summary>
/// Gets a <see cref="Span{T}"/> to the backing buffer of <paramref name="buffer"/>.
/// Gets a <see cref="Span{T}"/> to the backing data of <paramref name="buffer"/>
/// if the backing group consists of one single contiguous memory buffer.
/// Throws <see cref="InvalidOperationException"/> otherwise.
/// </summary>
/// <param name="buffer">The <see cref="Buffer2D{T}"/>.</param>
/// <typeparam name="T">The value type.</typeparam>
/// <returns>The <see cref="Span{T}"/> referencing the memory area.</returns>
public static Span<T> GetSpan<T>(this Buffer2D<T> buffer)
/// <exception cref="InvalidOperationException">
/// Thrown when the backing group is discontiguous.
/// </exception>
public static Span<T> GetSingleSpan<T>(this Buffer2D<T> buffer)
where T : struct
{
Guard.NotNull(buffer, nameof(buffer));
if (buffer.MemoryGroup.Count > 1)
{
throw new InvalidOperationException("GetSingleSpan is only valid for a single-buffer group!");
}
return buffer.MemoryGroup.Single().Span;
}
/// <summary>
/// Gets the <see cref="Memory{T}"/> holding the backing buffer of <paramref name="buffer"/>.
/// Gets a <see cref="Memory{T}"/> to the backing data of <paramref name="buffer"/>
/// if the backing group consists of one single contiguous memory buffer.
/// Throws <see cref="InvalidOperationException"/> otherwise.
/// </summary>
/// <param name="buffer">The <see cref="Buffer2D{T}"/>.</param>
/// <typeparam name="T">The value type.</typeparam>
/// <returns>The <see cref="Memory{T}"/>.</returns>
public static Memory<T> GetMemory<T>(this Buffer2D<T> buffer)
where T : struct
{
Guard.NotNull(buffer, nameof(buffer));
return buffer.MemoryGroup.Single();
}
/// <summary>
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
/// </summary>
/// <param name="buffer">The buffer</param>
/// <param name="y">The y (row) coordinate</param>
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> GetRowSpan<T>(this Buffer2D<T> buffer, int y)
/// <exception cref="InvalidOperationException">
/// Thrown when the backing group is discontiguous.
/// </exception>
public static Memory<T> GetSingleMemory<T>(this Buffer2D<T> buffer)
where T : struct
{
Guard.NotNull(buffer, nameof(buffer));
return buffer.MemoryGroup.GetBoundedSlice(y * buffer.Width, buffer.Width).Span;
}
if (buffer.MemoryGroup.Count > 1)
{
throw new InvalidOperationException("GetSingleMemory is only valid for a single-buffer group!");
}
/// <summary>
/// Gets a <see cref="Memory{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
/// </summary>
/// <param name="buffer">The buffer</param>
/// <param name="y">The y (row) coordinate</param>
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> GetRowMemory<T>(this Buffer2D<T> buffer, int y)
where T : struct
{
Guard.NotNull(buffer, nameof(buffer));
return buffer.MemoryGroup.GetBoundedSlice(y * buffer.Width, buffer.Width);
return buffer.MemoryGroup.Single();
}
/// <summary>
@ -93,7 +83,7 @@ namespace SixLabors.ImageSharp.Memory
int dOffset = destIndex * elementSize;
long count = columnCount * elementSize;
Span<byte> span = MemoryMarshal.AsBytes(buffer.GetMemory().Span);
Span<byte> span = MemoryMarshal.AsBytes(buffer.GetSingleMemory().Span);
fixed (byte* ptr = span)
{
@ -153,7 +143,7 @@ namespace SixLabors.ImageSharp.Memory
internal static Span<T> GetMultiRowSpan<T>(this Buffer2D<T> buffer, in RowInterval rows)
where T : struct
{
return buffer.GetSpan().Slice(rows.Min * buffer.Width, rows.Height * buffer.Width);
return buffer.GetSingleSpan().Slice(rows.Min * buffer.Width, rows.Height * buffer.Width);
}
/// <summary>

45
src/ImageSharp/Memory/Buffer2D{T}.cs

@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Memory
public sealed class Buffer2D<T> : IDisposable
where T : struct
{
private Memory<T> cachedMemory = default;
/// <summary>
/// Initializes a new instance of the <see cref="Buffer2D{T}"/> class.
/// </summary>
@ -28,6 +30,11 @@ namespace SixLabors.ImageSharp.Memory
this.MemoryGroup = memoryGroup;
this.Width = width;
this.Height = height;
if (memoryGroup.Count == 1)
{
this.cachedMemory = memoryGroup[0];
}
}
/// <summary>
@ -63,12 +70,39 @@ namespace SixLabors.ImageSharp.Memory
}
}
/// <summary>
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
/// </summary>
/// <param name="y">The y (row) coordinate.</param>
/// <returns>The <see cref="Span{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> GetRowSpan(int y)
{
return this.cachedMemory.Length > 0
? this.cachedMemory.Span.Slice(y * this.Width, this.Width)
: this.GetRowMemorySlow(y).Span;
}
/// <summary>
/// Gets a <see cref="Memory{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
/// </summary>
/// <param name="y">The y (row) coordinate.</param>
/// <returns>The <see cref="Span{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Memory<T> GetRowMemory(int y)
{
return this.cachedMemory.Length > 0
? this.cachedMemory.Slice(y * this.Width, this.Width)
: this.GetRowMemorySlow(y);
}
/// <summary>
/// Disposes the <see cref="Buffer2D{T}"/> instance
/// </summary>
public void Dispose()
{
this.MemoryGroup.Dispose();
this.cachedMemory = default;
}
/// <summary>
@ -78,10 +112,13 @@ namespace SixLabors.ImageSharp.Memory
internal static void SwapOrCopyContent(Buffer2D<T> destination, Buffer2D<T> source)
{
MemoryGroup<T>.SwapOrCopyContent(destination.MemoryGroup, source.MemoryGroup);
SwapDimensionData(destination, source);
SwapOwnData(destination, source);
}
private static void SwapDimensionData(Buffer2D<T> a, Buffer2D<T> b)
[MethodImpl(InliningOptions.ColdPath)]
private Memory<T> GetRowMemorySlow(int y) => this.MemoryGroup.GetBoundedSlice(y * this.Width, this.Width);
private static void SwapOwnData(Buffer2D<T> a, Buffer2D<T> b)
{
Size aSize = a.Size();
Size bSize = b.Size();
@ -91,6 +128,10 @@ namespace SixLabors.ImageSharp.Memory
a.Width = bSize.Width;
a.Height = bSize.Height;
Memory<T> aCached = a.cachedMemory;
a.cachedMemory = b.cachedMemory;
b.cachedMemory = aCached;
}
}
}

8
src/ImageSharp/Memory/BufferArea{T}.cs

@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Memory
/// <param name="x">The position inside a row</param>
/// <param name="y">The row index</param>
/// <returns>The reference to the value</returns>
public ref T this[int x, int y] => ref this.DestinationBuffer.GetSpan()[this.GetIndexOf(x, y)];
public ref T this[int x, int y] => ref this.DestinationBuffer.GetSingleSpan()[this.GetIndexOf(x, y)];
/// <summary>
/// Gets a reference to the [0,0] element.
@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Memory
/// <returns>The reference to the [0,0] element</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T GetReferenceToOrigin() =>
ref this.DestinationBuffer.GetSpan()[(this.Rectangle.Y * this.DestinationBuffer.Width) + this.Rectangle.X];
ref this.DestinationBuffer.GetSingleSpan()[(this.Rectangle.Y * this.DestinationBuffer.Width) + this.Rectangle.X];
/// <summary>
/// Gets a span to row 'y' inside this area.
@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Memory
int xx = this.Rectangle.X;
int width = this.Rectangle.Width;
return this.DestinationBuffer.GetSpan().Slice(yy + xx, width);
return this.DestinationBuffer.GetSingleSpan().Slice(yy + xx, width);
}
/// <summary>
@ -148,7 +148,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.GetSpan().Clear();
this.DestinationBuffer.GetSingleSpan().Clear();
return;
}

10
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs

@ -6,6 +6,7 @@ using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Memory
{
@ -69,15 +70,22 @@ namespace SixLabors.ImageSharp.Memory
{
Guard.NotNull(allocator, nameof(allocator));
Guard.MustBeGreaterThanOrEqualTo(totalLength, 0, nameof(totalLength));
Guard.MustBeGreaterThan(bufferAlignment, 0, nameof(bufferAlignment));
Guard.MustBeGreaterThanOrEqualTo(bufferAlignment, 0, nameof(bufferAlignment));
int blockCapacityInElements = allocator.GetBufferCapacityInBytes() / ElementSize;
if (bufferAlignment > blockCapacityInElements)
{
throw new InvalidMemoryOperationException(
$"The buffer capacity of the provided MemoryAllocator is insufficient for the requested buffer alignment: {bufferAlignment}.");
}
if (totalLength == 0)
{
var buffers0 = new IMemoryOwner<T>[1] { allocator.Allocate<T>(0, options) };
return new Owned(buffers0, 0, 0, true);
}
int numberOfAlignedSegments = blockCapacityInElements / bufferAlignment;
int bufferLength = numberOfAlignedSegments * bufferAlignment;
if (totalLength > 0 && totalLength < bufferLength)

2
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs

@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.DestinationLength = destinationLength;
this.MaxDiameter = (radius * 2) + 1;
this.data = memoryAllocator.Allocate2D<float>(this.MaxDiameter, bufferHeight, AllocationOptions.Clean);
this.pinHandle = this.data.GetMemory().Pin();
this.pinHandle = this.data.GetSingleMemory().Pin();
this.kernels = new ResizeKernel[destinationLength];
this.tempValues = new double[this.MaxDiameter];
}

4
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public void FillDestinationPixels(RowInterval rowInterval, Buffer2D<TPixel> destination)
{
Span<Vector4> tempColSpan = this.tempColumnBuffer.GetSpan();
Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.GetSpan();
Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.GetSingleSpan();
for (int y = rowInterval.Min; y < rowInterval.Max; y++)
{
@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private void CalculateFirstPassValues(RowInterval calculationInterval)
{
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.GetSpan();
Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.GetSingleSpan();
for (int y = calculationInterval.Min; y < calculationInterval.Max; y++)
{

2
tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs

@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.Output.WriteLine($"Component{i}: {diff}");
averageDifference += diff.average;
totalDifference += diff.total;
tolerance += libJpegComponent.SpectralBlocks.GetSpan().Length;
tolerance += libJpegComponent.SpectralBlocks.GetSingleSpan().Length;
}
averageDifference /= componentCount;

2
tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs

@ -330,7 +330,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
});
// Assert:
TestImageExtensions.CompareBuffers(expected.GetSpan(), actual.GetSpan());
TestImageExtensions.CompareBuffers(expected.GetSingleSpan(), actual.GetSingleSpan());
}
}

2
tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs

@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
Span<int> span = buffer.GetMultiRowSpan(rows);
ref int expected0 = ref buffer.GetSpan()[min * width];
ref int expected0 = ref buffer.GetSingleSpan()[min * width];
int expectedLength = (max - min) * width;
ref int actual0 = ref span[0];

34
tests/ImageSharp.Tests/Memory/Buffer2DTests.cs

@ -50,12 +50,30 @@ namespace SixLabors.ImageSharp.Tests.Memory
}
}
[Theory]
[InlineData(Big, 0, 42)]
[InlineData(Big, 1, 0)]
[InlineData(60, 42, 0)]
[InlineData(3, 0, 0)]
public unsafe void Construct_Empty(int bufferCapacity, int width, int height)
{
this.MemoryAllocator.BufferCapacityInBytes = sizeof(TestStructs.Foo) * bufferCapacity;
using (Buffer2D<TestStructs.Foo> buffer = this.MemoryAllocator.Allocate2D<TestStructs.Foo>(width, height))
{
Assert.Equal(width, buffer.Width);
Assert.Equal(height, buffer.Height);
Assert.Equal(0, buffer.MemoryGroup.TotalLength);
Assert.Equal(0, buffer.GetSingleSpan().Length);
}
}
[Fact]
public void CreateClean()
{
using (Buffer2D<int> buffer = this.MemoryAllocator.Allocate2D<int>(42, 42, AllocationOptions.Clean))
{
Span<int> span = buffer.GetSpan();
Span<int> span = buffer.GetSingleSpan();
for (int j = 0; j < span.Length; j++)
{
Assert.Equal(0, span[j]);
@ -114,9 +132,12 @@ namespace SixLabors.ImageSharp.Tests.Memory
[Fact]
public void SwapOrCopyContent()
{
using (Buffer2D<int> a = this.MemoryAllocator.Allocate2D<int>(10, 5))
using (Buffer2D<int> b = this.MemoryAllocator.Allocate2D<int>(3, 7))
using (Buffer2D<int> a = this.MemoryAllocator.Allocate2D<int>(10, 5, AllocationOptions.Clean))
using (Buffer2D<int> b = this.MemoryAllocator.Allocate2D<int>(3, 7, AllocationOptions.Clean))
{
a[1, 3] = 666;
b[1, 3] = 444;
Memory<int> aa = a.MemoryGroup.Single();
Memory<int> bb = b.MemoryGroup.Single();
@ -127,6 +148,9 @@ namespace SixLabors.ImageSharp.Tests.Memory
Assert.Equal(new Size(3, 7), a.Size());
Assert.Equal(new Size(10, 5), b.Size());
Assert.Equal(666, b[1, 3]);
Assert.Equal(444, a[1, 3]);
}
}
@ -142,7 +166,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
var rnd = new Random(123);
using (Buffer2D<float> b = this.MemoryAllocator.Allocate2D<float>(width, height))
{
rnd.RandomFill(b.GetSpan(), 0, 1);
rnd.RandomFill(b.GetSingleSpan(), 0, 1);
b.CopyColumns(startIndex, destIndex, columnCount);
@ -164,7 +188,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
var rnd = new Random(123);
using (Buffer2D<float> b = this.MemoryAllocator.Allocate2D<float>(100, 100))
{
rnd.RandomFill(b.GetSpan(), 0, 1);
rnd.RandomFill(b.GetSingleSpan(), 0, 1);
b.CopyColumns(0, 50, 22);
b.CopyColumns(0, 50, 22);

2
tests/ImageSharp.Tests/Memory/BufferAreaTests.cs

@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
using (Buffer2D<int> buffer = CreateTestBuffer(22, 13))
{
buffer.GetArea().Clear();
Span<int> fullSpan = buffer.GetSpan();
Span<int> fullSpan = buffer.GetSingleSpan();
Assert.True(fullSpan.SequenceEqual(new int[fullSpan.Length]));
}
}

12
tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs

@ -21,7 +21,10 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers
{ default(S5), 22, 4, 7, 2, 4, 3 },
{ default(S5), 22, 4, 8, 2, 4, 4 },
{ default(S5), 22, 4, 21, 6, 4, 1 },
{ default(S5), 22, 4, 0, 0, 4, -1 },
// empty:
{ default(S5), 22, 0, 0, 1, -1, 0 },
{ default(S5), 22, 4, 0, 1, -1, 0 },
{ default(S4), 50, 12, 12, 1, 12, 12 },
{ default(S4), 50, 7, 12, 2, 7, 5 },
@ -61,7 +64,12 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers
// Assert:
Assert.Equal(expectedNumberOfBuffers, g.Count);
Assert.Equal(expectedBufferSize, g.BufferLength);
if (expectedBufferSize >= 0)
{
Assert.Equal(expectedBufferSize, g.BufferLength);
}
if (g.Count == 0)
{
return;

2
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -672,7 +672,7 @@ namespace SixLabors.ImageSharp.Tests
Span<Rgba32> pixels = image.Frames.RootFrame.GetPixelSpan();
Span<float> bufferSpan = buffer.GetSpan();
Span<float> bufferSpan = buffer.GetSingleSpan();
for (int i = 0; i < bufferSpan.Length; i++)
{

Loading…
Cancel
Save