diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs
index d9767d45ea..92687a5630 100644
--- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs
+++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs
@@ -5,6 +5,7 @@ using System;
using System.ComponentModel;
using System.Numerics;
using System.Runtime.CompilerServices;
+// ReSharper disable CompareOfFloatsByEqualityOperator
namespace SixLabors.ImageSharp.ColorSpaces
{
@@ -143,7 +144,8 @@ namespace SixLabors.ImageSharp.ColorSpaces
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieXyChromaticityCoordinates other)
{
- return this.backingVector.Equals(other.backingVector);
+ // The memberwise comparison here is a workaround for https://github.com/dotnet/coreclr/issues/16443
+ return this.X == other.X && this.Y == other.Y;
}
///
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index b4db7527d0..201c041a24 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -343,15 +343,17 @@ namespace SixLabors.ImageSharp.Formats.Bmp
padding = 4 - padding;
}
- using (var row = this.configuration.MemoryManager.Allocate(arrayWidth + padding, true))
+ using (IManagedByteBuffer row = this.configuration.MemoryManager.AllocateManagedByteBuffer(arrayWidth + padding, true))
{
var color = default(TPixel);
var rgba = new Rgba32(0, 0, 0, 255);
+ Span rowSpan = row.Span;
+
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
- this.currentStream.Read(row.Array, 0, row.Length);
+ this.currentStream.Read(row.Array, 0, row.Length());
int offset = 0;
Span pixelRow = pixels.GetRowSpan(newY);
@@ -362,7 +364,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int shift = 0; shift < ppb && (x + shift) < width; shift++)
{
- int colorIndex = ((row[offset] >> (8 - bits - (shift * bits))) & mask) * 4;
+ int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4;
int newX = colOffset + shift;
// Stored in b-> g-> r order.
@@ -393,7 +395,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
var color = default(TPixel);
var rgba = new Rgba32(0, 0, 0, 255);
- using (var buffer = this.configuration.MemoryManager.Allocate(stride))
+ using (var buffer = this.configuration.MemoryManager.AllocateManagedByteBuffer(stride))
{
for (int y = 0; y < height; y++)
{
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index c120c9e113..c35d506dfe 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
/// The global color table.
///
- private Buffer globalColorTable;
+ private IManagedByteBuffer globalColorTable;
///
/// The global color table length
@@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
break;
}
- this.globalColorTable = this.MemoryManager.Allocate(this.globalColorTableLength, true);
+ this.globalColorTable = this.MemoryManager.AllocateManagedByteBuffer(this.globalColorTableLength, true);
nextFlag = stream.ReadByte();
if (nextFlag == -1)
@@ -337,7 +337,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
continue;
}
- using (Buffer commentsBuffer = this.MemoryManager.Allocate(length))
+ using (IManagedByteBuffer commentsBuffer = this.MemoryManager.AllocateManagedByteBuffer(length))
{
this.currentStream.Read(commentsBuffer.Array, 0, length);
string comments = this.TextEncoding.GetString(commentsBuffer.Array, 0, length);
@@ -357,22 +357,23 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
GifImageDescriptor imageDescriptor = this.ReadImageDescriptor();
- Buffer localColorTable = null;
- Buffer indices = null;
+ IManagedByteBuffer localColorTable = null;
+ IManagedByteBuffer indices = null;
try
{
// Determine the color table for this frame. If there is a local one, use it otherwise use the global color table.
if (imageDescriptor.LocalColorTableFlag)
{
int length = imageDescriptor.LocalColorTableSize * 3;
- localColorTable = this.configuration.MemoryManager.Allocate(length, true);
+ localColorTable = this.configuration.MemoryManager.AllocateManagedByteBuffer(length, true);
this.currentStream.Read(localColorTable.Array, 0, length);
}
- indices = this.configuration.MemoryManager.Allocate(imageDescriptor.Width * imageDescriptor.Height, true);
+ indices = this.configuration.MemoryManager.AllocateManagedByteBuffer(imageDescriptor.Width * imageDescriptor.Height, true);
- this.ReadFrameIndices(imageDescriptor, indices);
- this.ReadFrameColors(ref image, ref previousFrame, indices, localColorTable ?? this.globalColorTable, imageDescriptor);
+ this.ReadFrameIndices(imageDescriptor, indices.Span);
+ IManagedByteBuffer colorTable = localColorTable ?? this.globalColorTable;
+ this.ReadFrameColors(ref image, ref previousFrame, indices.Span, colorTable.Span, imageDescriptor);
// Skip any remaining blocks
this.Skip(0);
@@ -605,7 +606,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
this.globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
- this.globalColorTable = this.MemoryManager.Allocate(this.globalColorTableLength, true);
+ this.globalColorTable = this.MemoryManager.AllocateManagedByteBuffer(this.globalColorTableLength, true);
// Read the global color table from the stream
stream.Read(this.globalColorTable.Array, 0, this.globalColorTableLength);
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index 43d48605c4..13ca5f2c61 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -356,15 +356,17 @@ namespace SixLabors.ImageSharp.Formats.Gif
// Get max colors for bit depth.
int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3;
var rgb = default(Rgb24);
- using (Buffer colorTable = this.memoryManager.Allocate(colorTableLength))
+ using (IManagedByteBuffer colorTable = this.memoryManager.AllocateManagedByteBuffer(colorTableLength))
{
+ Span colorTableSpan = colorTable.Span;
+
for (int i = 0; i < pixelCount; i++)
{
int offset = i * 3;
image.Palette[i].ToRgb24(ref rgb);
- colorTable[offset] = rgb.R;
- colorTable[offset + 1] = rgb.G;
- colorTable[offset + 2] = rgb.B;
+ colorTableSpan[offset] = rgb.R;
+ colorTableSpan[offset + 1] = rgb.G;
+ colorTableSpan[offset + 2] = rgb.B;
}
writer.Write(colorTable.Array, 0, colorTableLength);
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs
index 7c1cd72061..56a85bc9df 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs
@@ -26,8 +26,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Gets or sets the buffer.
/// buffer[i:j] are the buffered bytes read from the underlying
/// stream that haven't yet been passed further on.
+ /// TODO: Do we really need buffer here? Might be an optimiziation opportunity.
///
- public Buffer Buffer;
+ public IManagedByteBuffer Buffer;
///
/// Values of converted to -s
@@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
return new Bytes
{
- Buffer = memoryManager.Allocate(BufferSize),
+ Buffer = memoryManager.AllocateManagedByteBuffer(BufferSize),
BufferAsInt = memoryManager.Allocate(BufferSize)
};
}
@@ -169,7 +170,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
}
- result = this.Buffer[this.I];
+ result = this.Buffer.Span[this.I];
this.I++;
this.UnreadableBytes = 0;
return errorCode;
@@ -229,18 +230,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
DecoderThrowHelper.ThrowImageFormatException.FillCalledWhenUnreadBytesExist();
}
+ Span bufferSpan = this.Buffer.Span;
+
// Move the last 2 bytes to the start of the buffer, in case we need
// to call UnreadByteStuffedByte.
if (this.J > 2)
{
- this.Buffer[0] = this.Buffer[this.J - 2];
- this.Buffer[1] = this.Buffer[this.J - 1];
+ bufferSpan[0] = bufferSpan[this.J - 2];
+ bufferSpan[1] = bufferSpan[this.J - 1];
this.I = 2;
this.J = 2;
}
// Fill in the rest of the buffer.
- int n = inputStream.Read(this.Buffer.Array, this.J, this.Buffer.Length - this.J);
+ int n = inputStream.Read(this.Buffer.Array, this.J, bufferSpan.Length - this.J);
if (n == 0)
{
return OrigDecoderErrorCode.UnexpectedEndOfStream;
@@ -248,9 +251,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.J += n;
- for (int i = 0; i < this.Buffer.Length; i++)
+ for (int i = 0; i < bufferSpan.Length; i++)
{
- this.BufferAsInt[i] = this.Buffer[i];
+ this.BufferAsInt[i] = bufferSpan[i];
}
return OrigDecoderErrorCode.NoError;
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
index f1beab114a..95631a7e66 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
@@ -12,10 +12,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
///
internal struct PdfJsHuffmanTable : IDisposable
{
- private Buffer lookahead;
- private Buffer valOffset;
- private Buffer maxcode;
- private Buffer huffval;
+ private FakeBuffer lookahead;
+ private FakeBuffer valOffset;
+ private FakeBuffer maxcode;
+ private IManagedByteBuffer huffval;
///
/// Initializes a new instance of the struct.
@@ -25,12 +25,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// The huffman values
public PdfJsHuffmanTable(MemoryManager memoryManager, byte[] lengths, byte[] values)
{
- this.lookahead = memoryManager.Allocate(256, true);
- this.valOffset = memoryManager.Allocate(18, true);
- this.maxcode = memoryManager.Allocate(18, true);
+ // TODO: Replace FakeBuffer usages with standard or array orfixed-sized arrays
+ this.lookahead = memoryManager.AllocateFake(256);
+ this.valOffset = memoryManager.AllocateFake(18);
+ this.maxcode = memoryManager.AllocateFake(18);
- using (var huffsize = memoryManager.Allocate(257, true))
- using (var huffcode = memoryManager.Allocate(257, true))
+ using (FakeBuffer huffsize = memoryManager.AllocateFake(257))
+ using (FakeBuffer huffcode = memoryManager.AllocateFake(257))
{
GenerateSizeTable(lengths, huffsize);
GenerateCodeTable(huffsize, huffcode);
@@ -38,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
GenerateLookaheadTables(lengths, values, this.lookahead);
}
- this.huffval = memoryManager.Allocate(values.Length, true);
+ this.huffval = memoryManager.AllocateManagedByteBuffer(values.Length, true);
Buffer.BlockCopy(values, 0, this.huffval.Array, 0, values.Length);
this.MaxCode = this.maxcode.Array;
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsIDCT.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsIDCT.cs
index 49bdc2423e..f2e269f6c2 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsIDCT.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsIDCT.cs
@@ -6,6 +6,8 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
+ using SixLabors.ImageSharp.Memory;
+
///
/// Performs the inverse Descrete Cosine Transform on each frame component.
///
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
index 863c4380bf..f05a8a136d 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
@@ -673,23 +673,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
throw new ImageFormatException($"DHT has wrong length: {remaining}");
}
- using (var huffmanData = this.configuration.MemoryManager.Allocate(256, true))
+ using (IManagedByteBuffer huffmanData = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(256))
{
+ Span huffmanSpan = huffmanData.Span;
for (int i = 2; i < remaining;)
{
byte huffmanTableSpec = (byte)this.InputStream.ReadByte();
this.InputStream.Read(huffmanData.Array, 0, 16);
- using (var codeLengths = this.configuration.MemoryManager.Allocate(17, true))
+ using (IManagedByteBuffer codeLengths = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(17))
{
+ Span codeLengthsSpan = codeLengths.Span;
int codeLengthSum = 0;
for (int j = 1; j < 17; j++)
{
- codeLengthSum += codeLengths[j] = huffmanData[j - 1];
+ codeLengthSum += codeLengthsSpan[j] = huffmanSpan[j - 1];
}
- using (var huffmanValues = this.configuration.MemoryManager.Allocate(256, true))
+ using (IManagedByteBuffer huffmanValues = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(256))
{
this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum);
@@ -784,8 +786,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
{
int blocksPerLine = component.BlocksPerLine;
int blocksPerColumn = component.BlocksPerColumn;
- using (var computationBuffer = this.configuration.MemoryManager.Allocate(64, true))
- using (var multiplicationBuffer = this.configuration.MemoryManager.Allocate(64, true))
+ using (Buffer computationBuffer = this.configuration.MemoryManager.Allocate(64, true))
+ using (Buffer multiplicationBuffer = this.configuration.MemoryManager.Allocate(64, true))
{
Span quantizationTable = this.quantizationTables.Tables.GetRowSpan(frameComponent.QuantizationTableIndex);
Span computationBufferSpan = computationBuffer;
diff --git a/src/ImageSharp/Formats/Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs
index 7412fdfcd3..2483a3ad9d 100644
--- a/src/ImageSharp/Formats/Png/PngChunk.cs
+++ b/src/ImageSharp/Formats/Png/PngChunk.cs
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Gets or sets the data bytes appropriate to the chunk type, if any.
/// This field can be of zero length.
///
- public Buffer Data { get; set; }
+ public IManagedByteBuffer Data { get; set; }
///
/// Gets or sets a CRC (Cyclic Redundancy Check) calculated on the preceding bytes in the chunk,
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 45d6fa3a28..fbff0ae1d9 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -137,12 +137,12 @@ namespace SixLabors.ImageSharp.Formats.Png
///
/// Previous scanline processed
///
- private Buffer previousScanline;
+ private IManagedByteBuffer previousScanline;
///
/// The current scanline that is being processed
///
- private Buffer scanline;
+ private IManagedByteBuffer scanline;
///
/// The index of the current scanline being processed
@@ -437,8 +437,8 @@ namespace SixLabors.ImageSharp.Formats.Png
this.bytesPerSample = this.header.BitDepth / 8;
}
- this.previousScanline = this.MemoryManager.Allocate(this.bytesPerScanline, true);
- this.scanline = this.configuration.MemoryManager.Allocate(this.bytesPerScanline, true);
+ this.previousScanline = this.MemoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
+ this.scanline = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
}
///
@@ -558,7 +558,8 @@ namespace SixLabors.ImageSharp.Formats.Png
}
this.currentRowBytesRead = 0;
- var filterType = (FilterType)this.scanline[0];
+ Span scanlineSpan = this.scanline.Span;
+ var filterType = (FilterType)scanlineSpan[0];
switch (filterType)
{
@@ -567,22 +568,22 @@ namespace SixLabors.ImageSharp.Formats.Png
case FilterType.Sub:
- SubFilter.Decode(this.scanline, this.bytesPerPixel);
+ SubFilter.Decode(scanlineSpan, this.bytesPerPixel);
break;
case FilterType.Up:
- UpFilter.Decode(this.scanline, this.previousScanline);
+ UpFilter.Decode(scanlineSpan, this.previousScanline.Span);
break;
case FilterType.Average:
- AverageFilter.Decode(this.scanline, this.previousScanline, this.bytesPerPixel);
+ AverageFilter.Decode(scanlineSpan, this.previousScanline.Span, this.bytesPerPixel);
break;
case FilterType.Paeth:
- PaethFilter.Decode(this.scanline, this.previousScanline, this.bytesPerPixel);
+ PaethFilter.Decode(scanlineSpan, this.previousScanline.Span, this.bytesPerPixel);
break;
default:
@@ -753,11 +754,11 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 3;
- using (var compressed = this.configuration.MemoryManager.Allocate(length))
+ using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length))
{
// TODO: Should we use pack from vector here instead?
- this.From16BitTo8Bit(scanlineBuffer, compressed, length);
- PixelOperations.Instance.PackFromRgb24Bytes(compressed, rowSpan, this.header.Width);
+ this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length);
+ PixelOperations.Instance.PackFromRgb24Bytes(compressed.Span, rowSpan, this.header.Width);
}
}
else
@@ -770,10 +771,10 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 3;
- using (var compressed = this.configuration.MemoryManager.Allocate(length))
+ using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length))
{
// TODO: Should we use pack from vector here instead?
- this.From16BitTo8Bit(scanlineBuffer, compressed, length);
+ this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length);
Span rgb24Span = compressed.Span.NonPortableCast();
for (int x = 0; x < this.header.Width; x++)
@@ -811,11 +812,11 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 4;
- using (var compressed = this.configuration.MemoryManager.Allocate(length))
+ using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length))
{
// TODO: Should we use pack from vector here instead?
- this.From16BitTo8Bit(scanlineBuffer, compressed, length);
- PixelOperations.Instance.PackFromRgba32Bytes(compressed, rowSpan, this.header.Width);
+ this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length);
+ PixelOperations.Instance.PackFromRgba32Bytes(compressed.Span, rowSpan, this.header.Width);
}
}
else
@@ -1014,18 +1015,20 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 3;
- using (var compressed = this.configuration.MemoryManager.Allocate(length))
+ using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length))
{
+ Span compressedSpan = compressed.Span;
+
// TODO: Should we use pack from vector here instead?
- this.From16BitTo8Bit(scanlineBuffer, compressed, length);
+ this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length);
if (this.hasTrans)
{
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 3)
{
- rgba.R = compressed[o];
- rgba.G = compressed[o + 1];
- rgba.B = compressed[o + 2];
+ rgba.R = compressedSpan[o];
+ rgba.G = compressedSpan[o + 1];
+ rgba.B = compressedSpan[o + 2];
rgba.A = (byte)(this.rgb24Trans.Equals(rgba.Rgb) ? 0 : 255);
color.PackFromRgba32(rgba);
@@ -1036,9 +1039,9 @@ namespace SixLabors.ImageSharp.Formats.Png
{
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 3)
{
- rgba.R = compressed[o];
- rgba.G = compressed[o + 1];
- rgba.B = compressed[o + 2];
+ rgba.R = compressedSpan[o];
+ rgba.G = compressedSpan[o + 1];
+ rgba.B = compressedSpan[o + 2];
color.PackFromRgba32(rgba);
rowSpan[x] = color;
@@ -1082,16 +1085,18 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 4;
- using (var compressed = this.configuration.MemoryManager.Allocate(length))
+ using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length))
{
+ Span compressedSpan = compressed.Span;
+
// TODO: Should we use pack from vector here instead?
- this.From16BitTo8Bit(scanlineBuffer, compressed, length);
+ this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length);
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4)
{
- rgba.R = compressed[o];
- rgba.G = compressed[o + 1];
- rgba.B = compressed[o + 2];
- rgba.A = compressed[o + 3];
+ rgba.R = compressedSpan[o];
+ rgba.G = compressedSpan[o + 1];
+ rgba.B = compressedSpan[o + 2];
+ rgba.A = compressedSpan[o + 3];
color.PackFromRgba32(rgba);
rowSpan[x] = color;
@@ -1281,7 +1286,7 @@ namespace SixLabors.ImageSharp.Formats.Png
private void ReadChunkData(PngChunk chunk)
{
// We rent the buffer here to return it afterwards in Decode()
- chunk.Data = this.configuration.MemoryManager.Allocate(chunk.Length);
+ chunk.Data = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(chunk.Length);
this.currentStream.Read(chunk.Data.Array, 0, chunk.Length);
}
@@ -1353,7 +1358,7 @@ namespace SixLabors.ImageSharp.Formats.Png
private void SwapBuffers()
{
- Buffer temp = this.previousScanline;
+ IManagedByteBuffer temp = this.previousScanline;
this.previousScanline = this.scanline;
this.scanline = temp;
}
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index d531250898..1ab7a83ce0 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -74,37 +74,37 @@ namespace SixLabors.ImageSharp.Formats.Png
///
/// The previous scanline.
///
- private Buffer previousScanline;
+ private IManagedByteBuffer previousScanline;
///
/// The raw scanline.
///
- private Buffer rawScanline;
+ private IManagedByteBuffer rawScanline;
///
/// The filtered scanline result.
///
- private Buffer result;
+ private IManagedByteBuffer result;
///
/// The buffer for the sub filter
///
- private Buffer sub;
+ private IManagedByteBuffer sub;
///
/// The buffer for the up filter
///
- private Buffer up;
+ private IManagedByteBuffer up;
///
/// The buffer for the average filter
///
- private Buffer average;
+ private IManagedByteBuffer average;
///
/// The buffer for the paeth filter
///
- private Buffer paeth;
+ private IManagedByteBuffer paeth;
///
/// The png color type.
@@ -357,11 +357,11 @@ namespace SixLabors.ImageSharp.Formats.Png
{
if (this.bytesPerPixel == 4)
{
- PixelOperations.Instance.ToRgba32Bytes(rowSpan, this.rawScanline, this.width);
+ PixelOperations.Instance.ToRgba32Bytes(rowSpan, this.rawScanline.Span, this.width);
}
else
{
- PixelOperations.Instance.ToRgb24Bytes(rowSpan, this.rawScanline, this.width);
+ PixelOperations.Instance.ToRgb24Bytes(rowSpan, this.rawScanline.Span, this.width);
}
}
@@ -373,13 +373,14 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The row span.
/// The row.
/// The
- private Buffer EncodePixelRow(Span rowSpan, int row)
+ private IManagedByteBuffer EncodePixelRow(Span rowSpan, int row)
where TPixel : struct, IPixel
{
switch (this.pngColorType)
{
case PngColorType.Palette:
- Buffer.BlockCopy(this.palettePixelData, row * this.rawScanline.Length, this.rawScanline.Array, 0, this.rawScanline.Length);
+ // TODO: Use Span copy!
+ Buffer.BlockCopy(this.palettePixelData, row * this.rawScanline.Length(), this.rawScanline.Array, 0, this.rawScanline.Length());
break;
case PngColorType.Grayscale:
case PngColorType.GrayscaleWithAlpha:
@@ -398,7 +399,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// to be most compressible, using lowest total variation as proxy for compressibility.
///
/// The
- private Buffer GetOptimalFilteredScanline()
+ private IManagedByteBuffer GetOptimalFilteredScanline()
{
Span scanSpan = this.rawScanline.Span;
Span prevSpan = this.previousScanline.Span;
@@ -406,18 +407,18 @@ namespace SixLabors.ImageSharp.Formats.Png
// Palette images don't compress well with adaptive filtering.
if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8)
{
- NoneFilter.Encode(this.rawScanline, this.result);
+ NoneFilter.Encode(this.rawScanline.Span, this.result.Span);
return this.result;
}
// This order, while different to the enumerated order is more likely to produce a smaller sum
// early on which shaves a couple of milliseconds off the processing time.
- UpFilter.Encode(scanSpan, prevSpan, this.up, out int currentSum);
+ UpFilter.Encode(scanSpan, prevSpan, this.up.Span, out int currentSum);
int lowestSum = currentSum;
- Buffer actualResult = this.up;
+ IManagedByteBuffer actualResult = this.up;
- PaethFilter.Encode(scanSpan, prevSpan, this.paeth, this.bytesPerPixel, out currentSum);
+ PaethFilter.Encode(scanSpan, prevSpan, this.paeth.Span, this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum)
{
@@ -425,7 +426,7 @@ namespace SixLabors.ImageSharp.Formats.Png
actualResult = this.paeth;
}
- SubFilter.Encode(scanSpan, this.sub, this.bytesPerPixel, out currentSum);
+ SubFilter.Encode(scanSpan, this.sub.Span, this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum)
{
@@ -433,7 +434,7 @@ namespace SixLabors.ImageSharp.Formats.Png
actualResult = this.sub;
}
- AverageFilter.Encode(scanSpan, prevSpan, this.average, this.bytesPerPixel, out currentSum);
+ AverageFilter.Encode(scanSpan, prevSpan, this.average.Span, this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum)
{
@@ -522,9 +523,13 @@ namespace SixLabors.ImageSharp.Formats.Png
int colorTableLength = (int)Math.Pow(2, header.BitDepth) * 3;
var rgba = default(Rgba32);
bool anyAlpha = false;
- using (Buffer colorTable = this.memoryManager.Allocate(colorTableLength))
- using (Buffer alphaTable = this.memoryManager.Allocate(pixelCount))
+
+ using (IManagedByteBuffer colorTable = this.memoryManager.AllocateManagedByteBuffer(colorTableLength))
+ using (IManagedByteBuffer alphaTable = this.memoryManager.AllocateManagedByteBuffer(pixelCount))
{
+ Span colorTableSpan = colorTable.Span;
+ Span alphaTableSpan = alphaTable.Span;
+
for (byte i = 0; i < pixelCount; i++)
{
if (quantized.Pixels.Contains(i))
@@ -534,9 +539,9 @@ namespace SixLabors.ImageSharp.Formats.Png
byte alpha = rgba.A;
- colorTable[offset] = rgba.R;
- colorTable[offset + 1] = rgba.G;
- colorTable[offset + 2] = rgba.B;
+ colorTableSpan[offset] = rgba.R;
+ colorTableSpan[offset + 1] = rgba.G;
+ colorTableSpan[offset + 2] = rgba.B;
if (alpha > this.threshold)
{
@@ -544,7 +549,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
anyAlpha = anyAlpha || alpha < 255;
- alphaTable[i] = alpha;
+ alphaTableSpan[i] = alpha;
}
}
@@ -617,16 +622,16 @@ namespace SixLabors.ImageSharp.Formats.Png
this.bytesPerScanline = this.width * this.bytesPerPixel;
int resultLength = this.bytesPerScanline + 1;
- this.previousScanline = this.memoryManager.Allocate(this.bytesPerScanline, true);
- this.rawScanline = this.memoryManager.Allocate(this.bytesPerScanline, true);
- this.result = this.memoryManager.Allocate(resultLength, true);
+ this.previousScanline = this.memoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
+ this.rawScanline = this.memoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
+ this.result = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
if (this.pngColorType != PngColorType.Palette)
{
- this.sub = this.memoryManager.Allocate(resultLength, true);
- this.up = this.memoryManager.Allocate(resultLength, true);
- this.average = this.memoryManager.Allocate(resultLength, true);
- this.paeth = this.memoryManager.Allocate(resultLength, true);
+ this.sub = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
+ this.up = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
+ this.average = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
+ this.paeth = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
}
byte[] buffer;
@@ -639,10 +644,10 @@ namespace SixLabors.ImageSharp.Formats.Png
{
for (int y = 0; y < this.height; y++)
{
- Buffer r = this.EncodePixelRow(pixels.GetPixelRowSpan(y), y);
+ IManagedByteBuffer r = this.EncodePixelRow(pixels.GetPixelRowSpan(y), y);
deflateStream.Write(r.Array, 0, resultLength);
- Buffer temp = this.rawScanline;
+ IManagedByteBuffer temp = this.rawScanline;
this.rawScanline = this.previousScanline;
this.previousScanline = temp;
}
diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs
index a2eacd3733..72492a494b 100644
--- a/src/ImageSharp/Image/Image.Decode.cs
+++ b/src/ImageSharp/Image/Image.Decode.cs
@@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp
return null;
}
- using (var buffer = config.MemoryManager.Allocate(maxHeaderSize))
+ using (IManagedByteBuffer buffer = config.MemoryManager.AllocateManagedByteBuffer(maxHeaderSize))
{
long startPosition = stream.Position;
stream.Read(buffer.Array, 0, maxHeaderSize);
stream.Position = startPosition;
- return config.FormatDetectors.Select(x => x.DetectFormat(buffer)).LastOrDefault(x => x != null);
+ return config.FormatDetectors.Select(x => x.DetectFormat(buffer.Span)).LastOrDefault(x => x != null);
}
}
diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
index 50e65a0829..80c0ce4e66 100644
--- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
+++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
@@ -84,11 +84,6 @@ namespace SixLabors.ImageSharp
this.Dispose();
}
- ///
- /// Gets the pixel buffer array.
- ///
- public TPixel[] PixelArray => this.PixelBuffer.Buffer.Array;
-
///
/// Gets the size of a single pixel in the number of bytes.
///
@@ -106,7 +101,7 @@ namespace SixLabors.ImageSharp
public int Height { get; private set; }
///
- Span IBuffer2D.Span => this.PixelBuffer.Span;
+ public Span Span => this.PixelBuffer.Span;
private static PixelOperations Operations => PixelOperations.Instance;
@@ -122,14 +117,15 @@ namespace SixLabors.ImageSharp
get
{
this.CheckCoordinates(x, y);
- return this.PixelArray[(y * this.Width) + x];
+ return this.Span[(y * this.Width) + x];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.CheckCoordinates(x, y);
- this.PixelArray[(y * this.Width) + x] = value;
+ Span span = this.Span;
+ span[(y * this.Width) + x] = value;
}
}
diff --git a/src/ImageSharp/Image/PixelArea{TPixel}.cs b/src/ImageSharp/Image/PixelArea{TPixel}.cs
index fa3499b6d7..7648017222 100644
--- a/src/ImageSharp/Image/PixelArea{TPixel}.cs
+++ b/src/ImageSharp/Image/PixelArea{TPixel}.cs
@@ -30,44 +30,7 @@ namespace SixLabors.ImageSharp
///
/// The underlying buffer containing the raw pixel data.
///
- private readonly Buffer byteBuffer;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The width.
- /// The bytes.
- /// The component order.
- ///
- /// Thrown if is the incorrect length.
- ///
- public PixelArea(int width, byte[] bytes, ComponentOrder componentOrder)
- : this(width, 1, bytes, componentOrder)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The width.
- /// The height.
- /// The bytes.
- /// The component order.
- ///
- /// Thrown if is the incorrect length.
- ///
- public PixelArea(int width, int height, byte[] bytes, ComponentOrder componentOrder)
- {
- this.CheckBytesLength(width, height, bytes, componentOrder);
-
- this.Width = width;
- this.Height = height;
- this.ComponentOrder = componentOrder;
- this.RowStride = width * GetComponentCount(componentOrder);
- this.Length = bytes.Length; // TODO: Is this the right value for Length?
-
- this.byteBuffer = new Buffer(bytes);
- }
+ private readonly IManagedByteBuffer byteBuffer;
///
/// Initializes a new instance of the class.
@@ -116,7 +79,7 @@ namespace SixLabors.ImageSharp
this.RowStride = (width * GetComponentCount(componentOrder)) + padding;
this.Length = this.RowStride * height;
- this.byteBuffer = Configuration.Default.MemoryManager.Allocate(this.Length, true);
+ this.byteBuffer = Configuration.Default.MemoryManager.AllocateCleanManagedByteBuffer(this.Length);
}
///
diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs b/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs
index 4034643345..e14ba443f9 100644
--- a/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs
+++ b/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs
@@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Memory
///
internal override void Release(Buffer buffer)
{
- byte[] byteBuffer = Unsafe.As(buffer.Array);
+ byte[] byteBuffer = Unsafe.As(buffer.GetArray());
this.pool.Return(byteBuffer);
}
}
diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs
index ac5ab09dbd..0cbffde775 100644
--- a/src/ImageSharp/Memory/Buffer2DExtensions.cs
+++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs
@@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Memory
///
internal static class Buffer2DExtensions
{
+
///
/// Gets a to the row 'y' beginning from the pixel at 'x'.
///
diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs
index 82cb25f476..e527c90c07 100644
--- a/src/ImageSharp/Memory/Buffer2D{T}.cs
+++ b/src/ImageSharp/Memory/Buffer2D{T}.cs
@@ -51,8 +51,8 @@ namespace SixLabors.ImageSharp.Memory
{
DebugGuard.MustBeLessThan(x, this.Width, nameof(x));
DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
-
- return ref this.Buffer.Array[(this.Width * y) + x];
+ Span span = this.Buffer.Span;
+ return ref span[(this.Width * y) + x];
}
}
diff --git a/src/ImageSharp/Memory/BufferExtensions.cs b/src/ImageSharp/Memory/BufferExtensions.cs
new file mode 100644
index 0000000000..8975d3b45d
--- /dev/null
+++ b/src/ImageSharp/Memory/BufferExtensions.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace SixLabors.ImageSharp.Memory
+{
+ internal static class BufferExtensions
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int Length(this IBuffer buffer)
+ where T : struct => buffer.Span.Length;
+
+ ///
+ /// Gets a to an offseted position inside the buffer.
+ ///
+ /// The buffer
+ /// The start
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span Slice(this IBuffer buffer, int start)
+ where T : struct
+ {
+ return buffer.Span.Slice(start);
+ }
+
+ ///
+ /// Gets a to an offsetted position inside the buffer.
+ ///
+ /// The buffer
+ /// The start
+ /// The length of the slice
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span Slice(this IBuffer buffer, int start, int length)
+ where T : struct
+ {
+ return buffer.Span.Slice(start, length);
+ }
+
+ ///
+ /// Clears the contents of this buffer.
+ ///
+ /// The buffer
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Clear(this IBuffer buffer)
+ where T : struct
+ {
+ buffer.Span.Clear();
+ }
+
+ public static ref T DangerousGetPinnableReference(this IBuffer buffer)
+ where T : struct =>
+ ref buffer.Span.DangerousGetPinnableReference();
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/Buffer{T}.cs b/src/ImageSharp/Memory/Buffer{T}.cs
index 07a827a67d..1ee1571c84 100644
--- a/src/ImageSharp/Memory/Buffer{T}.cs
+++ b/src/ImageSharp/Memory/Buffer{T}.cs
@@ -19,15 +19,23 @@ namespace SixLabors.ImageSharp.Memory
private MemoryManager memoryManager;
///
- /// A pointer to the first element of when pinned.
+ /// A pointer to the first element of when pinned.
///
private IntPtr pointer;
///
- /// A handle that allows to access the managed as an unmanaged memory by pinning.
+ /// A handle that allows to access the managed as an unmanaged memory by pinning.
///
private GCHandle handle;
+ // why is there such a rule? :S Protected should be fine for a field!
+#pragma warning disable SA1401 // Fields should be private
+ ///
+ /// The backing array.
+ ///
+ protected T[] array;
+#pragma warning restore SA1401 // Fields should be private
+
///
/// Initializes a new instance of the class.
///
@@ -35,7 +43,7 @@ namespace SixLabors.ImageSharp.Memory
public Buffer(T[] array)
{
this.Length = array.Length;
- this.Array = array;
+ this.array = array;
}
///
@@ -51,7 +59,7 @@ namespace SixLabors.ImageSharp.Memory
}
this.Length = length;
- this.Array = array;
+ this.array = array;
}
internal Buffer(T[] array, int length, MemoryManager memoryManager)
@@ -69,20 +77,15 @@ namespace SixLabors.ImageSharp.Memory
}
///
- /// Gets a value indicating whether this instance is disposed, or has lost ownership of .
+ /// Gets a value indicating whether this instance is disposed, or has lost ownership of .
///
public bool IsDisposedOrLostArrayOwnership { get; private set; }
///
- /// Gets the count of "relevant" elements. It's usually smaller than 'Array.Length' when is pooled.
+ /// Gets the count of "relevant" elements. It's usually smaller than 'Array.Length' when is pooled.
///
public int Length { get; private set; }
- ///
- /// Gets the backing pinned array.
- ///
- public T[] Array { get; private set; }
-
///
/// Gets a to the backing buffer.
///
@@ -112,7 +115,7 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlySpan(Buffer buffer)
{
- return new ReadOnlySpan(buffer.Array, 0, buffer.Length);
+ return new ReadOnlySpan(buffer.array, 0, buffer.Length);
}
///
@@ -122,30 +125,7 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Span(Buffer buffer)
{
- return new Span(buffer.Array, 0, buffer.Length);
- }
-
- ///
- /// Gets a to an offseted position inside the buffer.
- ///
- /// The start
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span Slice(int start)
- {
- return new Span(this.Array, start, this.Length - start);
- }
-
- ///
- /// Gets a to an offsetted position inside the buffer.
- ///
- /// The start
- /// The length of the slice
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span Slice(int start, int length)
- {
- return new Span(this.Array, start, length);
+ return new Span(buffer.array, 0, buffer.Length);
}
///
@@ -165,17 +145,17 @@ namespace SixLabors.ImageSharp.Memory
this.memoryManager?.Release(this);
this.memoryManager = null;
- this.Array = null;
+ this.array = null;
this.Length = 0;
GC.SuppressFinalize(this);
}
///
- /// Unpins and makes the object "quasi-disposed" so the array is no longer owned by this object.
- /// If is rented, it's the callers responsibility to return it to it's pool.
+ /// Unpins and makes the object "quasi-disposed" so the array is no longer owned by this object.
+ /// If is rented, it's the callers responsibility to return it to it's pool.
///
- /// The unpinned
+ /// The unpinned
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T[] TakeArrayOwnership()
{
@@ -187,23 +167,14 @@ namespace SixLabors.ImageSharp.Memory
this.IsDisposedOrLostArrayOwnership = true;
this.UnPin();
- T[] array = this.Array;
- this.Array = null;
+ T[] array = this.array;
+ this.array = null;
this.memoryManager = null;
return array;
}
///
- /// Clears the contents of this buffer.
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Clear()
- {
- this.Span.Clear();
- }
-
- ///
- /// Pins .
+ /// Pins .
///
/// The pinned pointer
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -217,7 +188,7 @@ namespace SixLabors.ImageSharp.Memory
if (this.pointer == IntPtr.Zero)
{
- this.handle = GCHandle.Alloc(this.Array, GCHandleType.Pinned);
+ this.handle = GCHandle.Alloc(this.array, GCHandleType.Pinned);
this.pointer = this.handle.AddrOfPinnedObject();
}
@@ -225,7 +196,15 @@ namespace SixLabors.ImageSharp.Memory
}
///
- /// Unpins .
+ /// TODO: Refactor this
+ ///
+ internal T[] GetArray()
+ {
+ return this.array;
+ }
+
+ ///
+ /// Unpins .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UnPin()
diff --git a/src/ImageSharp/Memory/ManagedByteBuffer.cs b/src/ImageSharp/Memory/ManagedByteBuffer.cs
index 17fe945d61..94d08e2aa7 100644
--- a/src/ImageSharp/Memory/ManagedByteBuffer.cs
+++ b/src/ImageSharp/Memory/ManagedByteBuffer.cs
@@ -6,5 +6,7 @@ namespace SixLabors.ImageSharp.Memory
: base(array, length, memoryManager)
{
}
+
+ public byte[] Array => this.array;
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/MemoryManager.cs b/src/ImageSharp/Memory/MemoryManager.cs
index cac9b785b8..58f2458193 100644
--- a/src/ImageSharp/Memory/MemoryManager.cs
+++ b/src/ImageSharp/Memory/MemoryManager.cs
@@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Memory
/// Temporal workaround. A method providing a "Buffer" based on a generic array without the 'Unsafe.As()' hackery.
/// Should be replaced with 'Allocate()' as soon as SixLabors.Shapes has Span-based API-s!
///
- internal FakeBuffer AllocateFake(int length)
+ internal FakeBuffer AllocateFake(int length, bool dummy = false)
where T : struct
{
return new FakeBuffer(new T[length]);
diff --git a/src/ImageSharp/Memory/MemoryManagerExtensions.cs b/src/ImageSharp/Memory/MemoryManagerExtensions.cs
index 8772307885..f157767217 100644
--- a/src/ImageSharp/Memory/MemoryManagerExtensions.cs
+++ b/src/ImageSharp/Memory/MemoryManagerExtensions.cs
@@ -26,6 +26,11 @@
return memoryManager.Allocate(length, true);
}
+ public static IManagedByteBuffer AllocateManagedByteBuffer(this MemoryManager memoryManager, int length)
+ {
+ return memoryManager.AllocateManagedByteBuffer(length, false);
+ }
+
public static IManagedByteBuffer AllocateCleanManagedByteBuffer(this MemoryManager memoryManager, int length)
{
return memoryManager.AllocateManagedByteBuffer(length, true);
diff --git a/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs
index 8f89c49611..b5d31014b2 100644
--- a/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs
@@ -180,14 +180,14 @@ namespace SixLabors.ImageSharp.Quantizers
{
this.Mark(ref this.colorCube[k], (byte)k);
- float weight = Volume(ref this.colorCube[k], this.vwt.Array);
+ float weight = Volume(ref this.colorCube[k], this.vwt.Span);
if (MathF.Abs(weight) > Constants.Epsilon)
{
- float r = Volume(ref this.colorCube[k], this.vmr.Array);
- float g = Volume(ref this.colorCube[k], this.vmg.Array);
- float b = Volume(ref this.colorCube[k], this.vmb.Array);
- float a = Volume(ref this.colorCube[k], this.vma.Array);
+ float r = Volume(ref this.colorCube[k], this.vmr.Span);
+ float g = Volume(ref this.colorCube[k], this.vmg.Span);
+ float b = Volume(ref this.colorCube[k], this.vmb.Span);
+ float a = Volume(ref this.colorCube[k], this.vma.Span);
ref TPixel color = ref this.palette[k];
color.PackFromVector4(new Vector4(r, g, b, a) / weight / 255F);
@@ -312,7 +312,7 @@ namespace SixLabors.ImageSharp.Quantizers
/// The cube.
/// The moment.
/// The result.
- private static float Volume(ref Box cube, long[] moment)
+ private static float Volume(ref Box cube, Span moment)
{
return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
@@ -339,7 +339,7 @@ namespace SixLabors.ImageSharp.Quantizers
/// The direction.
/// The moment.
/// The result.
- private static long Bottom(ref Box cube, int direction, long[] moment)
+ private static long Bottom(ref Box cube, int direction, Span moment)
{
switch (direction)
{
@@ -400,7 +400,7 @@ namespace SixLabors.ImageSharp.Quantizers
/// The position.
/// The moment.
/// The result.
- private static long Top(ref Box cube, int direction, int position, long[] moment)
+ private static long Top(ref Box cube, int direction, int position, Span moment)
{
switch (direction)
{
@@ -548,10 +548,10 @@ namespace SixLabors.ImageSharp.Quantizers
/// The .
private float Variance(ref Box cube)
{
- float dr = Volume(ref cube, this.vmr.Array);
- float dg = Volume(ref cube, this.vmg.Array);
- float db = Volume(ref cube, this.vmb.Array);
- float da = Volume(ref cube, this.vma.Array);
+ float dr = Volume(ref cube, this.vmr.Span);
+ float dg = Volume(ref cube, this.vmg.Span);
+ float db = Volume(ref cube, this.vmb.Span);
+ float da = Volume(ref cube, this.vma.Span);
float xx =
this.m2[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
@@ -572,7 +572,7 @@ namespace SixLabors.ImageSharp.Quantizers
+ this.m2[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
var vector = new Vector4(dr, dg, db, da);
- return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.Array));
+ return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.Span));
}
///
@@ -595,22 +595,22 @@ namespace SixLabors.ImageSharp.Quantizers
/// The .
private float Maximize(ref Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW)
{
- long baseR = Bottom(ref cube, direction, this.vmr.Array);
- long baseG = Bottom(ref cube, direction, this.vmg.Array);
- long baseB = Bottom(ref cube, direction, this.vmb.Array);
- long baseA = Bottom(ref cube, direction, this.vma.Array);
- long baseW = Bottom(ref cube, direction, this.vwt.Array);
+ long baseR = Bottom(ref cube, direction, this.vmr.Span);
+ long baseG = Bottom(ref cube, direction, this.vmg.Span);
+ long baseB = Bottom(ref cube, direction, this.vmb.Span);
+ long baseA = Bottom(ref cube, direction, this.vma.Span);
+ long baseW = Bottom(ref cube, direction, this.vwt.Span);
float max = 0F;
cut = -1;
for (int i = first; i < last; i++)
{
- float halfR = baseR + Top(ref cube, direction, i, this.vmr.Array);
- float halfG = baseG + Top(ref cube, direction, i, this.vmg.Array);
- float halfB = baseB + Top(ref cube, direction, i, this.vmb.Array);
- float halfA = baseA + Top(ref cube, direction, i, this.vma.Array);
- float halfW = baseW + Top(ref cube, direction, i, this.vwt.Array);
+ float halfR = baseR + Top(ref cube, direction, i, this.vmr.Span);
+ float halfG = baseG + Top(ref cube, direction, i, this.vmg.Span);
+ float halfB = baseB + Top(ref cube, direction, i, this.vmb.Span);
+ float halfA = baseA + Top(ref cube, direction, i, this.vma.Span);
+ float halfW = baseW + Top(ref cube, direction, i, this.vwt.Span);
if (MathF.Abs(halfW) < Constants.Epsilon)
{
@@ -654,11 +654,11 @@ namespace SixLabors.ImageSharp.Quantizers
/// Returns a value indicating whether the box has been split.
private bool Cut(ref Box set1, ref Box set2)
{
- float wholeR = Volume(ref set1, this.vmr.Array);
- float wholeG = Volume(ref set1, this.vmg.Array);
- float wholeB = Volume(ref set1, this.vmb.Array);
- float wholeA = Volume(ref set1, this.vma.Array);
- float wholeW = Volume(ref set1, this.vwt.Array);
+ float wholeR = Volume(ref set1, this.vmr.Span);
+ float wholeG = Volume(ref set1, this.vmg.Span);
+ float wholeB = Volume(ref set1, this.vmb.Span);
+ float wholeA = Volume(ref set1, this.vma.Span);
+ float wholeW = Volume(ref set1, this.vwt.Span);
float maxr = this.Maximize(ref set1, 3, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxg = this.Maximize(ref set1, 2, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW);
diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs
index 1f660466df..53a55e06e3 100644
--- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs
+++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs
@@ -2,6 +2,7 @@
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
{
using System.Numerics;
+ using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
@@ -36,12 +37,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
- Vector4[] s = this.source.Array;
- TPixel[] d = this.destination.Array;
+ ref Vector4 s = ref this.source.Span.DangerousGetPinnableReference();
+ ref TPixel d = ref this.destination.Span.DangerousGetPinnableReference();
for (int i = 0; i < this.Count; i++)
{
- d[i].PackFromVector4(s[i]);
+ Unsafe.Add(ref d, i).PackFromVector4(Unsafe.Add(ref s, i));
}
}
diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs
index fd96c02cd3..8925fe9038 100644
--- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs
+++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs
@@ -61,8 +61,8 @@
[Benchmark]
public void PackUsingReferences()
{
- ref Vector4 sp = ref this.source.Array[0];
- ref Rgba32 dp = ref this.destination.Array[0];
+ ref Vector4 sp = ref this.source.DangerousGetPinnableReference();
+ ref Rgba32 dp = ref this.destination.DangerousGetPinnableReference();
int count = this.Count;
for (int i = 0; i < count; i++)
diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
index eab65bb33a..fb2f03d743 100644
--- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
+++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
@@ -1,6 +1,8 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
{
+ using System;
+
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
@@ -33,13 +35,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
- byte[] s = this.source.Array;
- TPixel[] d = this.destination.Array;
+ Span s = this.source.Span;
+ Span d = this.destination.Span;
for (int i = 0; i < this.Count; i++)
{
int i4 = i * 4;
- TPixel c = default(TPixel);
+ var c = default(TPixel);
c.PackFromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3]));
d[i] = c;
}
diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
index f9ecc9635e..cddf0f9a86 100644
--- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
+++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
@@ -1,6 +1,7 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
{
+ using System;
using System.Numerics;
using BenchmarkDotNet.Attributes;
@@ -35,8 +36,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
- TPixel[] s = this.source.Array;
- Vector4[] d = this.destination.Array;
+ Span s = this.source.Span;
+ Span d = this.destination.Span;
for (int i = 0; i < this.Count; i++)
{
diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
index 8475a9e822..6593a28ae3 100644
--- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
+++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
@@ -1,6 +1,9 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
{
+ using System;
+ using System.Numerics;
+
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
@@ -33,8 +36,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
- TPixel[] s = this.source.Array;
- byte[] d = this.destination.Array;
+ Span s = this.source.Span;
+ Span d = this.destination.Span;
+
var rgb = default(Rgb24);
for (int i = 0; i < this.Count; i++)
diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
index b3e0eff14d..58b80d5504 100644
--- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
+++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
@@ -38,8 +38,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
- TPixel[] s = this.source.Array;
- byte[] d = this.destination.Array;
+ Span s = this.source.Span;
+ Span d = this.destination.Span;
+
var rgba = default(Rgba32);
for (int i = 0; i < this.Count; i++)
diff --git a/tests/ImageSharp.Benchmarks/General/ClearBuffer.cs b/tests/ImageSharp.Benchmarks/General/ClearBuffer.cs
deleted file mode 100644
index 6926d92536..0000000000
--- a/tests/ImageSharp.Benchmarks/General/ClearBuffer.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Benchmarks.General
-{
- using System;
- using System.Runtime.CompilerServices;
-
- using BenchmarkDotNet.Attributes;
-
- using SixLabors.ImageSharp.Memory;
-
- public unsafe class ClearBuffer
- {
- private Buffer buffer;
-
- [Params(32, 128, 512)]
- public int Count { get; set; }
-
- [GlobalSetup]
- public void Setup()
- {
- this.buffer = Configuration.Default.MemoryManager.Allocate(this.Count);
- }
-
- [GlobalCleanup]
- public void Cleanup()
- {
- this.buffer.Dispose();
- }
-
- [Benchmark(Baseline = true)]
- public void Array_Clear()
- {
- Array.Clear(this.buffer.Array, 0, this.Count);
- }
-
- [Benchmark]
- public void Unsafe_InitBlock()
- {
- Unsafe.InitBlock((void*)this.buffer.Pin(), default(byte), (uint)this.Count * sizeof(uint));
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Benchmarks/General/PixelIndexing.cs b/tests/ImageSharp.Benchmarks/General/PixelIndexing.cs
deleted file mode 100644
index 50e0bd6100..0000000000
--- a/tests/ImageSharp.Benchmarks/General/PixelIndexing.cs
+++ /dev/null
@@ -1,362 +0,0 @@
-namespace SixLabors.ImageSharp.Benchmarks.General
-{
- using System.Numerics;
- using System.Runtime.CompilerServices;
-
- using BenchmarkDotNet.Attributes;
-
- using SixLabors.ImageSharp.Memory;
-
- // Pixel indexing benchmarks compare different methods for getting/setting all pixel values in a subsegment of a single pixel row.
- public abstract unsafe class PixelIndexing
- {
- ///
- /// https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/Pinnable.cs
- ///
- protected class Pinnable
- {
- public T Data;
- }
-
- ///
- /// The indexer methods are encapsulated into a struct to make sure everything is inlined.
- ///
- internal struct Data
- {
- private Vector4* pointer;
-
- private Pinnable pinnable;
-
- private Vector4[] array;
-
- private int width;
-
- public Data(Buffer2D buffer)
- {
- this.pointer = (Vector4*)buffer.Buffer.Pin();
- this.pinnable = Unsafe.As>(buffer.Buffer.Array);
- this.array = buffer.Buffer.Array;
- this.width = buffer.Width;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vector4 GetPointersBasicImpl(int x, int y)
- {
- return this.pointer[y * this.width + x];
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vector4 GetPointersSrcsUnsafeImpl(int x, int y)
- {
- // This is the original solution in PixelAccessor:
- return Unsafe.Read((byte*)this.pointer + (((y * this.width) + x) * Unsafe.SizeOf()));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vector4 GetReferencesImpl(int x, int y)
- {
- int elementOffset = (y * this.width) + x;
- return Unsafe.Add(ref this.pinnable.Data, elementOffset);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref Vector4 GetReferencesRefReturnsImpl(int x, int y)
- {
- int elementOffset = (y * this.width) + x;
- return ref Unsafe.Add(ref this.pinnable.Data, elementOffset);
- }
-
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void IndexWithPointersBasicImpl(int x, int y, Vector4 v)
- {
- this.pointer[y * this.width + x] = v;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void IndexWithPointersSrcsUnsafeImpl(int x, int y, Vector4 v)
- {
- Unsafe.Write((byte*)this.pointer + (((y * this.width) + x) * Unsafe.SizeOf()), v);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void IndexWithReferencesOnPinnableIncorrectImpl(int x, int y, Vector4 v)
- {
- int elementOffset = (y * this.width) + x;
- // Incorrect, because also should add a runtime-specific byte offset here. See https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/Span.cs#L68
- Unsafe.Add(ref this.pinnable.Data, elementOffset) = v;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref Vector4 IndexWithReferencesOnPinnableIncorrectRefReturnImpl(int x, int y)
- {
- int elementOffset = (y * this.width) + x;
- // Incorrect, because also should add a runtime-specific byte offset here. See https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/Span.cs#L68
- return ref Unsafe.Add(ref this.pinnable.Data, elementOffset);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void IndexWithUnsafeReferenceArithmeticsOnArray0Impl(int x, int y, Vector4 v)
- {
- int elementOffset = (y * this.width) + x;
- Unsafe.Add(ref this.array[0], elementOffset) = v;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref Vector4 IndexWithUnsafeReferenceArithmeticsOnArray0RefReturnImpl(int x, int y)
- {
- int elementOffset = (y * this.width) + x;
- return ref Unsafe.Add(ref this.array[0], elementOffset);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void IndexSetArrayStraightforward(int x, int y, Vector4 v)
- {
- // No magic.
- // We just index right into the array as normal people do.
- // And it looks like this is the fastest way!
- this.array[(y * this.width) + x] = v;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref Vector4 IndexWithReferencesOnArrayStraightforwardRefReturnImpl(int x, int y)
- {
- // No magic.
- // We just index right into the array as normal people do.
- // And it looks like this is the fastest way!
- return ref this.array[(y * this.width) + x];
- }
- }
-
- internal Buffer2D buffer;
-
- protected int width;
-
- protected int startIndex;
-
- protected int endIndex;
-
- protected Vector4* pointer;
-
- protected Vector4[] array;
-
- protected Pinnable pinnable;
-
- // [Params(1024)]
- public int Count { get; set; } = 1024;
-
- [GlobalSetup]
- public void Setup()
- {
- this.width = 2048;
- this.buffer = Configuration.Default.MemoryManager.Allocate2D(2048, 2048);
- this.pointer = (Vector4*)this.buffer.Buffer.Pin();
- this.array = this.buffer.Buffer.Array;
- this.pinnable = Unsafe.As>(this.array);
-
- this.startIndex = 2048 / 2 - (this.Count / 2);
- this.endIndex = 2048 / 2 + (this.Count / 2);
- }
-
- [GlobalCleanup]
- public void Cleanup()
- {
- this.buffer.Dispose();
- }
-
- }
-
- public class PixelIndexingGetter : PixelIndexing
- {
- [Benchmark(Description = "Index.Get: Pointers+arithmetics", Baseline = true)]
- public Vector4 IndexWithPointersBasic()
- {
- Vector4 sum = Vector4.Zero;
- Data data = new Data(this.buffer);
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- sum += data.GetPointersBasicImpl(x, y);
- }
-
- return sum;
- }
-
- [Benchmark(Description = "Index.Get: Pointers+SRCS.Unsafe")]
- public Vector4 IndexWithPointersSrcsUnsafe()
- {
- Vector4 sum = Vector4.Zero;
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- sum += data.GetPointersSrcsUnsafeImpl(x, y);
- }
-
- return sum;
- }
-
- [Benchmark(Description = "Index.Get: References")]
- public Vector4 IndexWithReferences()
- {
- Vector4 sum = Vector4.Zero;
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- sum += data.GetReferencesImpl(x, y);
- }
-
- return sum;
- }
-
- [Benchmark(Description = "Index.Get: References|refreturns")]
- public Vector4 IndexWithReferencesRefReturns()
- {
- Vector4 sum = Vector4.Zero;
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- sum += data.GetReferencesRefReturnsImpl(x, y);
- }
-
- return sum;
- }
- }
-
- public class PixelIndexingSetter : PixelIndexing
- {
- [Benchmark(Description = "!!! Index.Set: Pointers|arithmetics", Baseline = true)]
- public void IndexWithPointersBasic()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- data.IndexWithPointersBasicImpl(x, y, v);
- }
- }
-
- [Benchmark(Description = "Index.Set: Pointers|SRCS.Unsafe")]
- public void IndexWithPointersSrcsUnsafe()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- data.IndexWithPointersSrcsUnsafeImpl(x, y, v);
- }
- }
-
- [Benchmark(Description = "Index.Set: References|IncorrectPinnable")]
- public void IndexWithReferencesPinnableBasic()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- data.IndexWithReferencesOnPinnableIncorrectImpl(x, y, v);
- }
- }
-
- [Benchmark(Description = "Index.Set: References|IncorrectPinnable|refreturn")]
- public void IndexWithReferencesPinnableRefReturn()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- data.IndexWithReferencesOnPinnableIncorrectRefReturnImpl(x, y) = v;
- }
- }
-
- [Benchmark(Description = "Index.Set: References|Array[0]Unsafe")]
- public void IndexWithReferencesArrayBasic()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- data.IndexWithUnsafeReferenceArithmeticsOnArray0Impl(x, y, v);
- }
- }
-
- [Benchmark(Description = "Index.Set: References|Array[0]Unsafe|refreturn")]
- public void IndexWithReferencesArrayRefReturn()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- data.IndexWithUnsafeReferenceArithmeticsOnArray0RefReturnImpl(x, y) = v;
- }
- }
-
- [Benchmark(Description = "!!! Index.Set: References|Array+Straight")]
- public void IndexWithReferencesArrayStraightforward()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- // No magic.
- // We just index right into the array as normal people do.
- // And it looks like this is the fastest way!
- data.IndexSetArrayStraightforward(x, y, v);
- }
- }
-
-
- [Benchmark(Description = "!!! Index.Set: References|Array+Straight|refreturn")]
- public void IndexWithReferencesArrayStraightforwardRefReturn()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- int y = this.startIndex;
- for (int x = this.startIndex; x < this.endIndex; x++)
- {
- // No magic.
- // We just index right into the array as normal people do.
- // And it looks like this is the fastest way!
- data.IndexWithReferencesOnArrayStraightforwardRefReturnImpl(x, y) = v;
- }
- }
-
- [Benchmark(Description = "!!! Index.Set: SmartUnsafe")]
- public void SmartUnsafe()
- {
- Vector4 v = new Vector4(1, 2, 3, 4);
- Data data = new Data(this.buffer);
-
- // This method is basically an unsafe variant of .GetRowSpan(y) + indexing individual pixels in the row.
- // If a user seriously needs by-pixel manipulation to be performant, we should provide this option.
-
- ref Vector4 rowStart = ref data.IndexWithReferencesOnArrayStraightforwardRefReturnImpl(this.startIndex, this.startIndex);
-
- for (int i = 0; i < this.Count; i++)
- {
- // We don't have to add 'Width * y' here!
- Unsafe.Add(ref rowStart, i) = v;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
index 7f78ef39c0..50c3ff0050 100644
--- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
+++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
@@ -46,10 +46,11 @@ namespace SixLabors.ImageSharp.Tests.Memory
{
using (Buffer2D buffer = Configuration.Default.MemoryManager.Allocate2D(42, 42, true))
{
+ Span span = buffer.Span;
for (int j = 0; j < buffer.Buffer.Length; j++)
{
- Assert.Equal(0, buffer.Buffer.Array[j]);
- buffer.Buffer.Array[j] = 666;
+ Assert.Equal(0, span[j]);
+ span[j] = 666;
}
}
}
@@ -95,7 +96,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
{
using (Buffer2D buffer = Configuration.Default.MemoryManager.Allocate2D(width, height))
{
- TestStructs.Foo[] array = buffer.Buffer.Array;
+ Span array = buffer.Buffer.Span;
ref TestStructs.Foo actual = ref buffer[x, y];
diff --git a/tests/ImageSharp.Tests/Memory/BufferTests.cs b/tests/ImageSharp.Tests/Memory/BufferTests.cs
deleted file mode 100644
index d0a83a094d..0000000000
--- a/tests/ImageSharp.Tests/Memory/BufferTests.cs
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Tests.Memory
-{
- using System;
- using System.Runtime.CompilerServices;
-
- using SixLabors.ImageSharp.Memory;
-
- using Xunit;
-
- public unsafe class BufferTests
- {
- // ReSharper disable once ClassNeverInstantiated.Local
- private class Assert : Xunit.Assert
- {
- public static void SpanPointsTo(Span span, Buffer buffer, int bufferOffset = 0)
- where T : struct
- {
- ref T actual = ref span.DangerousGetPinnableReference();
- ref T expected = ref Unsafe.Add(ref buffer[0], bufferOffset);
-
- Assert.True(Unsafe.AreSame(ref expected, ref actual), "span does not point to the expected position");
- }
-
- public static void Equal(void* expected, void* actual)
- {
- Assert.Equal((IntPtr)expected, (IntPtr)actual);
- }
- }
-
- [Theory]
- [InlineData(42)]
- [InlineData(1111)]
- public void ConstructWithOwnArray(int count)
- {
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(count))
- {
- Assert.False(buffer.IsDisposedOrLostArrayOwnership);
- Assert.NotNull(buffer.Array);
- Assert.Equal(count, buffer.Length);
- Assert.True(buffer.Array.Length >= count);
- }
- }
-
- [Theory]
- [InlineData(42)]
- [InlineData(1111)]
- public void ConstructWithExistingArray(int count)
- {
- TestStructs.Foo[] array = new TestStructs.Foo[count];
- using (Buffer buffer = new Buffer(array))
- {
- Assert.False(buffer.IsDisposedOrLostArrayOwnership);
- Assert.Equal(array, buffer.Array);
- Assert.Equal(count, buffer.Length);
- }
- }
-
- [Fact]
- public void Clear()
- {
- TestStructs.Foo[] a = { new TestStructs.Foo() { A = 1, B = 2 }, new TestStructs.Foo() { A = 3, B = 4 } };
- using (Buffer buffer = new Buffer(a))
- {
- buffer.Clear();
-
- Assert.Equal(default(TestStructs.Foo), a[0]);
- Assert.Equal(default(TestStructs.Foo), a[1]);
- }
- }
-
- [Fact]
- public void CreateClean()
- {
- for (int i = 0; i < 100; i++)
- {
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(42, true))
- {
- for (int j = 0; j < buffer.Length; j++)
- {
- Assert.Equal(0, buffer.Array[j]);
- buffer.Array[j] = 666;
- }
- }
- }
- }
-
- public class Indexer
- {
- public static readonly TheoryData IndexerData =
- new TheoryData()
- {
- { 10, 0 },
- { 16, 3 },
- { 10, 9 }
- };
-
- [Theory]
- [MemberData(nameof(IndexerData))]
- public void Read(int length, int index)
- {
- TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
-
- using (Buffer buffer = new Buffer(a))
- {
- TestStructs.Foo element = buffer[index];
-
- Assert.Equal(a[index], element);
- }
- }
-
- [Theory]
- [MemberData(nameof(IndexerData))]
- public void Write(int length, int index)
- {
- TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
-
- using (Buffer buffer = new Buffer(a))
- {
- buffer[index] = new TestStructs.Foo(666, 666);
-
- Assert.Equal(new TestStructs.Foo(666, 666), a[index]);
- }
- }
- }
-
- [Fact]
- public void Dispose()
- {
- Buffer buffer = Configuration.Default.MemoryManager.Allocate(42);
- buffer.Dispose();
-
- Assert.True(buffer.IsDisposedOrLostArrayOwnership);
- }
-
- [Theory]
- [InlineData(7)]
- [InlineData(123)]
- public void CastToSpan(int bufferLength)
- {
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(bufferLength))
- {
- Span span = buffer;
-
- //Assert.Equal(buffer.Array, span.ToArray());
- //Assert.Equal(0, span.Start);
- Assert.SpanPointsTo(span, buffer);
- Assert.Equal(span.Length, bufferLength);
- }
- }
-
- [Fact]
- public void Span()
- {
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(42))
- {
- Span span = buffer.Span;
-
- // Assert.Equal(buffer.Array, span.ToArray());
- // Assert.Equal(0, span.Start);
- Assert.SpanPointsTo(span, buffer);
- Assert.Equal(42, span.Length);
- }
- }
-
- public class Slice
- {
-
- [Theory]
- [InlineData(7, 2)]
- [InlineData(123, 17)]
- public void WithStartOnly(int bufferLength, int start)
- {
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(bufferLength))
- {
- Span span = buffer.Slice(start);
-
- Assert.SpanPointsTo(span, buffer, start);
- Assert.Equal(span.Length, bufferLength - start);
- }
- }
-
- [Theory]
- [InlineData(7, 2, 5)]
- [InlineData(123, 17, 42)]
- public void WithStartAndLength(int bufferLength, int start, int spanLength)
- {
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(bufferLength))
- {
- Span span = buffer.Slice(start, spanLength);
-
- Assert.SpanPointsTo(span, buffer, start);
- Assert.Equal(span.Length, spanLength);
- }
- }
- }
-
- [Fact]
- public void UnPinAndTakeArrayOwnership()
- {
- TestStructs.Foo[] data = null;
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(42))
- {
- data = buffer.TakeArrayOwnership();
- Assert.True(buffer.IsDisposedOrLostArrayOwnership);
- }
-
- Assert.NotNull(data);
- Assert.True(data.Length >= 42);
- }
-
- public class Pin
- {
- [Fact]
- public void ReturnsPinnedPointerToTheBeginningOfArray()
- {
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(42))
- {
- TestStructs.Foo* actual = (TestStructs.Foo*)buffer.Pin();
- fixed (TestStructs.Foo* expected = buffer.Array)
- {
- Assert.Equal(expected, actual);
- }
- }
- }
-
- [Fact]
- public void SecondCallReturnsTheSamePointer()
- {
- using (Buffer buffer = Configuration.Default.MemoryManager.Allocate(42))
- {
- IntPtr ptr1 = buffer.Pin();
- IntPtr ptr2 = buffer.Pin();
-
- Assert.Equal(ptr1, ptr2);
- }
- }
-
- [Fact]
- public void WhenCalledOnDisposedBuffer_ThrowsInvalidOperationException()
- {
- Buffer buffer = Configuration.Default.MemoryManager.Allocate(42);
- buffer.Dispose();
-
- Assert.Throws(() => buffer.Pin());
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs b/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs
index 757c8fcf9f..049c4c6ba9 100644
--- a/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs
+++ b/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+// ReSharper disable InconsistentNaming
+// ReSharper disable AccessToStaticMemberViaDerivedType
namespace SixLabors.ImageSharp.Tests.Memory
{
using System;
@@ -30,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
{
float[] stuff = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
- Span span = new Span(stuff);
+ var span = new Span(stuff);
ref Vector v = ref span.FetchVector();
@@ -39,199 +41,8 @@ namespace SixLabors.ImageSharp.Tests.Memory
Assert.Equal(2, v[2]);
Assert.Equal(3, v[3]);
}
-
- [Fact]
- public void AsBytes()
- {
- TestStructs.Foo[] fooz = { new TestStructs.Foo(1, 2), new TestStructs.Foo(3, 4), new TestStructs.Foo(5, 6) };
-
- using (Buffer colorBuf = new Buffer(fooz))
- {
- Span orig = colorBuf.Slice(1);
- Span asBytes = orig.AsBytes();
-
- // Assert.Equal(asBytes.Start, sizeof(Foo));
- Assert.Equal(orig.Length * Unsafe.SizeOf(), asBytes.Length);
- Assert.SameRefs(ref orig.DangerousGetPinnableReference(), ref asBytes.DangerousGetPinnableReference());
- }
- }
-
- public class Construct
- {
- [Fact]
- public void Basic()
- {
- TestStructs.Foo[] array = TestStructs.Foo.CreateArray(3);
-
- // Act:
- Span span = new Span(array);
-
- // Assert:
- Assert.Equal(array, span.ToArray());
- Assert.Equal(3, span.Length);
- Assert.SameRefs(ref array[0], ref span.DangerousGetPinnableReference());
- }
-
- [Fact]
- public void WithStart()
- {
- TestStructs.Foo[] array = TestStructs.Foo.CreateArray(4);
- int start = 2;
-
- // Act:
- Span span = new Span(array, start);
-
- // Assert:
- Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
- Assert.Equal(array.Length - start, span.Length);
- }
-
- [Fact]
- public void WithStartAndLength()
- {
- TestStructs.Foo[] array = TestStructs.Foo.CreateArray(10);
- int start = 2;
- int length = 3;
- // Act:
- Span span = new Span(array, start, length);
-
- // Assert:
- Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
- Assert.Equal(length, span.Length);
- }
- }
-
- public class Slice
- {
- [Fact]
- public void StartOnly()
- {
- TestStructs.Foo[] array = TestStructs.Foo.CreateArray(5);
- int start0 = 2;
- int start1 = 2;
- int totalOffset = start0 + start1;
-
- Span span = new Span(array, start0);
-
- // Act:
- span = span.Slice(start1);
-
- // Assert:
- Assert.SameRefs(ref array[totalOffset], ref span.DangerousGetPinnableReference());
- Assert.Equal(array.Length - totalOffset, span.Length);
- }
-
- [Fact]
- public void StartAndLength()
- {
- TestStructs.Foo[] array = TestStructs.Foo.CreateArray(10);
- int start0 = 2;
- int start1 = 2;
- int totalOffset = start0 + start1;
- int sliceLength = 3;
-
- Span span = new Span(array, start0);
-
- // Act:
- span = span.Slice(start1, sliceLength);
-
- // Assert:
- Assert.SameRefs(ref array[totalOffset], ref span.DangerousGetPinnableReference());
- Assert.Equal(sliceLength, span.Length);
- }
- }
-
- //[Theory]
- //[InlineData(4)]
- //[InlineData(1500)]
- //public void Clear(int count)
- //{
- // Foo[] array = Foo.CreateArray(count + 42);
-
- // int offset = 2;
- // Span ap = new Span(array, offset);
-
- // // Act:
- // ap.Clear(count);
-
- // Assert.NotEqual(default(Foo), array[offset - 1]);
- // Assert.Equal(default(Foo), array[offset]);
- // Assert.Equal(default(Foo), array[offset + count - 1]);
- // Assert.NotEqual(default(Foo), array[offset + count]);
- //}
-
- public class Indexer
- {
- public static readonly TheoryData IndexerData =
- new TheoryData()
- {
- { 10, 0, 0 },
- { 10, 2, 0 },
- { 16, 0, 3 },
- { 16, 2, 3 },
- { 10, 0, 9 },
- { 10, 1, 8 }
- };
-
- [Theory]
- [MemberData(nameof(IndexerData))]
- public void Read(int length, int start, int index)
- {
- TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
- Span span = new Span(a, start);
-
- TestStructs.Foo element = span[index];
-
- Assert.Equal(a[start + index], element);
- }
-
- [Theory]
- [MemberData(nameof(IndexerData))]
- public void Write(int length, int start, int index)
- {
- TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
- Span span = new Span(a, start);
-
- span[index] = new TestStructs.Foo(666, 666);
-
- Assert.Equal(new TestStructs.Foo(666, 666), a[start + index]);
- }
-
- [Theory]
- [InlineData(10, 0, 0, 5)]
- [InlineData(10, 1, 1, 5)]
- [InlineData(10, 1, 1, 6)]
- [InlineData(10, 1, 1, 7)]
- public void AsBytes_Read(int length, int start, int index, int byteOffset)
- {
- TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
- Span span = new Span(a, start);
-
- Span bytes = span.AsBytes();
-
- byte actual = bytes[index * Unsafe.SizeOf() + byteOffset];
-
- ref byte baseRef = ref Unsafe.As(ref a[0]);
- byte expected = Unsafe.Add(ref baseRef, (start + index) * Unsafe.SizeOf() + byteOffset);
-
- Assert.Equal(expected, actual);
- }
- }
-
- [Theory]
- [InlineData(0, 4)]
- [InlineData(2, 4)]
- [InlineData(3, 4)]
- public void DangerousGetPinnableReference(int start, int length)
- {
- TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
- Span span = new Span(a, start);
- ref TestStructs.Foo r = ref span.DangerousGetPinnableReference();
-
- Assert.True(Unsafe.AreSame(ref a[start], ref r));
- }
-
- public class Copy
+
+ public class SpanHelper_Copy
{
private static void AssertNotDefault(T[] data, int idx)
where T : struct
@@ -267,8 +78,8 @@ namespace SixLabors.ImageSharp.Tests.Memory
TestStructs.Foo[] source = TestStructs.Foo.CreateArray(count + 2);
TestStructs.Foo[] dest = new TestStructs.Foo[count + 5];
- Span apSource = new Span(source, 1);
- Span apDest = new Span(dest, 1);
+ var apSource = new Span(source, 1);
+ var apDest = new Span(dest, 1);
SpanHelper.Copy(apSource, apDest, count - 1);
@@ -290,8 +101,8 @@ namespace SixLabors.ImageSharp.Tests.Memory
TestStructs.AlignedFoo[] source = TestStructs.AlignedFoo.CreateArray(count + 2);
TestStructs.AlignedFoo[] dest = new TestStructs.AlignedFoo[count + 5];
- Span apSource = new Span(source, 1);
- Span apDest = new Span(dest, 1);
+ var apSource = new Span(source, 1);
+ var apDest = new Span(dest, 1);
SpanHelper.Copy(apSource, apDest, count - 1);
@@ -313,8 +124,8 @@ namespace SixLabors.ImageSharp.Tests.Memory
int[] source = CreateTestInts(count + 2);
int[] dest = new int[count + 5];
- Span apSource = new Span(source, 1);
- Span apDest = new Span(dest, 1);
+ var apSource = new Span(source, 1);
+ var apDest = new Span(dest, 1);
SpanHelper.Copy(apSource, apDest, count - 1);
@@ -337,8 +148,8 @@ namespace SixLabors.ImageSharp.Tests.Memory
TestStructs.Foo[] source = TestStructs.Foo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(TestStructs.Foo) * 2];
- Span apSource = new Span(source, 1);
- Span apDest = new Span(dest, sizeof(TestStructs.Foo));
+ var apSource = new Span(source, 1);
+ var apDest = new Span(dest, sizeof(TestStructs.Foo));
SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(TestStructs.Foo));
@@ -360,8 +171,8 @@ namespace SixLabors.ImageSharp.Tests.Memory
TestStructs.AlignedFoo[] source = TestStructs.AlignedFoo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(TestStructs.AlignedFoo) * 2];
- Span apSource = new Span(source, 1);
- Span apDest = new Span(dest, sizeof(TestStructs.AlignedFoo));
+ var apSource = new Span(source, 1);
+ var apDest = new Span(dest, sizeof(TestStructs.AlignedFoo));
SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(TestStructs.AlignedFoo));
@@ -383,8 +194,8 @@ namespace SixLabors.ImageSharp.Tests.Memory
int[] source = CreateTestInts(count + 2);
byte[] dest = new byte[destCount + sizeof(int) + 1];
- Span