Browse Source

Merge remote-tracking branch 'remotes/origin/master' into sw/draw-text-optermizations

af/merge-core
Scott Williams 8 years ago
parent
commit
f19df193c1
  1. 7
      src/ImageSharp.Drawing/Primitives/Region.cs
  2. 21
      src/ImageSharp.Drawing/Primitives/ShapeRegion.cs
  3. 14
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs
  4. 12
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/ImageBrush{TPixel}.cs
  5. 14
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/PatternBrush{TPixel}.cs
  6. 14
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/RecolorBrush{TPixel}.cs
  7. 18
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs
  8. 10
      src/ImageSharp.Drawing/Processing/Drawing/Processors/DrawImageProcessor.cs
  9. 8
      src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs
  10. 65
      src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs
  11. 114
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  12. 2
      src/ImageSharp/Advanced/IPixelSource.cs
  13. 8
      src/ImageSharp/Common/Helpers/ParallelFor.cs
  14. 8
      src/ImageSharp/Configuration.cs
  15. 24
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  16. 2
      src/ImageSharp/Formats/Bmp/BmpEncoder.cs
  17. 16
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  18. 20
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  19. 2
      src/ImageSharp/Formats/Gif/GifEncoder.cs
  20. 16
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  21. 18
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  22. 16
      src/ImageSharp/Formats/Gif/LzwEncoder.cs
  23. 2
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
  24. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
  25. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
  26. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
  27. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
  28. 16
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
  29. 3
      src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
  30. 8
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs
  31. 4
      src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs
  32. 8
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/DoubleBufferedStreamReader.cs
  33. 12
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
  34. 14
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
  35. 11
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
  36. 24
      src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
  37. 2
      src/ImageSharp/Formats/Png/PngChunk.cs
  38. 48
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  39. 2
      src/ImageSharp/Formats/Png/PngEncoder.cs
  40. 60
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  41. 6
      src/ImageSharp/Image.Decode.cs
  42. 59
      src/ImageSharp/Image.WrapMemory.cs
  43. 11
      src/ImageSharp/ImageFrameCollection.cs
  44. 70
      src/ImageSharp/ImageFrame{TPixel}.cs
  45. 28
      src/ImageSharp/Image{TPixel}.cs
  46. 24
      src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs
  47. 20
      src/ImageSharp/Memory/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
  48. 24
      src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs
  49. 24
      src/ImageSharp/Memory/BasicArrayBuffer.cs
  50. 5
      src/ImageSharp/Memory/BasicByteBuffer.cs
  51. 29
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  52. 40
      src/ImageSharp/Memory/Buffer2D{T}.cs
  53. 20
      src/ImageSharp/Memory/BufferArea{T}.cs
  54. 14
      src/ImageSharp/Memory/BufferExtensions.cs
  55. 34
      src/ImageSharp/Memory/ConsumedBuffer.cs
  56. 8
      src/ImageSharp/Memory/IBuffer2D{T}.cs
  57. 27
      src/ImageSharp/Memory/IBuffer{T}.cs
  58. 2
      src/ImageSharp/Memory/IManagedByteBuffer.cs
  59. 43
      src/ImageSharp/Memory/ManagedBufferBase.cs
  60. 14
      src/ImageSharp/Memory/MemoryAllocator.cs
  61. 46
      src/ImageSharp/Memory/MemoryAllocatorExtensions.cs
  62. 6
      src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs
  63. 13
      src/ImageSharp/PixelAccessor{TPixel}.cs
  64. 44
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
  65. 2
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt
  66. 6
      src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs
  67. 2
      src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs
  68. 6
      src/ImageSharp/Processing/Convolution/Processors/Convolution2DProcessor.cs
  69. 4
      src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs
  70. 6
      src/ImageSharp/Processing/Convolution/Processors/ConvolutionProcessor.cs
  71. 1
      src/ImageSharp/Processing/Convolution/Processors/SobelProcessor.cs
  72. 4
      src/ImageSharp/Processing/DefaultInternalImageProcessorContext.cs
  73. 6
      src/ImageSharp/Processing/Effects/Processors/OilPaintingProcessor.cs
  74. 6
      src/ImageSharp/Processing/IImageProcessingContext{TPixel}.cs
  75. 12
      src/ImageSharp/Processing/Overlays/Processors/BackgroundColorProcessor.cs
  76. 12
      src/ImageSharp/Processing/Overlays/Processors/GlowProcessor.cs
  77. 12
      src/ImageSharp/Processing/Overlays/Processors/VignetteProcessor.cs
  78. 2
      src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
  79. 156
      src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs
  80. 8
      src/ImageSharp/Processing/Transforms/Processors/AffineTransformProcessor.cs
  81. 1
      src/ImageSharp/Processing/Transforms/Processors/CropProcessor.cs
  82. 10
      src/ImageSharp/Processing/Transforms/Processors/FlipProcessor.cs
  83. 8
      src/ImageSharp/Processing/Transforms/Processors/ProjectiveTransformProcessor.cs
  84. 18
      src/ImageSharp/Processing/Transforms/Processors/ResizeProcessor.cs
  85. 8
      src/ImageSharp/Processing/Transforms/Processors/WeightsBuffer.cs
  86. 4
      src/ImageSharp/Processing/Transforms/Processors/WeightsWindow.cs
  87. 2
      tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs
  88. 4
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs
  89. 4
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
  90. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs
  91. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
  92. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  93. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  94. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
  95. 2
      tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs
  96. 16
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  97. 6
      tests/ImageSharp.Benchmarks/Samplers/Glow.cs
  98. 119
      tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs
  99. 46
      tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs
  100. 18
      tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs

7
src/ImageSharp.Drawing/Primitives/Region.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Primitives
@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Primitives
/// Gets the bounding box that entirely surrounds this region.
/// </summary>
/// <remarks>
/// This should always contains all possible points returned from <see cref="Scan(float, float[], int)"/>.
/// This should always contains all possible points returned from <see cref="Scan"/>.
/// </remarks>
public abstract Rectangle Bounds { get; }
@ -28,8 +29,8 @@ namespace SixLabors.ImageSharp.Primitives
/// </summary>
/// <param name="y">The position along the y axis to find intersections.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The point in the buffer to start setting offset.</param>
/// <param name="configuration">A <see cref="Configuration"/> instance in the context of the caller.</param>
/// <returns>The number of intersections found.</returns>
public abstract int Scan(float y, float[] buffer, int offset);
public abstract int Scan(float y, Span<float> buffer, Configuration configuration);
}
}

21
src/ImageSharp.Drawing/Primitives/ShapeRegion.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Memory;
using SixLabors.Primitives;
using SixLabors.Shapes;
@ -39,21 +40,23 @@ namespace SixLabors.ImageSharp.Primitives
public override Rectangle Bounds { get; }
/// <inheritdoc/>
public override int Scan(float y, float[] buffer, int offset)
public override int Scan(float y, Span<float> buffer, Configuration configuration)
{
var start = new PointF(this.Bounds.Left - 1, y);
var end = new PointF(this.Bounds.Right + 1, y);
// TODO: This is a temporary workaround because of the lack of Span<T> API-s on IPath. We should use MemoryManager.Allocate() here!
var innerBuffer = new PointF[buffer.Length];
int count = this.Shape.FindIntersections(start, end, innerBuffer, 0);
for (int i = 0; i < count; i++)
using (IBuffer<PointF> tempBuffer = configuration.MemoryAllocator.Allocate<PointF>(buffer.Length))
{
buffer[i + offset] = innerBuffer[i].X;
}
Span<PointF> innerBuffer = tempBuffer.GetSpan();
int count = this.Shape.FindIntersections(start, end, innerBuffer);
return count;
for (int i = 0; i < count; i++)
{
buffer[i] = innerBuffer[i].X;
}
return count;
}
}
}
}

14
src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs

@ -3,8 +3,8 @@
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
{
@ -65,13 +65,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <remarks>scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.</remarks>
internal virtual void Apply(Span<float> scanline, int x, int y)
{
MemoryManager memoryManager = this.Target.MemoryManager;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
using (IBuffer<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++)
{
@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

12
src/ImageSharp.Drawing/Processing/Drawing/Brushes/ImageBrush{TPixel}.cs

@ -3,8 +3,8 @@
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
@ -118,11 +118,11 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
internal override void Apply(Span<float> scanline, int x, int y)
{
// Create a span for colors
using (IBuffer<float> amountBuffer = this.Target.MemoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = this.Target.MemoryManager.Allocate<TPixel>(scanline.Length))
using (IBuffer<float> amountBuffer = this.Target.MemoryAllocator.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = this.Target.MemoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
int sourceY = (y - this.offsetY) % this.yLength;
int offsetX = x - this.offsetX;
@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(this.source.MemoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

14
src/ImageSharp.Drawing/Processing/Drawing/Brushes/PatternBrush{TPixel}.cs

@ -4,9 +4,9 @@
using System;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
@ -151,13 +151,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
internal override void Apply(Span<float> scanline, int x, int y)
{
int patternY = y % this.pattern.Rows;
MemoryManager memoryManager = this.Target.MemoryManager;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
using (IBuffer<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++)
{
@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

14
src/ImageSharp.Drawing/Processing/Drawing/Brushes/RecolorBrush{TPixel}.cs

@ -4,8 +4,8 @@
using System;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
@ -136,13 +136,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
MemoryManager memoryManager = this.Target.MemoryManager;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
using (IBuffer<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++)
{
@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

18
src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs

@ -3,8 +3,8 @@
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
@ -58,8 +58,8 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
public SolidBrushApplicator(ImageFrame<TPixel> source, TPixel color, GraphicsOptions options)
: base(source, options)
{
this.Colors = source.MemoryManager.Allocate<TPixel>(source.Width);
this.Colors.Span.Fill(color);
this.Colors = source.MemoryAllocator.Allocate<TPixel>(source.Width);
this.Colors.GetSpan().Fill(color);
}
/// <summary>
@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <returns>
/// The color
/// </returns>
internal override TPixel this[int x, int y] => this.Colors.Span[x];
internal override TPixel this[int x, int y] => this.Colors.GetSpan()[x];
/// <inheritdoc />
public override void Dispose()
@ -88,24 +88,24 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
{
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
MemoryManager memoryManager = this.Target.MemoryManager;
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
if (this.Options.BlendPercentage == 1f)
{
this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, scanline);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
}
else
{
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<float> amountSpan = amountBuffer.GetSpan();
for (int i = 0; i < scanline.Length; i++)
{
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}
this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, amountSpan);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan);
}
}
}

10
src/ImageSharp.Drawing/Processing/Drawing/Processors/DrawImageProcessor.cs

@ -4,9 +4,9 @@
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors
@ -133,11 +133,11 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
int width = maxX - minX;
MemoryManager memoryManager = this.Image.GetConfiguration().MemoryManager;
MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator;
using (IBuffer<float> amount = memoryManager.Allocate<float>(width))
using (IBuffer<float> amount = memoryAllocator.Allocate<float>(width))
{
amount.Span.Fill(this.Opacity);
amount.GetSpan().Fill(this.Opacity);
Parallel.For(
minY,
@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
{
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend(memoryManager, background, background, foreground, amount.Span);
blender.Blend(memoryAllocator, background, background, foreground, amount.GetSpan());
});
}
}

8
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs

@ -4,10 +4,10 @@
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors
@ -77,13 +77,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
startY = 0;
}
using (IBuffer<float> amount = source.MemoryManager.Allocate<float>(width))
using (IBuffer<float> amount = source.MemoryAllocator.Allocate<float>(width))
using (BrushApplicator<TPixel> applicator = this.brush.CreateApplicator(
source,
sourceRectangle,
this.options))
{
amount.Span.Fill(1f);
amount.GetSpan().Fill(1f);
Parallel.For(
minY,
@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
int offsetY = y - startY;
int offsetX = minX - startX;
applicator.Apply(amount.Span, offsetX, offsetY);
applicator.Apply(amount.GetSpan(), offsetX, offsetY);
});
}
}

65
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs

@ -3,11 +3,11 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors
@ -103,36 +103,35 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
using (BrushApplicator<TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options))
{
int scanlineWidth = maxX - minX;
using (BasicArrayBuffer<float> buffer = source.MemoryManager.AllocateFake<float>(maxIntersections))
using (BasicArrayBuffer<float> scanline = source.MemoryManager.AllocateFake<float>(scanlineWidth))
using (IBuffer<float> bBuffer = source.MemoryAllocator.Allocate<float>(maxIntersections))
using (IBuffer<float> bScanline = source.MemoryAllocator.Allocate<float>(scanlineWidth))
{
bool scanlineDirty = true;
float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount;
Span<float> buffer = bBuffer.GetSpan();
Span<float> scanline = bScanline.GetSpan();
for (int y = minY; y < maxY; y++)
{
if (scanlineDirty)
{
// clear the buffer
for (int x = 0; x < scanlineWidth; x++)
{
scanline[x] = 0;
}
scanline.Clear();
scanlineDirty = false;
}
float yPlusOne = y + 1;
for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
{
int pointsFound = region.Scan(subPixel + offset, buffer.Array, 0);
int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
if (pointsFound == 0)
{
// nothing on this line skip
continue;
}
QuickSort(new Span<float>(buffer.Array, 0, pointsFound));
QuickSort(buffer.Slice(0, pointsFound));
for (int point = 0; point < pointsFound; point += 2)
{
@ -188,7 +187,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
}
}
applicator.Apply(scanline.Span, minX, y);
applicator.Apply(scanline, minX, y);
}
}
}
@ -196,31 +195,45 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap(Span<float> data, int left, int right)
private static void Swap(ref float left, ref float right)
{
float tmp = data[left];
data[left] = data[right];
data[right] = tmp;
float tmp = left;
left = right;
right = tmp;
}
private static void QuickSort(Span<float> data)
{
QuickSort(data, 0, data.Length - 1);
if (data.Length < 2)
{
return;
}
else if (data.Length == 2)
{
if (data[0] > data[1])
{
Swap(ref data[0], ref data[1]);
}
return;
}
QuickSort(ref data[0], 0, data.Length - 1);
}
private static void QuickSort(Span<float> data, int lo, int hi)
private static void QuickSort(ref float data0, int lo, int hi)
{
if (lo < hi)
{
int p = Partition(data, lo, hi);
QuickSort(data, lo, p);
QuickSort(data, p + 1, hi);
int p = Partition(ref data0, lo, hi);
QuickSort(ref data0, lo, p);
QuickSort(ref data0, p + 1, hi);
}
}
private static int Partition(Span<float> data, int lo, int hi)
private static int Partition(ref float data0, int lo, int hi)
{
float pivot = data[lo];
float pivot = Unsafe.Add(ref data0, lo);
int i = lo - 1;
int j = hi + 1;
while (true)
@ -229,20 +242,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
{
i = i + 1;
}
while (data[i] < pivot && i < hi);
while (Unsafe.Add(ref data0, i) < pivot && i < hi);
do
{
j = j - 1;
}
while (data[j] > pivot && j > lo);
while (Unsafe.Add(ref data0, j) > pivot && j > lo);
if (i >= j)
{
return j;
}
Swap(data, i, j);
Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j));
}
}
}

114
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -3,8 +3,8 @@
using System;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Advanced
{
@ -23,6 +23,52 @@ namespace SixLabors.ImageSharp.Advanced
where TPixel : struct, IPixel<TPixel>
=> GetConfiguration((IConfigurable)source);
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelSpan<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.GetPixelMemory().Span;
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelSpan<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelSpan();
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelRowSpan<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.PixelBuffer.GetRowSpan(rowIndex);
/// <summary>
/// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelRowSpan<TPixel>(this Image<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelRowSpan(rowIndex);
/// <summary>
/// Returns a reference to the 0th element of the Pixel buffer,
/// allowing direct manipulation of pixel data through unsafe operations.
@ -31,9 +77,10 @@ namespace SixLabors.ImageSharp.Advanced
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image frame</param>
/// <returns>A pinnable reference the first root of the pixel buffer.</returns>
[Obsolete("This method will be removed in our next release! Please use MemoryMarshal.GetReference(source.GetPixelSpan())!")]
public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> ref DangerousGetPinnableReferenceToPixelBuffer((IPixelSource<TPixel>)source);
=> ref DangerousGetPinnableReferenceToPixelBuffer((IPixelSource<TPixel>)source);
/// <summary>
/// Returns a reference to the 0th element of the Pixel buffer,
@ -43,59 +90,68 @@ namespace SixLabors.ImageSharp.Advanced
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param>
/// <returns>A pinnable reference the first root of the pixel buffer.</returns>
[Obsolete("This method will be removed in our next release! Please use MemoryMarshal.GetReference(source.GetPixelSpan())!")]
public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> ref source.Frames.RootFrame.DangerousGetPinnableReferenceToPixelBuffer();
=> ref source.Frames.RootFrame.DangerousGetPinnableReferenceToPixelBuffer();
/// <summary>
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format.
/// Gets the representation of the pixels as a <see cref="Memory{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelSpan<TPixel>(this ImageFrame<TPixel> source)
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source <see cref="ImageFrame{TPixel}"/></param>
/// <returns>The <see cref="Memory{T}"/></returns>
internal static Memory<TPixel> GetPixelMemory<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> GetSpan(source);
{
return source.PixelBuffer.Buffer.Memory;
}
/// <summary>
/// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row.
/// Gets the representation of the pixels as a <see cref="Memory{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="row">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelRowSpan<TPixel>(this ImageFrame<TPixel> source, int row)
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source <see cref="Image{TPixel}"/></param>
/// <returns>The <see cref="Memory{T}"/></returns>
internal static Memory<TPixel> GetPixelMemory<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> GetSpan(source, row);
{
return source.Frames.RootFrame.GetPixelMemory();
}
/// <summary>
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format.
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelSpan<TPixel>(this Image<TPixel> source)
internal static Memory<TPixel> GetPixelRowMemory<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelSpan();
=> source.PixelBuffer.GetRowMemory(rowIndex);
/// <summary>
/// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row.
/// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="row">The row.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelRowSpan<TPixel>(this Image<TPixel> source, int row)
internal static Memory<TPixel> GetPixelRowMemory<TPixel>(this Image<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelRowSpan(row);
=> source.Frames.RootFrame.GetPixelRowMemory(rowIndex);
/// <summary>
/// Gets the <see cref="MemoryManager"/> assigned to 'source'.
/// Gets the <see cref="MemoryAllocator"/> assigned to 'source'.
/// </summary>
/// <param name="source">The source image</param>
/// <returns>Returns the configuration.</returns>
internal static MemoryManager GetMemoryManager(this IConfigurable source)
=> GetConfiguration(source).MemoryManager;
internal static MemoryAllocator GetMemoryAllocator(this IConfigurable source)
=> GetConfiguration(source).MemoryAllocator;
/// <summary>
/// Gets the span to the backing buffer.
@ -105,7 +161,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <returns>The span retuned from Pixel source</returns>
private static Span<TPixel> GetSpan<TPixel>(IPixelSource<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.PixelBuffer.Span;
=> source.PixelBuffer.GetSpan();
/// <summary>
/// Gets the span to the backing buffer at the given row.
@ -131,7 +187,7 @@ namespace SixLabors.ImageSharp.Advanced
/// </returns>
private static Span<TPixel> GetSpan<TPixel>(Buffer2D<TPixel> source, int row)
where TPixel : struct, IPixel<TPixel>
=> source.Span.Slice(row * source.Width, source.Width);
=> source.GetSpan().Slice(row * source.Width, source.Width);
/// <summary>
/// Gets the configuration.
@ -149,6 +205,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.Span);
=> ref MemoryMarshal.GetReference(source.PixelBuffer.GetSpan());
}
}

2
src/ImageSharp/Advanced/IPixelSource.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Advanced
{

8
src/ImageSharp/Common/Helpers/ParallelFor.cs

@ -1,6 +1,6 @@
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp
/// <typeparam name="T">The value type of the buffer</typeparam>
/// <param name="fromInclusive">The start index, inclusive.</param>
/// <param name="toExclusive">The end index, exclusive.</param>
/// <param name="configuration">The <see cref="Configuration"/> used for getting the <see cref="MemoryManager"/> and <see cref="ParallelOptions"/></param>
/// <param name="configuration">The <see cref="Configuration"/> used for getting the <see cref="MemoryAllocator"/> and <see cref="ParallelOptions"/></param>
/// <param name="bufferLength">The length of the requested parallel buffer</param>
/// <param name="body">The delegate that is invoked once per iteration.</param>
public static void WithTemporaryBuffer<T>(
@ -35,12 +35,12 @@ namespace SixLabors.ImageSharp
Action<int, IBuffer<T>> body)
where T : struct
{
MemoryManager memoryManager = configuration.MemoryManager;
MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
ParallelOptions parallelOptions = configuration.ParallelOptions;
IBuffer<T> InitBuffer()
{
return memoryManager.Allocate<T>(bufferLength);
return memoryAllocator.Allocate<T>(bufferLength);
}
void CleanUpBuffer(IBuffer<T> buffer)

8
src/ImageSharp/Configuration.cs

@ -12,8 +12,8 @@ using SixLabors.ImageSharp.Formats.Png;
#if !NETSTANDARD1_1
using SixLabors.ImageSharp.IO;
#endif
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Processing;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
@ -75,9 +75,9 @@ namespace SixLabors.ImageSharp
public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager();
/// <summary>
/// Gets or sets the <see cref="MemoryManager"/> that is currently in use.
/// Gets or sets the <see cref="MemoryAllocator"/> that is currently in use.
/// </summary>
public MemoryManager MemoryManager { get; set; } = ArrayPoolMemoryManager.CreateDefault();
public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault();
/// <summary>
/// Gets the maximum header size of all the formats.
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp
{
ParallelOptions = this.ParallelOptions,
ImageFormatsManager = this.ImageFormatsManager,
MemoryManager = this.MemoryManager,
MemoryAllocator = this.MemoryAllocator,
ImageOperationsProvider = this.ImageOperationsProvider,
ReadOrigin = this.ReadOrigin,

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

@ -4,9 +4,9 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Bmp
{
@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private readonly Configuration configuration;
private readonly MemoryManager memoryManager;
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// Initializes a new instance of the <see cref="BmpDecoderCore"/> class.
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options)
{
this.configuration = configuration;
this.memoryManager = configuration.MemoryManager;
this.memoryAllocator = configuration.MemoryAllocator;
}
/// <summary>
@ -213,9 +213,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
var color = default(TPixel);
var rgba = new Rgba32(0, 0, 0, 255);
using (Buffer2D<byte> buffer = this.memoryManager.AllocateClean2D<byte>(width, height))
using (Buffer2D<byte> buffer = this.memoryAllocator.AllocateClean2D<byte>(width, height))
{
this.UncompressRle8(width, buffer.Span);
this.UncompressRle8(width, buffer.GetSpan());
for (int y = 0; y < height; y++)
{
@ -337,12 +337,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp
padding = 4 - padding;
}
using (IManagedByteBuffer row = this.memoryManager.AllocateCleanManagedByteBuffer(arrayWidth + padding))
using (IManagedByteBuffer row = this.memoryAllocator.AllocateCleanManagedByteBuffer(arrayWidth + padding))
{
TPixel color = default;
var rgba = new Rgba32(0, 0, 0, 255);
Span<byte> rowSpan = row.Span;
Span<byte> rowSpan = row.GetSpan();
for (int y = 0; y < height; y++)
{
@ -389,7 +389,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
var color = default(TPixel);
var rgba = new Rgba32(0, 0, 0, 255);
using (IManagedByteBuffer buffer = this.memoryManager.AllocateManagedByteBuffer(stride))
using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
{
for (int y = 0; y < height; y++)
{
@ -427,14 +427,14 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
int padding = CalculatePadding(width, 3);
using (IManagedByteBuffer row = this.memoryManager.AllocatePaddedPixelRowBuffer(width, 3, padding))
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, padding))
{
for (int y = 0; y < height; y++)
{
this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.PackFromBgr24Bytes(row.Span, pixelSpan, width);
PixelOperations<TPixel>.Instance.PackFromBgr24Bytes(row.GetSpan(), pixelSpan, width);
}
}
}
@ -452,14 +452,14 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
int padding = CalculatePadding(width, 4);
using (IManagedByteBuffer row = this.memoryManager.AllocatePaddedPixelRowBuffer(width, 4, padding))
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding))
{
for (int y = 0; y < height; y++)
{
this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.PackFromBgra32Bytes(row.Span, pixelSpan, width);
PixelOperations<TPixel>.Instance.PackFromBgra32Bytes(row.GetSpan(), pixelSpan, width);
}
}
}

2
src/ImageSharp/Formats/Bmp/BmpEncoder.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
var encoder = new BmpEncoderCore(this, image.GetMemoryManager());
var encoder = new BmpEncoderCore(this, image.GetMemoryAllocator());
encoder.Encode(image, stream);
}
}

16
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -3,8 +3,8 @@
using System;
using System.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Bmp
{
@ -20,16 +20,16 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private readonly BmpBitsPerPixel bitsPerPixel;
private readonly MemoryManager memoryManager;
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// Initializes a new instance of the <see cref="BmpEncoderCore"/> class.
/// </summary>
/// <param name="options">The encoder options</param>
/// <param name="memoryManager">The memory manager</param>
public BmpEncoderCore(IBmpEncoderOptions options, MemoryManager memoryManager)
/// <param name="memoryAllocator">The memory manager</param>
public BmpEncoderCore(IBmpEncoderOptions options, MemoryAllocator memoryAllocator)
{
this.memoryManager = memoryManager;
this.memoryAllocator = memoryAllocator;
this.bitsPerPixel = options.BitsPerPixel;
}
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel)
{
return this.memoryManager.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding);
return this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding);
}
/// <summary>
@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(pixelSpan, row.Span, pixelSpan.Length);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length);
stream.Write(row.Array, 0, row.Length());
}
}
@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(pixelSpan, row.Span, pixelSpan.Length);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length);
stream.Write(row.Array, 0, row.Length());
}
}

20
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -7,9 +7,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Gif
@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
public FrameDecodingMode DecodingMode { get; }
private MemoryManager MemoryManager => this.configuration.MemoryManager;
private MemoryAllocator MemoryAllocator => this.configuration.MemoryAllocator;
/// <summary>
/// Decodes the stream to the image.
@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
continue;
}
using (IManagedByteBuffer commentsBuffer = this.MemoryManager.AllocateManagedByteBuffer(length))
using (IManagedByteBuffer commentsBuffer = this.MemoryAllocator.AllocateManagedByteBuffer(length))
{
this.stream.Read(commentsBuffer.Array, 0, length);
string comments = this.TextEncoding.GetString(commentsBuffer.Array, 0, length);
@ -321,15 +321,15 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (imageDescriptor.LocalColorTableFlag)
{
int length = imageDescriptor.LocalColorTableSize * 3;
localColorTable = this.configuration.MemoryManager.AllocateManagedByteBuffer(length, true);
localColorTable = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(length, true);
this.stream.Read(localColorTable.Array, 0, length);
}
indices = this.configuration.MemoryManager.AllocateManagedByteBuffer(imageDescriptor.Width * imageDescriptor.Height, true);
indices = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(imageDescriptor.Width * imageDescriptor.Height, true);
this.ReadFrameIndices(imageDescriptor, indices.Span);
ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>((localColorTable ?? this.globalColorTable).Span);
this.ReadFrameColors(ref image, ref previousFrame, indices.Span, colorTable, imageDescriptor);
this.ReadFrameIndices(imageDescriptor, indices.GetSpan());
ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>((localColorTable ?? this.globalColorTable).GetSpan());
this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, imageDescriptor);
// Skip any remaining blocks
this.Skip(0);
@ -350,7 +350,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void ReadFrameIndices(in GifImageDescriptor imageDescriptor, Span<byte> indices)
{
int dataSize = this.stream.ReadByte();
using (var lzwDecoder = new LzwDecoder(this.configuration.MemoryManager, this.stream))
using (var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream))
{
lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize, indices);
}
@ -528,7 +528,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
this.globalColorTable = this.MemoryManager.AllocateManagedByteBuffer(globalColorTableLength, true);
this.globalColorTable = this.MemoryAllocator.AllocateManagedByteBuffer(globalColorTableLength, true);
// Read the global color table data from the stream
stream.Read(this.globalColorTable.Array, 0, globalColorTableLength);

2
src/ImageSharp/Formats/Gif/GifEncoder.cs

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
var encoder = new GifEncoderCore(image.GetConfiguration().MemoryManager, this);
var encoder = new GifEncoderCore(image.GetConfiguration().MemoryAllocator, this);
encoder.Encode(image, stream);
}
}

16
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -7,10 +7,10 @@ using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Quantization;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif
{
@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
internal sealed class GifEncoderCore
{
private readonly MemoryManager memoryManager;
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// A reusable buffer used to reduce allocations.
@ -49,11 +49,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// Initializes a new instance of the <see cref="GifEncoderCore"/> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="options">The options for the encoder.</param>
public GifEncoderCore(MemoryManager memoryManager, IGifEncoderOptions options)
public GifEncoderCore(MemoryAllocator memoryAllocator, IGifEncoderOptions options)
{
this.memoryManager = memoryManager;
this.memoryAllocator = memoryAllocator;
this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding;
this.quantizer = options.Quantizer;
this.ignoreMetadata = options.IgnoreMetadata;
@ -317,10 +317,10 @@ namespace SixLabors.ImageSharp.Formats.Gif
int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3; // The maximium number of colors for the bit depth
Rgb24 rgb = default;
using (IManagedByteBuffer colorTable = this.memoryManager.AllocateManagedByteBuffer(colorTableLength))
using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
{
ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan());
ref Rgb24 rgb24Ref = ref Unsafe.As<byte, Rgb24>(ref MemoryMarshal.GetReference(colorTable.Span));
ref Rgb24 rgb24Ref = ref Unsafe.As<byte, Rgb24>(ref MemoryMarshal.GetReference(colorTable.GetSpan()));
for (int i = 0; i < pixelCount; i++)
{
ref TPixel entry = ref Unsafe.Add(ref paletteRef, i);
@ -342,7 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteImageData<TPixel>(QuantizedFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
using (var encoder = new LzwEncoder(this.memoryManager, image.Pixels, (byte)this.bitDepth))
using (var encoder = new LzwEncoder(this.memoryAllocator, image.Pixels, (byte)this.bitDepth))
{
encoder.Encode(stream);
}

18
src/ImageSharp/Formats/Gif/LzwDecoder.cs

@ -5,7 +5,7 @@ using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif
{
@ -48,18 +48,18 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// Initializes a new instance of the <see cref="LzwDecoder"/> class
/// and sets the stream, where the compressed data should be read from.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="stream">The stream to read from.</param>
/// <exception cref="System.ArgumentNullException"><paramref name="stream"/> is null.</exception>
public LzwDecoder(MemoryManager memoryManager, Stream stream)
public LzwDecoder(MemoryAllocator memoryAllocator, Stream stream)
{
Guard.NotNull(stream, nameof(stream));
this.stream = stream;
this.prefix = memoryManager.Allocate<int>(MaxStackSize, true);
this.suffix = memoryManager.Allocate<int>(MaxStackSize, true);
this.pixelStack = memoryManager.Allocate<int>(MaxStackSize + 1, true);
this.prefix = memoryAllocator.Allocate<int>(MaxStackSize, true);
this.suffix = memoryAllocator.Allocate<int>(MaxStackSize, true);
this.pixelStack = memoryAllocator.Allocate<int>(MaxStackSize + 1, true);
}
/// <summary>
@ -102,9 +102,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
int data = 0;
int first = 0;
ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.Span);
ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.Span);
ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.Span);
ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan());
ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan());
ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan());
ref byte pixelsRef = ref MemoryMarshal.GetReference(pixels);
for (code = 0; code < clearCode; code++)

16
src/ImageSharp/Formats/Gif/LzwEncoder.cs

@ -5,7 +5,7 @@ using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif
{
@ -168,16 +168,16 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// Initializes a new instance of the <see cref="LzwEncoder"/> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="indexedPixels">The array of indexed pixels.</param>
/// <param name="colorDepth">The color depth in bits.</param>
public LzwEncoder(MemoryManager memoryManager, byte[] indexedPixels, int colorDepth)
public LzwEncoder(MemoryAllocator memoryAllocator, byte[] indexedPixels, int colorDepth)
{
this.pixelArray = indexedPixels;
this.initialCodeSize = Math.Max(2, colorDepth);
this.hashTable = memoryManager.Allocate<int>(HashSize, true);
this.codeTable = memoryManager.Allocate<int>(HashSize, true);
this.hashTable = memoryAllocator.Allocate<int>(HashSize, true);
this.codeTable = memoryAllocator.Allocate<int>(HashSize, true);
}
/// <summary>
@ -246,7 +246,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ResetCodeTable()
{
this.hashTable.Span.Fill(-1);
this.hashTable.GetSpan().Fill(-1);
}
/// <summary>
@ -293,8 +293,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.Output(this.clearCode, stream);
ref int hashTableRef = ref MemoryMarshal.GetReference(this.hashTable.Span);
ref int codeTableRef = ref MemoryMarshal.GetReference(this.codeTable.Span);
ref int hashTableRef = ref MemoryMarshal.GetReference(this.hashTable.GetSpan());
ref int codeTableRef = ref MemoryMarshal.GetReference(this.codeTable.GetSpan());
while (this.position < this.pixelArray.Length)
{

2
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs

@ -4,7 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Components

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs

@ -7,7 +7,7 @@ using System.Linq;
using System.Numerics;
using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs

@ -3,7 +3,7 @@
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder

6
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs

@ -3,7 +3,7 @@
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
@ -26,11 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <summary>
/// Initializes a new instance of the <see cref="JpegComponentPostProcessor"/> class.
/// </summary>
public JpegComponentPostProcessor(MemoryManager memoryManager, JpegImagePostProcessor imagePostProcessor, IJpegComponent component)
public JpegComponentPostProcessor(MemoryAllocator memoryAllocator, JpegImagePostProcessor imagePostProcessor, IJpegComponent component)
{
this.Component = component;
this.ImagePostProcessor = imagePostProcessor;
this.ColorBuffer = memoryManager.Allocate2D<float>(
this.ColorBuffer = memoryAllocator.Allocate2D<float>(
imagePostProcessor.PostProcessorBufferSize.Width,
imagePostProcessor.PostProcessorBufferSize.Height);

16
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs

@ -4,12 +4,10 @@
using System;
using System.Linq;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters.JpegColorConverter;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
@ -49,17 +47,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <summary>
/// Initializes a new instance of the <see cref="JpegImagePostProcessor"/> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="rawJpeg">The <see cref="IRawJpegData"/> representing the uncompressed spectral Jpeg data</param>
public JpegImagePostProcessor(MemoryManager memoryManager, IRawJpegData rawJpeg)
public JpegImagePostProcessor(MemoryAllocator memoryAllocator, IRawJpegData rawJpeg)
{
this.RawJpeg = rawJpeg;
IJpegComponent c0 = rawJpeg.Components.First();
this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / BlockRowsPerStep;
this.PostProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, PixelRowsPerStep);
this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryManager, this, c)).ToArray();
this.rgbaBuffer = memoryManager.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width);
this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryAllocator, this, c)).ToArray();
this.rgbaBuffer = memoryAllocator.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width);
this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace);
}
@ -155,11 +153,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int y = yy - this.PixelRowCounter;
var values = new JpegColorConverter.ComponentValues(buffers, y);
this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.Span);
this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan());
Span<TPixel> destRow = destination.GetPixelRowSpan(yy);
PixelOperations<TPixel>.Instance.PackFromVector4(this.rgbaBuffer.Span, destRow, destination.Width);
PixelOperations<TPixel>.Instance.PackFromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width);
}
}
}

3
src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs

@ -4,10 +4,9 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Components

8
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs

@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
@ -56,9 +56,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary>
/// Initializes <see cref="SpectralBlocks"/>
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
public void InitializeDerivedData(MemoryManager memoryManager, GolangJpegDecoderCore decoder)
public void InitializeDerivedData(MemoryAllocator memoryAllocator, GolangJpegDecoderCore decoder)
{
// For 4-component images (either CMYK or YCbCrK), we only support two
// hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
}
this.SpectralBlocks = memoryManager.Allocate2D<Block8x8>(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true);
this.SpectralBlocks = memoryAllocator.Allocate2D<Block8x8>(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true);
}
/// <summary>

4
src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs

@ -705,7 +705,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
foreach (GolangComponent component in this.Components)
{
component.InitializeDerivedData(this.configuration.MemoryManager, this);
component.InitializeDerivedData(this.configuration.MemoryAllocator, this);
}
}
}
@ -812,7 +812,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private Image<TPixel> PostProcessIntoImage<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryManager, this))
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this))
{
var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
postProcessor.PostProcess(image.Frames.RootFrame);

8
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/DoubleBufferedStreamReader.cs

@ -5,7 +5,7 @@ using System;
using System.IO;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
// TODO: This could be useful elsewhere.
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
@ -38,13 +38,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// <summary>
/// Initializes a new instance of the <see cref="DoubleBufferedStreamReader"/> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="stream">The input stream.</param>
public DoubleBufferedStreamReader(MemoryManager memoryManager, Stream stream)
public DoubleBufferedStreamReader(MemoryAllocator memoryAllocator, Stream stream)
{
this.stream = stream;
this.length = (int)stream.Length;
this.managedBuffer = memoryManager.AllocateCleanManagedByteBuffer(ChunkLength);
this.managedBuffer = memoryAllocator.AllocateCleanManagedByteBuffer(ChunkLength);
this.bufferChunk = this.managedBuffer.Array;
}

12
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs

@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
@ -17,11 +17,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// </summary>
internal class PdfJsFrameComponent : IDisposable, IJpegComponent
{
private readonly MemoryManager memoryManager;
private readonly MemoryAllocator memoryAllocator;
public PdfJsFrameComponent(MemoryManager memoryManager, PdfJsFrame frame, byte id, int horizontalFactor, int verticalFactor, byte quantizationTableIndex, int index)
public PdfJsFrameComponent(MemoryAllocator memoryAllocator, PdfJsFrame frame, byte id, int horizontalFactor, int verticalFactor, byte quantizationTableIndex, int index)
{
this.memoryManager = memoryManager;
this.memoryAllocator = memoryAllocator;
this.Frame = frame;
this.Id = id;
this.HorizontalSamplingFactor = horizontalFactor;
@ -129,14 +129,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
}
this.SpectralBlocks = this.memoryManager.Allocate2D<Block8x8>(blocksPerColumnForMcu, blocksPerLineForMcu + 1, true);
this.SpectralBlocks = this.memoryAllocator.Allocate2D<Block8x8>(blocksPerColumnForMcu, blocksPerLineForMcu + 1, true);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Block8x8 GetBlockReference(int column, int row)
{
int offset = ((this.WidthInBlocks + 1) * row) + column;
return ref Unsafe.Add(ref MemoryMarshal.GetReference(this.SpectralBlocks.Span), offset);
return ref Unsafe.Add(ref MemoryMarshal.GetReference(this.SpectralBlocks.GetSpan()), offset);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

14
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs

@ -4,7 +4,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
@ -37,17 +37,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// <summary>
/// Initializes a new instance of the <see cref="PdfJsHuffmanTable"/> struct.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="lengths">The code lengths</param>
/// <param name="values">The huffman values</param>
public PdfJsHuffmanTable(MemoryManager memoryManager, ReadOnlySpan<byte> lengths, ReadOnlySpan<byte> values)
public PdfJsHuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> lengths, ReadOnlySpan<byte> values)
{
const int length = 257;
using (IBuffer<short> huffsize = memoryManager.Allocate<short>(length))
using (IBuffer<short> huffcode = memoryManager.Allocate<short>(length))
using (IBuffer<short> huffsize = memoryAllocator.Allocate<short>(length))
using (IBuffer<short> huffcode = memoryAllocator.Allocate<short>(length))
{
ref short huffsizeRef = ref MemoryMarshal.GetReference(huffsize.Span);
ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.Span);
ref short huffsizeRef = ref MemoryMarshal.GetReference(huffsize.GetSpan());
ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan());
GenerateSizeTable(lengths, ref huffsizeRef);
GenerateCodeTable(ref huffsizeRef, ref huffcodeRef, length);

11
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs

@ -2,13 +2,14 @@
// Licensed under the Apache License, Version 2.0.
using System;
#if DEBUG
using System.Diagnostics;
#endif
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
@ -166,7 +167,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1)
{
PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span));
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.GetSpan()));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
@ -188,7 +189,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++)
{
PdfJsFrameComponent component = components[i];
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span));
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.GetSpan()));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalSamplingFactor;
@ -224,7 +225,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1)
{
PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span));
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.GetSpan()));
ref PdfJsHuffmanTable huffmanTable = ref huffmanTables[isAC ? component.ACHuffmanTableId : component.DCHuffmanTableId];
for (int n = 0; n < this.mcuToRead; n++)
@ -267,7 +268,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++)
{
PdfJsFrameComponent component = components[i];
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span));
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.GetSpan()));
ref PdfJsHuffmanTable huffmanTable = ref huffmanTables[isAC ? component.ACHuffmanTableId : component.DCHuffmanTableId];
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;

24
src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs

@ -11,12 +11,12 @@ using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
public void ParseStream(Stream stream, bool metadataOnly = false)
{
this.MetaData = new ImageMetaData();
this.InputStream = new DoubleBufferedStreamReader(this.configuration.MemoryManager, stream);
this.InputStream = new DoubleBufferedStreamReader(this.configuration.MemoryAllocator, stream);
// Check for the Start Of Image marker.
this.InputStream.Read(this.markerBuffer, 0, 2);
@ -675,7 +675,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
maxV = v;
}
var component = new PdfJsFrameComponent(this.configuration.MemoryManager, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
var component = new PdfJsFrameComponent(this.configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
this.Frame.Components[i] = component;
this.Frame.ComponentIds[i] = component.Id;
@ -703,17 +703,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
throw new ImageFormatException($"DHT has wrong length: {remaining}");
}
using (IManagedByteBuffer huffmanData = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(256))
using (IManagedByteBuffer huffmanData = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(256))
{
ref byte huffmanDataRef = ref MemoryMarshal.GetReference(huffmanData.Span);
ref byte huffmanDataRef = ref MemoryMarshal.GetReference(huffmanData.GetSpan());
for (int i = 2; i < remaining;)
{
byte huffmanTableSpec = (byte)this.InputStream.ReadByte();
this.InputStream.Read(huffmanData.Array, 0, 16);
using (IManagedByteBuffer codeLengths = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(17))
using (IManagedByteBuffer codeLengths = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(17))
{
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths.Span);
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths.GetSpan());
int codeLengthSum = 0;
for (int j = 1; j < 17; j++)
@ -721,7 +721,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
codeLengthSum += Unsafe.Add(ref codeLengthsRef, j) = Unsafe.Add(ref huffmanDataRef, j - 1);
}
using (IManagedByteBuffer huffmanValues = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(256))
using (IManagedByteBuffer huffmanValues = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(256))
{
this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum);
@ -730,8 +730,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.BuildHuffmanTable(
huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables,
huffmanTableSpec & 15,
codeLengths.Span,
huffmanValues.Span);
codeLengths.GetSpan(),
huffmanValues.GetSpan());
}
}
}
@ -817,7 +817,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BuildHuffmanTable(PdfJsHuffmanTables tables, int index, ReadOnlySpan<byte> codeLengths, ReadOnlySpan<byte> values)
{
tables[index] = new PdfJsHuffmanTable(this.configuration.MemoryManager, codeLengths, values);
tables[index] = new PdfJsHuffmanTable(this.configuration.MemoryAllocator, codeLengths, values);
}
/// <summary>
@ -834,7 +834,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
private Image<TPixel> PostProcessIntoImage<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryManager, this))
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this))
{
var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
postProcessor.PostProcess(image.Frames.RootFrame);

2
src/ImageSharp/Formats/Png/PngChunk.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Png
{

48
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -13,9 +13,9 @@ using System.Text;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Png.Filters;
using SixLabors.ImageSharp.Formats.Png.Zlib;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Png
{
@ -188,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Png
this.ignoreMetadata = options.IgnoreMetadata;
}
private MemoryManager MemoryManager => this.configuration.MemoryManager;
private MemoryAllocator MemoryAllocator => this.configuration.MemoryAllocator;
/// <summary>
/// Decodes the stream to the image.
@ -410,8 +410,8 @@ namespace SixLabors.ImageSharp.Formats.Png
this.bytesPerSample = this.header.BitDepth / 8;
}
this.previousScanline = this.MemoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.scanline = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.previousScanline = this.MemoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.scanline = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
}
/// <summary>
@ -531,7 +531,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
this.currentRowBytesRead = 0;
Span<byte> scanlineSpan = this.scanline.Span;
Span<byte> scanlineSpan = this.scanline.GetSpan();
var filterType = (FilterType)scanlineSpan[0];
switch (filterType)
@ -546,17 +546,17 @@ namespace SixLabors.ImageSharp.Formats.Png
case FilterType.Up:
UpFilter.Decode(scanlineSpan, this.previousScanline.Span);
UpFilter.Decode(scanlineSpan, this.previousScanline.GetSpan());
break;
case FilterType.Average:
AverageFilter.Decode(scanlineSpan, this.previousScanline.Span, this.bytesPerPixel);
AverageFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel);
break;
case FilterType.Paeth:
PaethFilter.Decode(scanlineSpan, this.previousScanline.Span, this.bytesPerPixel);
PaethFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel);
break;
default:
@ -639,7 +639,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
Span<TPixel> rowSpan = image.GetPixelRowSpan(this.currentRow);
this.ProcessInterlacedDefilteredScanline(this.scanline.Span, rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]);
this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]);
this.SwapBuffers();
@ -727,11 +727,11 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 3;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length))
using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{
// TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length);
PixelOperations<TPixel>.Instance.PackFromRgb24Bytes(compressed.Span, rowSpan, this.header.Width);
this.From16BitTo8Bit(scanlineBuffer, compressed.GetSpan(), length);
PixelOperations<TPixel>.Instance.PackFromRgb24Bytes(compressed.GetSpan(), rowSpan, this.header.Width);
}
}
else
@ -744,12 +744,12 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 3;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length))
using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{
// TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length);
this.From16BitTo8Bit(scanlineBuffer, compressed.GetSpan(), length);
Span<Rgb24> rgb24Span = MemoryMarshal.Cast<byte, Rgb24>(compressed.Span);
Span<Rgb24> rgb24Span = MemoryMarshal.Cast<byte, Rgb24>(compressed.GetSpan());
for (int x = 0; x < this.header.Width; x++)
{
ref Rgb24 rgb24 = ref rgb24Span[x];
@ -785,11 +785,11 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 4;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length))
using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{
// TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length);
PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(compressed.Span, rowSpan, this.header.Width);
this.From16BitTo8Bit(scanlineBuffer, compressed.GetSpan(), length);
PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(compressed.GetSpan(), rowSpan, this.header.Width);
}
}
else
@ -984,9 +984,9 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 3;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length))
using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{
Span<byte> compressedSpan = compressed.Span;
Span<byte> compressedSpan = compressed.GetSpan();
// TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length);
@ -1054,9 +1054,9 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16)
{
int length = this.header.Width * 4;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length))
using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{
Span<byte> compressedSpan = compressed.Span;
Span<byte> compressedSpan = compressed.GetSpan();
// TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length);
@ -1229,7 +1229,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
this.crc.Reset();
this.crc.Update(this.chunkTypeBuffer);
this.crc.Update(chunk.Data.Span);
this.crc.Update(chunk.Data.GetSpan());
if (this.crc.Value != chunk.Crc)
{
@ -1273,7 +1273,7 @@ namespace SixLabors.ImageSharp.Formats.Png
private IManagedByteBuffer ReadChunkData(int length)
{
// We rent the buffer here to return it afterwards in Decode()
IManagedByteBuffer buffer = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(length);
IManagedByteBuffer buffer = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(length);
this.currentStream.Read(buffer.Array, 0, length);

2
src/ImageSharp/Formats/Png/PngEncoder.cs

@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
using (var encoder = new PngEncoderCore(image.GetMemoryManager(), this))
using (var encoder = new PngEncoderCore(image.GetMemoryAllocator(), this))
{
encoder.Encode(image, stream);
}

60
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -8,9 +8,9 @@ using System.Linq;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Png.Filters;
using SixLabors.ImageSharp.Formats.Png.Zlib;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Quantization;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Png
{
@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary>
internal sealed class PngEncoderCore : IDisposable
{
private readonly MemoryManager memoryManager;
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// The maximum block size, defaults at 64k for uncompressed blocks.
@ -144,11 +144,11 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary>
/// Initializes a new instance of the <see cref="PngEncoderCore"/> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="options">The options for influencing the encoder</param>
public PngEncoderCore(MemoryManager memoryManager, IPngEncoderOptions options)
public PngEncoderCore(MemoryAllocator memoryAllocator, IPngEncoderOptions options)
{
this.memoryManager = memoryManager;
this.memoryAllocator = memoryAllocator;
this.pngColorType = options.PngColorType;
this.pngFilterMethod = options.PngFilterMethod;
this.compressionLevel = options.CompressionLevel;
@ -283,11 +283,11 @@ namespace SixLabors.ImageSharp.Formats.Png
{
if (this.bytesPerPixel == 4)
{
PixelOperations<TPixel>.Instance.ToRgba32Bytes(rowSpan, this.rawScanline.Span, this.width);
PixelOperations<TPixel>.Instance.ToRgba32Bytes(rowSpan, this.rawScanline.GetSpan(), this.width);
}
else
{
PixelOperations<TPixel>.Instance.ToRgb24Bytes(rowSpan, this.rawScanline.Span, this.width);
PixelOperations<TPixel>.Instance.ToRgb24Bytes(rowSpan, this.rawScanline.GetSpan(), this.width);
}
}
@ -320,23 +320,23 @@ namespace SixLabors.ImageSharp.Formats.Png
switch (this.pngFilterMethod)
{
case PngFilterMethod.None:
NoneFilter.Encode(this.rawScanline.Span, this.result.Span);
NoneFilter.Encode(this.rawScanline.GetSpan(), this.result.GetSpan());
return this.result;
case PngFilterMethod.Sub:
SubFilter.Encode(this.rawScanline.Span, this.sub.Span, this.bytesPerPixel, out int _);
SubFilter.Encode(this.rawScanline.GetSpan(), this.sub.GetSpan(), this.bytesPerPixel, out int _);
return this.sub;
case PngFilterMethod.Up:
UpFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.up.Span, out int _);
UpFilter.Encode(this.rawScanline.GetSpan(), this.previousScanline.GetSpan(), this.up.GetSpan(), out int _);
return this.up;
case PngFilterMethod.Average:
AverageFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.average.Span, this.bytesPerPixel, out int _);
AverageFilter.Encode(this.rawScanline.GetSpan(), this.previousScanline.GetSpan(), this.average.GetSpan(), this.bytesPerPixel, out int _);
return this.average;
case PngFilterMethod.Paeth:
PaethFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.paeth.Span, this.bytesPerPixel, out int _);
PaethFilter.Encode(this.rawScanline.GetSpan(), this.previousScanline.GetSpan(), this.paeth.GetSpan(), this.bytesPerPixel, out int _);
return this.paeth;
default:
@ -354,21 +354,21 @@ 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.Span, this.result.Span);
NoneFilter.Encode(this.rawScanline.GetSpan(), this.result.GetSpan());
return this.result;
}
Span<byte> scanSpan = this.rawScanline.Span;
Span<byte> prevSpan = this.previousScanline.Span;
Span<byte> scanSpan = this.rawScanline.GetSpan();
Span<byte> prevSpan = this.previousScanline.GetSpan();
// 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.Span, out int currentSum);
UpFilter.Encode(scanSpan, prevSpan, this.up.GetSpan(), out int currentSum);
int lowestSum = currentSum;
IManagedByteBuffer actualResult = this.up;
PaethFilter.Encode(scanSpan, prevSpan, this.paeth.Span, this.bytesPerPixel, out currentSum);
PaethFilter.Encode(scanSpan, prevSpan, this.paeth.GetSpan(), this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum)
{
@ -376,7 +376,7 @@ namespace SixLabors.ImageSharp.Formats.Png
actualResult = this.paeth;
}
SubFilter.Encode(scanSpan, this.sub.Span, this.bytesPerPixel, out currentSum);
SubFilter.Encode(scanSpan, this.sub.GetSpan(), this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum)
{
@ -384,7 +384,7 @@ namespace SixLabors.ImageSharp.Formats.Png
actualResult = this.sub;
}
AverageFilter.Encode(scanSpan, prevSpan, this.average.Span, this.bytesPerPixel, out currentSum);
AverageFilter.Encode(scanSpan, prevSpan, this.average.GetSpan(), this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum)
{
@ -460,11 +460,11 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba32 rgba = default;
bool anyAlpha = false;
using (IManagedByteBuffer colorTable = this.memoryManager.AllocateManagedByteBuffer(colorTableLength))
using (IManagedByteBuffer alphaTable = this.memoryManager.AllocateManagedByteBuffer(pixelCount))
using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(pixelCount))
{
Span<byte> colorTableSpan = colorTable.Span;
Span<byte> alphaTableSpan = alphaTable.Span;
Span<byte> colorTableSpan = colorTable.GetSpan();
Span<byte> alphaTableSpan = alphaTable.GetSpan();
for (byte i = 0; i < pixelCount; i++)
{
@ -552,16 +552,16 @@ namespace SixLabors.ImageSharp.Formats.Png
this.bytesPerScanline = this.width * this.bytesPerPixel;
int resultLength = this.bytesPerScanline + 1;
this.previousScanline = this.memoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.rawScanline = this.memoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.result = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
this.previousScanline = this.memoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.rawScanline = this.memoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.result = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
if (this.pngColorType != PngColorType.Palette)
{
this.sub = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
this.up = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
this.average = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
this.paeth = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength);
this.sub = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
this.up = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
this.average = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
this.paeth = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
}
byte[] buffer;

6
src/ImageSharp/Image.Decode.cs

@ -4,8 +4,8 @@
using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp
return null;
}
using (IManagedByteBuffer buffer = config.MemoryManager.AllocateManagedByteBuffer(maxHeaderSize))
using (IManagedByteBuffer buffer = config.MemoryAllocator.AllocateManagedByteBuffer(maxHeaderSize))
{
long startPosition = stream.Position;
stream.Read(buffer.Array, 0, maxHeaderSize);
stream.Position = startPosition;
return config.ImageFormatsManager.FormatDetectors.Select(x => x.DetectFormat(buffer.Span)).LastOrDefault(x => x != null);
return config.ImageFormatsManager.FormatDetectors.Select(x => x.DetectFormat(buffer.GetSpan())).LastOrDefault(x => x != null);
}
}

59
src/ImageSharp/Image.WrapMemory.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
/// <content>
/// Adds static methods allowing wrapping an existing memory area as an image.
/// </content>
public static partial class Image
{
// TODO: This is a WIP API, should be public when finished.
/// <summary>
/// Wraps an existing contigous memory area of 'width'x'height' pixels,
/// allowing to view/manipulate it as an ImageSharp <see cref="Image{TPixel}"/> instance.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="config">The <see cref="Configuration"/></param>
/// <param name="pixelMemory">The pixel memory</param>
/// <param name="width">The width of the memory image</param>
/// <param name="height">The height of the memory image</param>
/// <param name="metaData">The <see cref="ImageMetaData"/></param>
/// <returns>An <see cref="Image{TPixel}"/> instance</returns>
internal static Image<TPixel> WrapMemory<TPixel>(
Configuration config,
Memory<TPixel> pixelMemory,
int width,
int height,
ImageMetaData metaData)
where TPixel : struct, IPixel<TPixel>
{
var buffer = new ConsumedBuffer<TPixel>(pixelMemory);
return new Image<TPixel>(config, buffer, width, height, metaData);
}
/// <summary>
/// Wraps an existing contigous memory area of 'width'x'height' pixels,
/// allowing to view/manipulate it as an ImageSharp <see cref="Image{TPixel}"/> instance.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="pixelMemory">The pixel memory</param>
/// <param name="width">The width of the memory image</param>
/// <param name="height">The height of the memory image</param>
/// <returns>An <see cref="Image{TPixel}"/> instance</returns>
internal static Image<TPixel> WrapMemory<TPixel>(
Memory<TPixel> pixelMemory,
int width,
int height)
where TPixel : struct, IPixel<TPixel>
{
return WrapMemory(Configuration.Default, pixelMemory, width, height, new ImageMetaData());
}
}
}

11
src/ImageSharp/ImageFrameCollection.cs

@ -6,6 +6,7 @@ using System.Collections;
using System.Collections.Generic;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
@ -29,6 +30,16 @@ namespace SixLabors.ImageSharp
this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, backgroundColor));
}
internal ImageFrameCollection(Image<TPixel> parent, int width, int height, IBuffer<TPixel> consumedBuffer)
{
Guard.NotNull(parent, nameof(parent));
this.parent = parent;
// Frames are already cloned within the caller
this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, consumedBuffer));
}
internal ImageFrameCollection(Image<TPixel> parent, IEnumerable<ImageFrame<TPixel>> frames)
{
Guard.NotNull(parent, nameof(parent));

70
src/ImageSharp/ImageFrame{TPixel}.cs

@ -6,9 +6,9 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp
@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metaData">The meta data.</param>
internal ImageFrame(Configuration configuration, int width, int height, ImageFrameMetaData metaData)
: this(configuration, width, height, default, metaData)
: this(configuration, width, height, default(TPixel), metaData)
{
}
@ -85,12 +85,41 @@ namespace SixLabors.ImageSharp
Guard.NotNull(metaData, nameof(metaData));
this.configuration = configuration;
this.MemoryManager = configuration.MemoryManager;
this.PixelBuffer = this.MemoryManager.Allocate2D<TPixel>(width, height, false);
this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(width, height, false);
this.MetaData = metaData;
this.Clear(configuration.ParallelOptions, backgroundColor);
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class wrapping an existing buffer.
/// </summary>
internal ImageFrame(Configuration configuration, int width, int height, IBuffer<TPixel> consumedBuffer)
: this(configuration, width, height, consumedBuffer, new ImageFrameMetaData())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class wrapping an existing buffer.
/// </summary>
internal ImageFrame(
Configuration configuration,
int width,
int height,
IBuffer<TPixel> consumedBuffer,
ImageFrameMetaData metaData)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
Guard.NotNull(metaData, nameof(metaData));
this.configuration = configuration;
this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = new Buffer2D<TPixel>(consumedBuffer, width, height);
this.MetaData = metaData;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary>
@ -102,16 +131,16 @@ namespace SixLabors.ImageSharp
Guard.NotNull(source, nameof(source));
this.configuration = configuration;
this.MemoryManager = configuration.MemoryManager;
this.PixelBuffer = this.MemoryManager.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.Span.CopyTo(this.PixelBuffer.Span);
this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan());
this.MetaData = source.MetaData.Clone();
}
/// <summary>
/// Gets the <see cref="MemoryManager" /> to use for buffer allocations.
/// Gets the <see cref="MemoryAllocator" /> to use for buffer allocations.
/// </summary>
public MemoryManager MemoryManager { get; }
public MemoryAllocator MemoryAllocator { get; }
/// <summary>
/// Gets the image pixels. Not private as Buffer2D requires an array in its constructor.
@ -213,33 +242,18 @@ namespace SixLabors.ImageSharp
throw new ArgumentException("ImageFrame<TPixel>.CopyTo(): target must be of the same size!", nameof(target));
}
this.GetPixelSpan().CopyTo(target.Span);
}
/// <summary>
/// Switches the buffers used by the image and the PixelAccessor meaning that the Image will "own" the buffer from the PixelAccessor and the PixelAccessor will now own the Images buffer.
/// </summary>
/// <param name="pixelSource">The pixel source.</param>
internal void SwapPixelsBuffers(PixelAccessor<TPixel> pixelSource)
{
Guard.NotNull(pixelSource, nameof(pixelSource));
// Push my memory into the accessor (which in turn unpins the old buffer ready for the images use)
Buffer2D<TPixel> newPixels = pixelSource.SwapBufferOwnership(this.PixelBuffer);
this.PixelBuffer = newPixels;
this.GetPixelSpan().CopyTo(target.GetSpan());
}
/// <summary>
/// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer.
/// </summary>
/// <param name="pixelSource">The pixel source.</param>
internal void SwapPixelsBuffers(ImageFrame<TPixel> pixelSource)
internal void SwapOrCopyPixelsBufferFrom(ImageFrame<TPixel> pixelSource)
{
Guard.NotNull(pixelSource, nameof(pixelSource));
Buffer2D<TPixel> temp = this.PixelBuffer;
this.PixelBuffer = pixelSource.PixelBuffer;
pixelSource.PixelBuffer = temp;
Buffer2D<TPixel>.SwapOrCopyContent(this.PixelBuffer, pixelSource.PixelBuffer);
}
/// <summary>
@ -289,7 +303,7 @@ namespace SixLabors.ImageSharp
{
Span<TPixel> sourceRow = this.GetPixelRowSpan(y);
Span<TPixel2> targetRow = target.GetPixelRowSpan(y);
Span<Vector4> tempRowSpan = tempRowBuffer.Span;
Span<Vector4> tempRowSpan = tempRowBuffer.GetSpan();
PixelOperations<TPixel>.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length);
PixelOperations<TPixel2>.Instance.PackFromScaledVector4(tempRowSpan, targetRow, targetRow.Length);

28
src/ImageSharp/Image{TPixel}.cs

@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
@ -78,7 +79,28 @@ namespace SixLabors.ImageSharp
this.configuration = configuration ?? Configuration.Default;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.MetaData = metadata ?? new ImageMetaData();
this.frames = new ImageFrameCollection<TPixel>(this, width, height, default);
this.frames = new ImageFrameCollection<TPixel>(this, width, height, default(TPixel));
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// consuming an external buffer instance.
/// </summary>
internal Image(Configuration configuration, IBuffer<TPixel> consumedBuffer, int width, int height)
: this(configuration, consumedBuffer, width, height, new ImageMetaData())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// consuming an external buffer instance.
/// </summary>
internal Image(Configuration configuration, IBuffer<TPixel> consumedBuffer, int width, int height, ImageMetaData metadata)
{
this.configuration = configuration;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.MetaData = metadata;
this.frames = new ImageFrameCollection<TPixel>(this, width, height, consumedBuffer);
}
/// <summary>
@ -211,13 +233,13 @@ namespace SixLabors.ImageSharp
/// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer.
/// </summary>
/// <param name="pixelSource">The pixel source.</param>
internal void SwapPixelsBuffers(Image<TPixel> pixelSource)
internal void SwapOrCopyPixelsBuffersFrom(Image<TPixel> pixelSource)
{
Guard.NotNull(pixelSource, nameof(pixelSource));
for (int i = 0; i < this.frames.Count; i++)
{
this.frames[i].SwapPixelsBuffers(pixelSource.frames[i]);
this.frames[i].SwapOrCopyPixelsBufferFrom(pixelSource.frames[i]);
}
}
}

24
src/ImageSharp/Memory/ArrayPoolMemoryManager.Buffer{T}.cs → src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs

@ -5,17 +5,18 @@ using System;
using System.Buffers;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Contains <see cref="Buffer{T}"/> and <see cref="ManagedByteBuffer"/>
/// </summary>
public partial class ArrayPoolMemoryManager
public partial class ArrayPoolMemoryAllocator
{
/// <summary>
/// The buffer implementation of <see cref="ArrayPoolMemoryManager"/>
/// The buffer implementation of <see cref="ArrayPoolMemoryAllocator"/>.
/// In this implementation <see cref="IBuffer{T}.Memory"/> is owned.
/// </summary>
private class Buffer<T> : IBuffer<T>
private class Buffer<T> : ManagedBufferBase<T>
where T : struct
{
/// <summary>
@ -28,7 +29,7 @@ namespace SixLabors.ImageSharp.Memory
/// </summary>
/// <remarks>
/// By using a weak reference here, we are making sure that array pools and their retained arrays are always GC-ed
/// after a call to <see cref="ArrayPoolMemoryManager.ReleaseRetainedResources"/>, regardless of having buffer instances still being in use.
/// after a call to <see cref="ArrayPoolMemoryAllocator.ReleaseRetainedResources"/>, regardless of having buffer instances still being in use.
/// </remarks>
private WeakReference<ArrayPool<byte>> sourcePoolReference;
@ -45,12 +46,9 @@ namespace SixLabors.ImageSharp.Memory
protected byte[] Data { get; private set; }
/// <inheritdoc />
public Span<T> Span => MemoryMarshal.Cast<byte, T>(this.Data.AsSpan()).Slice(0, this.length);
/// <inheritdoc />
public void Dispose()
protected override void Dispose(bool disposing)
{
if (this.Data == null || this.sourcePoolReference == null)
if (!disposing || this.Data == null || this.sourcePoolReference == null)
{
return;
}
@ -63,10 +61,14 @@ namespace SixLabors.ImageSharp.Memory
this.sourcePoolReference = null;
this.Data = null;
}
public override Span<T> GetSpan() => MemoryMarshal.Cast<byte, T>(this.Data.AsSpan()).Slice(0, this.length);
protected override object GetPinnableObject() => this.Data;
}
/// <summary>
/// The <see cref="IManagedByteBuffer"/> implementation of <see cref="ArrayPoolMemoryManager"/>.
/// The <see cref="IManagedByteBuffer"/> implementation of <see cref="ArrayPoolMemoryAllocator"/>.
/// </summary>
private class ManagedByteBuffer : Buffer<byte>, IManagedByteBuffer
{

20
src/ImageSharp/Memory/ArrayPoolMemoryManager.CommonFactoryMethods.cs → src/ImageSharp/Memory/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs

@ -1,11 +1,11 @@
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Contains common factory methods and configuration constants.
/// </summary>
public partial class ArrayPoolMemoryManager
public partial class ArrayPoolMemoryAllocator
{
/// <summary>
/// The default value for: maximum size of pooled arrays in bytes.
@ -32,9 +32,9 @@ namespace SixLabors.ImageSharp.Memory
/// This is the default. Should be good for most use cases.
/// </summary>
/// <returns>The memory manager</returns>
public static ArrayPoolMemoryManager CreateDefault()
public static ArrayPoolMemoryAllocator CreateDefault()
{
return new ArrayPoolMemoryManager(
return new ArrayPoolMemoryAllocator(
DefaultMaxPooledBufferSizeInBytes,
DefaultBufferSelectorThresholdInBytes,
DefaultLargePoolBucketCount,
@ -45,27 +45,27 @@ namespace SixLabors.ImageSharp.Memory
/// For environments with limited memory capabilities. Only small images are pooled, which can result in reduced througput.
/// </summary>
/// <returns>The memory manager</returns>
public static ArrayPoolMemoryManager CreateWithModeratePooling()
public static ArrayPoolMemoryAllocator CreateWithModeratePooling()
{
return new ArrayPoolMemoryManager(1024 * 1024, 32 * 1024, 16, 24);
return new ArrayPoolMemoryAllocator(1024 * 1024, 32 * 1024, 16, 24);
}
/// <summary>
/// Only pool small buffers like image rows.
/// </summary>
/// <returns>The memory manager</returns>
public static ArrayPoolMemoryManager CreateWithMinimalPooling()
public static ArrayPoolMemoryAllocator CreateWithMinimalPooling()
{
return new ArrayPoolMemoryManager(64 * 1024, 32 * 1024, 8, 24);
return new ArrayPoolMemoryAllocator(64 * 1024, 32 * 1024, 8, 24);
}
/// <summary>
/// RAM is not an issue for me, gimme maximum througput!
/// </summary>
/// <returns>The memory manager</returns>
public static ArrayPoolMemoryManager CreateWithAggressivePooling()
public static ArrayPoolMemoryAllocator CreateWithAggressivePooling()
{
return new ArrayPoolMemoryManager(128 * 1024 * 1024, 32 * 1024 * 1024, 16, 32);
return new ArrayPoolMemoryAllocator(128 * 1024 * 1024, 32 * 1024 * 1024, 16, 32);
}
}
}

24
src/ImageSharp/Memory/ArrayPoolMemoryManager.cs → src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs

@ -4,12 +4,12 @@
using System.Buffers;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Implements <see cref="MemoryManager"/> by allocating memory from <see cref="ArrayPool{T}"/>.
/// Implements <see cref="MemoryAllocator"/> by allocating memory from <see cref="ArrayPool{T}"/>.
/// </summary>
public partial class ArrayPoolMemoryManager : MemoryManager
public partial class ArrayPoolMemoryAllocator : MemoryAllocator
{
/// <summary>
/// The <see cref="ArrayPool{T}"/> for small-to-medium buffers which is not kept clean.
@ -26,42 +26,42 @@ namespace SixLabors.ImageSharp.Memory
private readonly int maxArraysPerBucketLargePool;
/// <summary>
/// Initializes a new instance of the <see cref="ArrayPoolMemoryManager"/> class.
/// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
/// </summary>
public ArrayPoolMemoryManager()
public ArrayPoolMemoryAllocator()
: this(DefaultMaxPooledBufferSizeInBytes, DefaultBufferSelectorThresholdInBytes)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ArrayPoolMemoryManager"/> class.
/// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
/// </summary>
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
public ArrayPoolMemoryManager(int maxPoolSizeInBytes)
public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes)
: this(maxPoolSizeInBytes, GetLargeBufferThresholdInBytes(maxPoolSizeInBytes))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ArrayPoolMemoryManager"/> class.
/// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
/// </summary>
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
/// <param name="poolSelectorThresholdInBytes">Arrays over this threshold will be pooled in <see cref="largeArrayPool"/> which has less buckets for memory safety.</param>
public ArrayPoolMemoryManager(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes)
public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes)
: this(maxPoolSizeInBytes, poolSelectorThresholdInBytes, DefaultLargePoolBucketCount, DefaultNormalPoolBucketCount)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ArrayPoolMemoryManager"/> class.
/// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
/// </summary>
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
/// <param name="poolSelectorThresholdInBytes">The threshold to pool arrays in <see cref="largeArrayPool"/> which has less buckets for memory safety.</param>
/// <param name="maxArraysPerBucketLargePool">Max arrays per bucket for the large array pool</param>
/// <param name="maxArraysPerBucketNormalPool">Max arrays per bucket for the normal array pool</param>
public ArrayPoolMemoryManager(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool)
public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool)
{
Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes));
ImageSharp.Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes));
Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes));
this.MaxPoolSizeInBytes = maxPoolSizeInBytes;

24
src/ImageSharp/Memory/BasicArrayBuffer.cs

@ -1,17 +1,20 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Exposes an array through the <see cref="IBuffer{T}"/> interface.
/// Wraps an array as an <see cref="IBuffer{T}"/> instance. In this implementation <see cref="IBuffer{T}.Memory"/> is owned.
/// </summary>
internal class BasicArrayBuffer<T> : IBuffer<T>
internal class BasicArrayBuffer<T> : ManagedBufferBase<T>
where T : struct
{
public BasicArrayBuffer(T[] array, int length)
{
DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length));
ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length));
this.Array = array;
this.Length = length;
}
@ -25,8 +28,6 @@ namespace SixLabors.ImageSharp.Memory
public int Length { get; }
public Span<T> Span => this.Array.AsSpan(0, this.Length);
/// <summary>
/// Returns a reference to specified element of the buffer.
/// </summary>
@ -39,13 +40,20 @@ namespace SixLabors.ImageSharp.Memory
{
DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
Span<T> span = this.Span;
Span<T> span = this.GetSpan();
return ref span[index];
}
}
public void Dispose()
protected override void Dispose(bool disposing)
{
}
public override Span<T> GetSpan() => this.Array.AsSpan(0, this.Length);
protected override object GetPinnableObject()
{
return this.Array;
}
}
}

5
src/ImageSharp/Memory/BasicByteBuffer.cs

@ -1,4 +1,7 @@
namespace SixLabors.ImageSharp.Memory
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.Memory
{
internal class BasicByteBuffer : BasicArrayBuffer<byte>, IManagedByteBuffer
{

29
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -5,13 +5,22 @@ using System;
using System.Runtime.CompilerServices;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Defines extension methods for <see cref="IBuffer2D{T}"/>.
/// </summary>
internal static class Buffer2DExtensions
{
/// <summary>
/// Gets a <see cref="Span{T}"/> to the backing buffer of <paramref name="buffer"/>.
/// </summary>
internal static Span<T> GetSpan<T>(this IBuffer2D<T> buffer)
where T : struct
{
return buffer.Buffer.GetSpan();
}
/// <summary>
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// </summary>
@ -24,7 +33,7 @@ namespace SixLabors.ImageSharp.Memory
public static Span<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int x, int y)
where T : struct
{
return buffer.Span.Slice((y * buffer.Width) + x, buffer.Width - x);
return buffer.GetSpan().Slice((y * buffer.Width) + x, buffer.Width - x);
}
/// <summary>
@ -38,7 +47,21 @@ namespace SixLabors.ImageSharp.Memory
public static Span<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int y)
where T : struct
{
return buffer.Span.Slice(y * buffer.Width, buffer.Width);
return buffer.GetSpan().Slice(y * buffer.Width, buffer.Width);
}
/// <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 IBuffer2D<T> buffer, int y)
where T : struct
{
return buffer.Buffer.Memory.Slice(y * buffer.Width, buffer.Width);
}
/// <summary>

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

@ -5,7 +5,7 @@ using System;
using System.Runtime.CompilerServices;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Represents a buffer of value type objects
@ -34,16 +34,15 @@ namespace SixLabors.ImageSharp.Memory
/// <inheritdoc />
public int Height { get; private set; }
/// <summary>
/// Gets the span to the whole area.
/// </summary>
public Span<T> Span => this.Buffer.Span;
/// <summary>
/// Gets the backing <see cref="IBuffer{T}"/>
/// </summary>
public IBuffer<T> Buffer { get; private set; }
public Memory<T> Memory => this.Buffer.Memory;
public Span<T> Span => this.Buffer.GetSpan();
/// <summary>
/// Gets a reference to the element at the specified position.
/// </summary>
@ -55,9 +54,9 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
DebugGuard.MustBeLessThan(x, this.Width, nameof(x));
ImageSharp.DebugGuard.MustBeLessThan(x, this.Width, nameof(x));
DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
Span<T> span = this.Buffer.Span;
Span<T> span = this.Buffer.GetSpan();
return ref span[(this.Width * y) + x];
}
}
@ -70,13 +69,34 @@ namespace SixLabors.ImageSharp.Memory
this.Buffer?.Dispose();
}
/// <summary>
/// Swaps the contents of 'destination' with 'source' if the buffers are owned (1),
/// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2!
/// </summary>
public static void SwapOrCopyContent(Buffer2D<T> destination, Buffer2D<T> source)
{
if (source.Buffer.IsMemoryOwner && destination.Buffer.IsMemoryOwner)
{
SwapContents(destination, source);
}
else
{
if (destination.Size() != source.Size())
{
throw new InvalidOperationException("SwapOrCopyContents(): buffers should both owned or the same size!");
}
source.Span.CopyTo(destination.Span);
}
}
/// <summary>
/// Swap the contents (<see cref="Buffer"/>, <see cref="Width"/>, <see cref="Height"/>) of the two buffers.
/// Useful to transfer the contents of a temporary <see cref="Buffer2D{T}"/> to a persistent <see cref="ImageFrame{TPixel}.PixelBuffer"/>
/// Useful to transfer the contents of a temporary <see cref="Buffer2D{T}"/> to a persistent <see cref="SixLabors.ImageSharp.ImageFrame{T}.PixelBuffer"/>
/// </summary>
/// <param name="a">The first buffer</param>
/// <param name="b">The second buffer</param>
public static void SwapContents(Buffer2D<T> a, Buffer2D<T> b)
private static void SwapContents(Buffer2D<T> a, Buffer2D<T> b)
{
Size aSize = a.Size();
Size bSize = b.Size();

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

@ -2,7 +2,7 @@ using System;
using System.Runtime.CompilerServices;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Represents a rectangular area inside a 2D memory buffer (<see cref="Buffer2D{T}"/>).
@ -20,10 +20,10 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferArea(IBuffer2D<T> destinationBuffer, Rectangle rectangle)
{
DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle));
DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle));
DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, destinationBuffer.Width, nameof(rectangle));
DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, destinationBuffer.Height, nameof(rectangle));
ImageSharp.DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle));
ImageSharp.DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle));
ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, destinationBuffer.Width, nameof(rectangle));
ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, destinationBuffer.Height, nameof(rectangle));
this.DestinationBuffer = destinationBuffer;
this.Rectangle = rectangle;
@ -71,7 +71,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.Span[this.GetIndexOf(x, y)];
public ref T this[int x, int y] => ref this.DestinationBuffer.GetSpan()[this.GetIndexOf(x, y)];
/// <summary>
/// Gets a reference to the [0,0] element.
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Memory
/// <returns>The reference to the [0,0] element</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T GetReferenceToOrigin() =>
ref this.DestinationBuffer.Span[(this.Rectangle.Y * this.DestinationBuffer.Width) + this.Rectangle.X];
ref this.DestinationBuffer.GetSpan()[(this.Rectangle.Y * this.DestinationBuffer.Width) + this.Rectangle.X];
/// <summary>
/// Gets a span to row 'y' inside this area.
@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Memory
int xx = this.Rectangle.X;
int width = this.Rectangle.Width;
return this.DestinationBuffer.Span.Slice(yy + xx, width);
return this.DestinationBuffer.GetSpan().Slice(yy + xx, width);
}
/// <summary>
@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferArea<T> GetSubArea(Rectangle rectangle)
{
DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle));
ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle));
DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle));
int x = this.Rectangle.X + rectangle.X;
@ -147,7 +147,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.Span.Clear();
this.DestinationBuffer.GetSpan().Clear();
return;
}

14
src/ImageSharp/Memory/BufferExtensions.cs

@ -6,13 +6,13 @@ using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
internal static class BufferExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Length<T>(this IBuffer<T> buffer)
where T : struct => buffer.Span.Length;
where T : struct => buffer.GetSpan().Length;
/// <summary>
/// Gets a <see cref="Span{T}"/> to an offseted position inside the buffer.
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Memory
public static Span<T> Slice<T>(this IBuffer<T> buffer, int start)
where T : struct
{
return buffer.Span.Slice(start);
return buffer.GetSpan().Slice(start);
}
/// <summary>
@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Memory
public static Span<T> Slice<T>(this IBuffer<T> buffer, int start, int length)
where T : struct
{
return buffer.Span.Slice(start, length);
return buffer.GetSpan().Slice(start, length);
}
/// <summary>
@ -49,12 +49,12 @@ namespace SixLabors.ImageSharp.Memory
public static void Clear<T>(this IBuffer<T> buffer)
where T : struct
{
buffer.Span.Clear();
buffer.GetSpan().Clear();
}
public static ref T DangerousGetPinnableReference<T>(this IBuffer<T> buffer)
public static ref T GetReference<T>(this IBuffer<T> buffer)
where T : struct =>
ref MemoryMarshal.GetReference(buffer.Span);
ref MemoryMarshal.GetReference(buffer.GetSpan());
public static void Read(this Stream stream, IManagedByteBuffer buffer)
{

34
src/ImageSharp/Memory/ConsumedBuffer.cs

@ -0,0 +1,34 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.Memory
{
/// <summary>
/// A buffer implementation that consumes an existing <see cref="Memory{T}"/> instance.
/// The ownership of the memory remains external.
/// </summary>
/// <typeparam name="T">The value type</typeparam>
internal sealed class ConsumedBuffer<T> : IBuffer<T>
where T : struct
{
public ConsumedBuffer(Memory<T> memory)
{
this.Memory = memory;
}
public Memory<T> Memory { get; }
public bool IsMemoryOwner => false;
public Span<T> GetSpan()
{
return this.Memory.Span;
}
public void Dispose()
{
}
}
}

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

@ -3,10 +3,10 @@
using System;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// An interface that represents a pinned buffer of value type objects
/// An interface that represents a contigous buffer of value type objects
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Memory
int Height { get; }
/// <summary>
/// Gets a <see cref="Span{T}"/> to the backing buffer.
/// Gets the contigous buffer being wrapped.
/// </summary>
Span<T> Span { get; }
IBuffer<T> Buffer { get; }
}
}

27
src/ImageSharp/Memory/IBuffer{T}.cs

@ -2,20 +2,37 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <inheritdoc />
/// <summary>
/// Represents a contigous memory buffer of value-type items "promising" a <see cref="Span{T}"/>
/// Represents a contigous memory buffer of value-type items.
/// Depending on it's implementation, an <see cref="IBuffer{T}"/> can (1) OWN or (2) CONSUME the <see cref="Memory{T}"/> instance it wraps.
/// For a deeper understanding of the owner/consumer model, read the following docs: <br/>
/// https://gist.github.com/GrabYourPitchforks/4c3e1935fd4d9fa2831dbfcab35dffc6
/// TODO: We need more SOC here! For owned buffers we should use <see cref="IMemoryOwner{T}"/>.
/// For the consumption case we should not use buffers at all. We need to refactor Buffer2D{T} for this.
/// </summary>
/// <typeparam name="T">The value type</typeparam>
internal interface IBuffer<T> : IDisposable
where T : struct
{
/// <summary>
/// Gets the span to the memory "promised" by this buffer
/// Gets the <see cref="Memory{T}"/> ownerd/consumed by this buffer.
/// </summary>
Span<T> Span { get; }
Memory<T> Memory { get; }
/// <summary>
/// Gets a value indicating whether this instance is owning the <see cref="Memory"/>.
/// </summary>
bool IsMemoryOwner { get; }
/// <summary>
/// Gets the span to the memory "promised" by this buffer when it's OWNED (1).
/// Gets `this.Memory.Span` when the buffer CONSUMED (2).
/// </summary>
/// <returns>The <see cref="Span{T}"/></returns>
Span<T> GetSpan();
}
}

2
src/ImageSharp/Memory/IManagedByteBuffer.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Represents a byte buffer backed by a managed array. Useful for interop with classic .NET API-s.

43
src/ImageSharp/Memory/ManagedBufferBase.cs

@ -0,0 +1,43 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Buffers;
using System.Runtime.InteropServices;
namespace SixLabors.Memory
{
/// <summary>
/// Provides a base class for <see cref="IBuffer{T}"/> implementations by implementing pinning logic for <see cref="MemoryManager{T}"/> adaption.
/// </summary>
internal abstract class ManagedBufferBase<T> : System.Buffers.MemoryManager<T>, IBuffer<T>
where T : struct
{
private GCHandle pinHandle;
public bool IsMemoryOwner => true;
/// <summary>
/// Gets the object that should be pinned.
/// </summary>
protected abstract object GetPinnableObject();
public override unsafe MemoryHandle Pin(int elementIndex = 0)
{
if (!this.pinHandle.IsAllocated)
{
this.pinHandle = GCHandle.Alloc(this.GetPinnableObject(), GCHandleType.Pinned);
}
void* ptr = (void*)this.pinHandle.AddrOfPinnedObject();
return new MemoryHandle(ptr, this.pinHandle);
}
public override void Unpin()
{
if (this.pinHandle.IsAllocated)
{
this.pinHandle.Free();
}
}
}
}

14
src/ImageSharp/Memory/MemoryManager.cs → src/ImageSharp/Memory/MemoryAllocator.cs

@ -1,12 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Memory managers are used to allocate memory for image processing operations.
/// </summary>
public abstract class MemoryManager
public abstract class MemoryAllocator
{
/// <summary>
/// Allocates an <see cref="IBuffer{T}"/> of size <paramref name="length"/>, optionally
@ -27,16 +27,6 @@ namespace SixLabors.ImageSharp.Memory
/// <returns>The <see cref="IManagedByteBuffer"/></returns>
internal abstract IManagedByteBuffer AllocateManagedByteBuffer(int length, bool clear);
/// <summary>
/// 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!
/// </summary>
internal BasicArrayBuffer<T> AllocateFake<T>(int length, bool dummy = false)
where T : struct
{
return new BasicArrayBuffer<T>(new T[length]);
}
/// <summary>
/// Releases all retained resources not being in use.
/// Eg: by resetting array pools and letting GC to free the arrays.

46
src/ImageSharp/Memory/MemoryManagerExtensions.cs → src/ImageSharp/Memory/MemoryAllocatorExtensions.cs

@ -1,11 +1,11 @@
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Extension methods for <see cref="MemoryManager"/>.
/// Extension methods for <see cref="MemoryAllocator"/>.
/// </summary>
internal static class MemoryManagerExtensions
internal static class MemoryAllocatorExtensions
{
/// <summary>
/// Allocates a <see cref="IBuffer{T}"/> of size <paramref name="length"/>.
@ -13,67 +13,67 @@ namespace SixLabors.ImageSharp.Memory
/// returning, so it may contain data from an earlier use.
/// </summary>
/// <typeparam name="T">Type of the data stored in the buffer</typeparam>
/// <param name="memoryManager">The <see cref="MemoryManager"/></param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/></param>
/// <param name="length">Size of the buffer to allocate</param>
/// <returns>A buffer of values of type <typeparamref name="T"/>.</returns>
public static IBuffer<T> Allocate<T>(this MemoryManager memoryManager, int length)
public static IBuffer<T> Allocate<T>(this MemoryAllocator memoryAllocator, int length)
where T : struct
{
return memoryManager.Allocate<T>(length, false);
return memoryAllocator.Allocate<T>(length, false);
}
public static IBuffer<T> AllocateClean<T>(this MemoryManager memoryManager, int length)
public static IBuffer<T> AllocateClean<T>(this MemoryAllocator memoryAllocator, int length)
where T : struct
{
return memoryManager.Allocate<T>(length, true);
return memoryAllocator.Allocate<T>(length, true);
}
public static IManagedByteBuffer AllocateManagedByteBuffer(this MemoryManager memoryManager, int length)
public static IManagedByteBuffer AllocateManagedByteBuffer(this MemoryAllocator memoryAllocator, int length)
{
return memoryManager.AllocateManagedByteBuffer(length, false);
return memoryAllocator.AllocateManagedByteBuffer(length, false);
}
public static IManagedByteBuffer AllocateCleanManagedByteBuffer(this MemoryManager memoryManager, int length)
public static IManagedByteBuffer AllocateCleanManagedByteBuffer(this MemoryAllocator memoryAllocator, int length)
{
return memoryManager.AllocateManagedByteBuffer(length, true);
return memoryAllocator.AllocateManagedByteBuffer(length, true);
}
public static Buffer2D<T> Allocate2D<T>(this MemoryManager memoryManager, int width, int height, bool clear)
public static Buffer2D<T> Allocate2D<T>(this MemoryAllocator memoryAllocator, int width, int height, bool clear)
where T : struct
{
IBuffer<T> buffer = memoryManager.Allocate<T>(width * height, clear);
IBuffer<T> buffer = memoryAllocator.Allocate<T>(width * height, clear);
return new Buffer2D<T>(buffer, width, height);
}
public static Buffer2D<T> Allocate2D<T>(this MemoryManager memoryManager, Size size)
public static Buffer2D<T> Allocate2D<T>(this MemoryAllocator memoryAllocator, Size size)
where T : struct =>
Allocate2D<T>(memoryManager, size.Width, size.Height, false);
Allocate2D<T>(memoryAllocator, size.Width, size.Height, false);
public static Buffer2D<T> Allocate2D<T>(this MemoryManager memoryManager, int width, int height)
public static Buffer2D<T> Allocate2D<T>(this MemoryAllocator memoryAllocator, int width, int height)
where T : struct =>
Allocate2D<T>(memoryManager, width, height, false);
Allocate2D<T>(memoryAllocator, width, height, false);
public static Buffer2D<T> AllocateClean2D<T>(this MemoryManager memoryManager, int width, int height)
public static Buffer2D<T> AllocateClean2D<T>(this MemoryAllocator memoryAllocator, int width, int height)
where T : struct =>
Allocate2D<T>(memoryManager, width, height, true);
Allocate2D<T>(memoryAllocator, width, height, true);
/// <summary>
/// Allocates padded buffers for BMP encoder/decoder. (Replacing old PixelRow/PixelArea)
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/></param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/></param>
/// <param name="width">Pixel count in the row</param>
/// <param name="pixelSizeInBytes">The pixel size in bytes, eg. 3 for RGB</param>
/// <param name="paddingInBytes">The padding</param>
/// <returns>A <see cref="IManagedByteBuffer"/></returns>
public static IManagedByteBuffer AllocatePaddedPixelRowBuffer(
this MemoryManager memoryManager,
this MemoryAllocator memoryAllocator,
int width,
int pixelSizeInBytes,
int paddingInBytes)
{
int length = (width * pixelSizeInBytes) + paddingInBytes;
return memoryManager.AllocateManagedByteBuffer(length);
return memoryAllocator.AllocateManagedByteBuffer(length);
}
}
}

6
src/ImageSharp/Memory/SimpleGcMemoryManager.cs → src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs

@ -1,9 +1,9 @@
namespace SixLabors.ImageSharp.Memory
namespace SixLabors.Memory
{
/// <summary>
/// Implements <see cref="MemoryManager"/> by newing up arrays by the GC on every allocation requests.
/// Implements <see cref="MemoryAllocator"/> by newing up arrays by the GC on every allocation requests.
/// </summary>
public class SimpleGcMemoryManager : MemoryManager
public class SimpleGcMemoryAllocator : MemoryAllocator
{
/// <inheritdoc />
internal override IBuffer<T> Allocate<T>(int length, bool clear)

13
src/ImageSharp/PixelAccessor{TPixel}.cs

@ -5,8 +5,8 @@ using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
@ -51,10 +51,7 @@ namespace SixLabors.ImageSharp
/// <inheritdoc />
public int Height { get; private set; }
/// <inheritdoc />
public Span<TPixel> Span => this.PixelBuffer.Span;
private static PixelOperations<TPixel> Operations => PixelOperations<TPixel>.Instance;
public IBuffer<TPixel> Buffer => this.PixelBuffer.Buffer;
/// <summary>
/// Gets or sets the pixel at the specified position.
@ -68,14 +65,14 @@ namespace SixLabors.ImageSharp
get
{
this.CheckCoordinates(x, y);
return this.Span[(y * this.Width) + x];
return this.GetSpan()[(y * this.Width) + x];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.CheckCoordinates(x, y);
Span<TPixel> span = this.Span;
Span<TPixel> span = this.GetSpan();
span[(y * this.Width) + x] = value;
}
}
@ -112,7 +109,7 @@ namespace SixLabors.ImageSharp
/// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TPixel> target)
{
this.PixelBuffer.Span.CopyTo(target.PixelBuffer.Span);
this.PixelBuffer.GetSpan().CopyTo(target.PixelBuffer.GetSpan());
}
/// <summary>

44
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
/// <summary>
@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -194,7 +194,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -272,7 +272,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -311,7 +311,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -350,7 +350,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -389,7 +389,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -428,7 +428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -467,7 +467,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -506,7 +506,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -545,7 +545,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -584,7 +584,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -623,7 +623,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -662,7 +662,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -701,7 +701,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -740,7 +740,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -779,7 +779,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -818,7 +818,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));

2
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt

@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));

6
src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.PixelFormats
{
@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Blend 2 pixels together.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/></param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/></param>
/// <param name="destination">The destination span.</param>
/// <param name="background">The background span.</param>
/// <param name="source">The source span.</param>
@ -36,6 +36,6 @@ namespace SixLabors.ImageSharp.PixelFormats
/// A value between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param>
public abstract void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount);
public abstract void Blend(MemoryAllocator memoryAllocator, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount);
}
}

2
src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs

@ -5,7 +5,7 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.PixelFormats
{

6
src/ImageSharp/Processing/Convolution/Processors/Convolution2DProcessor.cs

@ -5,10 +5,10 @@ using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
int maxY = endY - 1;
int maxX = endX - 1;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Width, source.Height))
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Width, source.Height))
{
source.CopyTo(targetPixels);
@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}

4
src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs

@ -4,10 +4,10 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
ParallelOptions parallelOptions = configuration.ParallelOptions;
using (Buffer2D<TPixel> firstPassPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size()))
using (Buffer2D<TPixel> firstPassPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{
this.ApplyConvolution(firstPassPixels, source.PixelBuffer, source.Bounds(), this.KernelX, parallelOptions);
this.ApplyConvolution(source.PixelBuffer, firstPassPixels, sourceRectangle, this.KernelY, parallelOptions);

6
src/ImageSharp/Processing/Convolution/Processors/ConvolutionProcessor.cs

@ -5,10 +5,10 @@ using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
int maxY = endY - 1;
int maxX = endX - 1;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size()))
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{
source.CopyTo(targetPixels);
@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}

1
src/ImageSharp/Processing/Convolution/Processors/SobelProcessor.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors

4
src/ImageSharp/Processing/DefaultInternalImageProcessorContext.cs

@ -2,9 +2,9 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing
}
/// <inheritdoc/>
public MemoryManager MemoryManager => this.source.GetConfiguration().MemoryManager;
public MemoryAllocator MemoryAllocator => this.source.GetConfiguration().MemoryAllocator;
/// <inheritdoc/>
public Image<TPixel> Apply()

6
src/ImageSharp/Processing/Effects/Processors/OilPaintingProcessor.cs

@ -5,9 +5,9 @@ using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Effects.Processors
@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Effects.Processors
int radius = this.BrushSize >> 1;
int levels = this.Levels;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size()))
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{
source.CopyTo(targetPixels);
@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.Processing.Effects.Processors
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}

6
src/ImageSharp/Processing/IImageProcessingContext{TPixel}.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
@ -16,10 +16,10 @@ namespace SixLabors.ImageSharp.Processing
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets a reference to the <see cref="MemoryManager" /> used to allocate buffers
/// Gets a reference to the <see cref="MemoryAllocator" /> used to allocate buffers
/// for this context.
/// </summary>
MemoryManager MemoryManager { get; }
MemoryAllocator MemoryAllocator { get; }
/// <summary>
/// Gets the image dimensions at the current point in the processing pipeline.

12
src/ImageSharp/Processing/Overlays/Processors/BackgroundColorProcessor.cs

@ -4,9 +4,9 @@
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Overlays.Processors
@ -66,12 +66,12 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
int width = maxX - minX;
using (IBuffer<TPixel> colors = source.MemoryManager.Allocate<TPixel>(width))
using (IBuffer<float> amount = source.MemoryManager.Allocate<float>(width))
using (IBuffer<TPixel> colors = source.MemoryAllocator.Allocate<TPixel>(width))
using (IBuffer<float> amount = source.MemoryAllocator.Allocate<float>(width))
{
// Be careful! Do not capture colorSpan & amountSpan in the lambda below!
Span<TPixel> colorSpan = colors.Span;
Span<float> amountSpan = amount.Span;
Span<TPixel> colorSpan = colors.GetSpan();
Span<float> amountSpan = amount.GetSpan();
// TODO: Use Span.Fill?
for (int i = 0; i < width; i++)
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
Span<TPixel> destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width);
// This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one
blender.Blend(source.MemoryManager, destination, colors.Span, destination, amount.Span);
blender.Blend(source.MemoryAllocator, destination, colors.GetSpan(), destination, amount.GetSpan());
});
}
}

12
src/ImageSharp/Processing/Overlays/Processors/GlowProcessor.cs

@ -5,10 +5,10 @@ using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Overlays.Processors
@ -112,10 +112,10 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
}
int width = maxX - minX;
using (IBuffer<TPixel> rowColors = source.MemoryManager.Allocate<TPixel>(width))
using (IBuffer<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width))
{
// Be careful! Do not capture rowColorsSpan in the lambda below!
Span<TPixel> rowColorsSpan = rowColors.Span;
Span<TPixel> rowColorsSpan = rowColors.GetSpan();
for (int i = 0; i < width; i++)
{
@ -128,9 +128,9 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
configuration.ParallelOptions,
y =>
{
using (IBuffer<float> amounts = source.MemoryManager.Allocate<float>(width))
using (IBuffer<float> amounts = source.MemoryAllocator.Allocate<float>(width))
{
Span<float> amountsSpan = amounts.Span;
Span<float> amountsSpan = amounts.GetSpan();
int offsetY = y - startY;
int offsetX = minX - startX;
for (int i = 0; i < width; i++)
@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(source.MemoryManager, destination, destination, rowColors.Span, amountsSpan);
this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan);
}
});
}

12
src/ImageSharp/Processing/Overlays/Processors/VignetteProcessor.cs

@ -5,10 +5,10 @@ using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Overlays.Processors
@ -114,10 +114,10 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
}
int width = maxX - minX;
using (IBuffer<TPixel> rowColors = source.MemoryManager.Allocate<TPixel>(width))
using (IBuffer<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width))
{
// Be careful! Do not capture rowColorsSpan in the lambda below!
Span<TPixel> rowColorsSpan = rowColors.Span;
Span<TPixel> rowColorsSpan = rowColors.GetSpan();
for (int i = 0; i < width; i++)
{
@ -130,9 +130,9 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
configuration.ParallelOptions,
y =>
{
using (IBuffer<float> amounts = source.MemoryManager.Allocate<float>(width))
using (IBuffer<float> amounts = source.MemoryAllocator.Allocate<float>(width))
{
Span<float> amountsSpan = amounts.Span;
Span<float> amountsSpan = amounts.GetSpan();
int offsetY = y - startY;
int offsetX = minX - startX;
for (int i = 0; i < width; i++)
@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(source.MemoryManager, destination, destination, rowColors.Span, amountsSpan);
this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan);
}
});
}

2
src/ImageSharp/Processing/Processors/CloningImageProcessor.cs

@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
}
source.SwapPixelsBuffers(cloned);
source.SwapOrCopyPixelsBuffersFrom(cloned);
}
}

156
src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs

@ -7,8 +7,8 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{
@ -141,17 +141,17 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
public override QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image)
{
Guard.NotNull(image, nameof(image));
MemoryManager memoryManager = image.MemoryManager;
MemoryAllocator memoryAllocator = image.MemoryAllocator;
try
{
this.vwt = memoryManager.AllocateClean<long>(TableLength);
this.vmr = memoryManager.AllocateClean<long>(TableLength);
this.vmg = memoryManager.AllocateClean<long>(TableLength);
this.vmb = memoryManager.AllocateClean<long>(TableLength);
this.vma = memoryManager.AllocateClean<long>(TableLength);
this.m2 = memoryManager.AllocateClean<float>(TableLength);
this.tag = memoryManager.AllocateClean<byte>(TableLength);
this.vwt = memoryAllocator.AllocateClean<long>(TableLength);
this.vmr = memoryAllocator.AllocateClean<long>(TableLength);
this.vmg = memoryAllocator.AllocateClean<long>(TableLength);
this.vmb = memoryAllocator.AllocateClean<long>(TableLength);
this.vma = memoryAllocator.AllocateClean<long>(TableLength);
this.m2 = memoryAllocator.AllocateClean<float>(TableLength);
this.tag = memoryAllocator.AllocateClean<byte>(TableLength);
return base.QuantizeFrame(image);
}
@ -177,14 +177,14 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{
this.Mark(ref this.colorCube[k], (byte)k);
float weight = Volume(ref this.colorCube[k], this.vwt.Span);
float weight = Volume(ref this.colorCube[k], this.vwt.GetSpan());
if (MathF.Abs(weight) > Constants.Epsilon)
{
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);
float r = Volume(ref this.colorCube[k], this.vmr.GetSpan());
float g = Volume(ref this.colorCube[k], this.vmg.GetSpan());
float b = Volume(ref this.colorCube[k], this.vmb.GetSpan());
float a = Volume(ref this.colorCube[k], this.vma.GetSpan());
ref TPixel color = ref this.palette[k];
color.PackFromVector4(new Vector4(r, g, b, a) / weight / 255F);
@ -209,12 +209,12 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
Span<long> vwtSpan = this.vwt.Span;
Span<long> vmrSpan = this.vmr.Span;
Span<long> vmgSpan = this.vmg.Span;
Span<long> vmbSpan = this.vmb.Span;
Span<long> vmaSpan = this.vma.Span;
Span<float> m2Span = this.m2.Span;
Span<long> vwtSpan = this.vwt.GetSpan();
Span<long> vmrSpan = this.vmr.GetSpan();
Span<long> vmgSpan = this.vmg.GetSpan();
Span<long> vmbSpan = this.vmb.GetSpan();
Span<long> vmaSpan = this.vma.GetSpan();
Span<float> m2Span = this.m2.GetSpan();
vwtSpan[index]++;
vmrSpan[index] += rgba.R;
@ -246,7 +246,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
}
}
this.Get3DMoments(source.MemoryManager);
this.Get3DMoments(source.MemoryAllocator);
this.BuildCube();
}
@ -464,42 +464,42 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <summary>
/// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box.
/// </summary>
private void Get3DMoments(MemoryManager memoryManager)
private void Get3DMoments(MemoryAllocator memoryAllocator)
{
Span<long> vwtSpan = this.vwt.Span;
Span<long> vmrSpan = this.vmr.Span;
Span<long> vmgSpan = this.vmg.Span;
Span<long> vmbSpan = this.vmb.Span;
Span<long> vmaSpan = this.vma.Span;
Span<float> m2Span = this.m2.Span;
using (IBuffer<long> volume = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeR = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeG = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeB = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeA = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<float> volume2 = memoryManager.Allocate<float>(IndexCount * IndexAlphaCount))
using (IBuffer<long> area = memoryManager.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaR = memoryManager.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaG = memoryManager.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaB = memoryManager.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaA = memoryManager.Allocate<long>(IndexAlphaCount))
using (IBuffer<float> area2 = memoryManager.Allocate<float>(IndexAlphaCount))
Span<long> vwtSpan = this.vwt.GetSpan();
Span<long> vmrSpan = this.vmr.GetSpan();
Span<long> vmgSpan = this.vmg.GetSpan();
Span<long> vmbSpan = this.vmb.GetSpan();
Span<long> vmaSpan = this.vma.GetSpan();
Span<float> m2Span = this.m2.GetSpan();
using (IBuffer<long> volume = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeR = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeG = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeB = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeA = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<float> volume2 = memoryAllocator.Allocate<float>(IndexCount * IndexAlphaCount))
using (IBuffer<long> area = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaR = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaG = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaB = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaA = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<float> area2 = memoryAllocator.Allocate<float>(IndexAlphaCount))
{
Span<long> volumeSpan = volume.Span;
Span<long> volumeRSpan = volumeR.Span;
Span<long> volumeGSpan = volumeG.Span;
Span<long> volumeBSpan = volumeB.Span;
Span<long> volumeASpan = volumeA.Span;
Span<float> volume2Span = volume2.Span;
Span<long> areaSpan = area.Span;
Span<long> areaRSpan = areaR.Span;
Span<long> areaGSpan = areaG.Span;
Span<long> areaBSpan = areaB.Span;
Span<long> areaASpan = areaA.Span;
Span<float> area2Span = area2.Span;
Span<long> volumeSpan = volume.GetSpan();
Span<long> volumeRSpan = volumeR.GetSpan();
Span<long> volumeGSpan = volumeG.GetSpan();
Span<long> volumeBSpan = volumeB.GetSpan();
Span<long> volumeASpan = volumeA.GetSpan();
Span<float> volume2Span = volume2.GetSpan();
Span<long> areaSpan = area.GetSpan();
Span<long> areaRSpan = areaR.GetSpan();
Span<long> areaGSpan = areaG.GetSpan();
Span<long> areaBSpan = areaB.GetSpan();
Span<long> areaASpan = areaA.GetSpan();
Span<float> area2Span = area2.GetSpan();
for (int r = 1; r < IndexCount; r++)
{
@ -577,12 +577,12 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <returns>The <see cref="float"/>.</returns>
private float Variance(ref Box cube)
{
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 dr = Volume(ref cube, this.vmr.GetSpan());
float dg = Volume(ref cube, this.vmg.GetSpan());
float db = Volume(ref cube, this.vmb.GetSpan());
float da = Volume(ref cube, this.vma.GetSpan());
Span<float> m2Span = this.m2.Span;
Span<float> m2Span = this.m2.GetSpan();
float xx =
m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
@ -603,7 +603,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
+ m2Span[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.Span));
return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.GetSpan()));
}
/// <summary>
@ -626,22 +626,22 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <returns>The <see cref="float"/>.</returns>
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.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);
long baseR = Bottom(ref cube, direction, this.vmr.GetSpan());
long baseG = Bottom(ref cube, direction, this.vmg.GetSpan());
long baseB = Bottom(ref cube, direction, this.vmb.GetSpan());
long baseA = Bottom(ref cube, direction, this.vma.GetSpan());
long baseW = Bottom(ref cube, direction, this.vwt.GetSpan());
float max = 0F;
cut = -1;
for (int i = first; i < last; i++)
{
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);
float halfR = baseR + Top(ref cube, direction, i, this.vmr.GetSpan());
float halfG = baseG + Top(ref cube, direction, i, this.vmg.GetSpan());
float halfB = baseB + Top(ref cube, direction, i, this.vmb.GetSpan());
float halfA = baseA + Top(ref cube, direction, i, this.vma.GetSpan());
float halfW = baseW + Top(ref cube, direction, i, this.vwt.GetSpan());
if (MathF.Abs(halfW) < Constants.Epsilon)
{
@ -685,11 +685,11 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <returns>Returns a value indicating whether the box has been split.</returns>
private bool Cut(ref Box set1, ref Box set2)
{
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 wholeR = Volume(ref set1, this.vmr.GetSpan());
float wholeG = Volume(ref set1, this.vmg.GetSpan());
float wholeB = Volume(ref set1, this.vmb.GetSpan());
float wholeA = Volume(ref set1, this.vma.GetSpan());
float wholeW = Volume(ref set1, this.vwt.GetSpan());
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);
@ -773,7 +773,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <param name="label">A label.</param>
private void Mark(ref Box cube, byte label)
{
Span<byte> tagSpan = this.tag.Span;
Span<byte> tagSpan = this.tag.GetSpan();
for (int r = cube.R0 + 1; r <= cube.R1; r++)
{
@ -866,7 +866,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
int b = rgba.B >> (8 - IndexBits);
int a = rgba.A >> (8 - IndexAlphaBits);
Span<byte> tagSpan = this.tag.Span;
Span<byte> tagSpan = this.tag.GetSpan();
return tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)];
}

8
src/ImageSharp/Processing/Transforms/Processors/AffineTransformProcessor.cs

@ -9,9 +9,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Transforms.Resamplers;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors
@ -111,10 +111,10 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
int xLength = (int)MathF.Ceiling((radius.X * 2) + 2);
int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2);
MemoryManager memoryManager = configuration.MemoryManager;
MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
using (Buffer2D<float> yBuffer = memoryManager.Allocate2D<float>(yLength, height))
using (Buffer2D<float> xBuffer = memoryManager.Allocate2D<float>(xLength, height))
using (Buffer2D<float> yBuffer = memoryAllocator.Allocate2D<float>(yLength, height))
using (Buffer2D<float> xBuffer = memoryAllocator.Allocate2D<float>(xLength, height))
{
Parallel.For(
0,

1
src/ImageSharp/Processing/Transforms/Processors/CropProcessor.cs

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;

10
src/ImageSharp/Processing/Transforms/Processors/FlipProcessor.cs

@ -4,9 +4,9 @@
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
int height = source.Height;
int halfHeight = (int)Math.Ceiling(source.Height * .5F);
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size()))
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{
Parallel.For(
0,
@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
altSourceRow.CopyTo(targetRow);
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
int height = source.Height;
int halfWidth = (int)Math.Ceiling(width * .5F);
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size()))
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{
Parallel.For(
0,
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}

8
src/ImageSharp/Processing/Transforms/Processors/ProjectiveTransformProcessor.cs

@ -9,9 +9,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Transforms.Resamplers;
using SixLabors.Memory;
using SixLabors.Primitives;
// TODO: Doesn't work yet! Implement tests + Finish implementation + Document Matrix4x4 behavior
@ -117,10 +117,10 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
int xLength = (int)MathF.Ceiling((radius.X * 2) + 2);
int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2);
MemoryManager memoryManager = configuration.MemoryManager;
MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
using (Buffer2D<float> yBuffer = memoryManager.Allocate2D<float>(yLength, height))
using (Buffer2D<float> xBuffer = memoryManager.Allocate2D<float>(xLength, height))
using (Buffer2D<float> yBuffer = memoryAllocator.Allocate2D<float>(yLength, height))
using (Buffer2D<float> xBuffer = memoryAllocator.Allocate2D<float>(xLength, height))
{
Parallel.For(
0,

18
src/ImageSharp/Processing/Transforms/Processors/ResizeProcessor.cs

@ -9,9 +9,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Transforms.Resamplers;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors
@ -143,12 +143,12 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// <summary>
/// Computes the weights to apply at each pixel when resizing.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations</param>
/// <param name="destinationSize">The destination size</param>
/// <param name="sourceSize">The source size</param>
/// <returns>The <see cref="WeightsBuffer"/></returns>
// TODO: Made internal to simplify experimenting with weights data. Make it private when finished figuring out how to optimize all the stuff!
internal WeightsBuffer PrecomputeWeights(MemoryManager memoryManager, int destinationSize, int sourceSize)
internal WeightsBuffer PrecomputeWeights(MemoryAllocator memoryAllocator, int destinationSize, int sourceSize)
{
float ratio = (float)sourceSize / destinationSize;
float scale = ratio;
@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
IResampler sampler = this.Sampler;
float radius = MathF.Ceiling(scale * sampler.Radius);
var result = new WeightsBuffer(memoryManager, sourceSize, destinationSize);
var result = new WeightsBuffer(memoryAllocator, sourceSize, destinationSize);
for (int i = 0; i < destinationSize; i++)
{
@ -226,14 +226,14 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
if (!(this.Sampler is NearestNeighborResampler))
{
// Since all image frame dimensions have to be the same we can calculate this for all frames.
MemoryManager memoryManager = source.GetMemoryManager();
MemoryAllocator memoryAllocator = source.GetMemoryAllocator();
this.horizontalWeights = this.PrecomputeWeights(
memoryManager,
memoryAllocator,
this.ResizeRectangle.Width,
sourceRectangle.Width);
this.verticalWeights = this.PrecomputeWeights(
memoryManager,
memoryAllocator,
this.ResizeRectangle.Height,
sourceRectangle.Height);
}
@ -295,7 +295,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
// First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle.
// TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed!
using (Buffer2D<Vector4> firstPassPixels = source.MemoryManager.Allocate2D<Vector4>(width, source.Height))
using (Buffer2D<Vector4> firstPassPixels = source.MemoryAllocator.Allocate2D<Vector4>(width, source.Height))
{
firstPassPixels.Buffer.Clear();
@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{
ref Vector4 firstPassRow = ref MemoryMarshal.GetReference(firstPassPixels.GetRowSpan(y));
Span<TPixel> sourceRow = source.GetPixelRowSpan(y);
Span<Vector4> tempRowSpan = tempRowBuffer.Span;
Span<Vector4> tempRowSpan = tempRowBuffer.GetSpan();
PixelOperations<TPixel>.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length);

8
src/ImageSharp/Processing/Transforms/Processors/WeightsBuffer.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{
@ -16,12 +16,12 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// <summary>
/// Initializes a new instance of the <see cref="WeightsBuffer"/> class.
/// </summary>
/// <param name="memoryManager">The MemoryManager to use for allocations.</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for allocations.</param>
/// <param name="sourceSize">The size of the source window</param>
/// <param name="destinationSize">The size of the destination window</param>
public WeightsBuffer(MemoryManager memoryManager, int sourceSize, int destinationSize)
public WeightsBuffer(MemoryAllocator memoryAllocator, int sourceSize, int destinationSize)
{
this.dataBuffer = memoryManager.Allocate2D<float>(sourceSize, destinationSize, true);
this.dataBuffer = memoryAllocator.Allocate2D<float>(sourceSize, destinationSize, true);
this.Weights = new WeightsWindow[destinationSize];
}

4
src/ImageSharp/Processing/Transforms/Processors/WeightsWindow.cs

@ -5,7 +5,7 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref float GetStartReference()
{
Span<float> span = this.buffer.Span;
Span<float> span = this.buffer.GetSpan();
return ref span[this.flatStartIndex];
}

2
tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
public class CopyPixels : BenchmarkBase
{

4
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs

@ -29,8 +29,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
this.stream2 = new MemoryStream(this.buffer);
this.stream3 = new MemoryStream(this.buffer);
this.stream4 = new MemoryStream(this.buffer);
this.reader1 = new DoubleBufferedStreamReader(Configuration.Default.MemoryManager, this.stream2);
this.reader2 = new DoubleBufferedStreamReader(Configuration.Default.MemoryManager, this.stream2);
this.reader1 = new DoubleBufferedStreamReader(Configuration.Default.MemoryAllocator, this.stream2);
this.reader2 = new DoubleBufferedStreamReader(Configuration.Default.MemoryAllocator, this.stream2);
}
[GlobalCleanup]

4
tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs

@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
[Config(typeof(Config.ShortClr))]
public class YCbCrColorConversion
@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
}
// no need to dispose when buffer is not array owner
buffers[i] = Configuration.Default.MemoryManager.Allocate2D<float>(values.Length, 1);
buffers[i] = Configuration.Default.MemoryAllocator.Allocate2D<float>(values.Length, 1);
}
return buffers;

14
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats;
[Config(typeof(Config.ShortClr))]
@ -23,8 +23,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup]
public void Setup()
{
this.destination = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count);
this.source = Configuration.Default.MemoryManager.Allocate<Vector4>(this.Count);
this.destination = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.source = Configuration.Default.MemoryAllocator.Allocate<Vector4>(this.Count);
}
[GlobalCleanup]
@ -37,8 +37,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
ref Vector4 s = ref MemoryMarshal.GetReference(this.source.Span);
ref TPixel d = ref MemoryMarshal.GetReference(this.destination.Span);
ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan());
ref TPixel d = ref MemoryMarshal.GetReference(this.destination.GetSpan());
for (int i = 0; i < this.Count; i++)
{
@ -49,13 +49,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().PackFromVector4(this.source.Span, this.destination.Span, this.Count);
new PixelOperations<TPixel>().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.PackFromVector4(this.source.Span, this.destination.Span, this.Count);
PixelOperations<TPixel>.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
}

14
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs

@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats;
public abstract class PackFromXyzw<TPixel>
@ -21,8 +21,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup]
public void Setup()
{
this.destination = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count);
this.source = Configuration.Default.MemoryManager.Allocate<byte>(this.Count * 4);
this.destination = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.source = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 4);
}
[GlobalCleanup]
@ -35,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
Span<byte> s = this.source.Span;
Span<TPixel> d = this.destination.Span;
Span<byte> s = this.source.GetSpan();
Span<TPixel> d = this.destination.GetSpan();
for (int i = 0; i < this.Count; i++)
{
@ -50,13 +50,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().PackFromRgba32Bytes(this.source.Span, this.destination.Span, this.Count);
new PixelOperations<TPixel>().PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(this.source.Span, this.destination.Span, this.Count);
PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
}

14
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats;
public abstract class ToVector4<TPixel>
@ -22,8 +22,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup]
public void Setup()
{
this.source = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryManager.Allocate<Vector4>(this.Count);
this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryAllocator.Allocate<Vector4>(this.Count);
}
[GlobalCleanup]
@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
Span<TPixel> s = this.source.Span;
Span<Vector4> d = this.destination.Span;
Span<TPixel> s = this.source.GetSpan();
Span<Vector4> d = this.destination.GetSpan();
for (int i = 0; i < this.Count; i++)
{
@ -49,13 +49,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().ToVector4(this.source.Span, this.destination.Span, this.Count);
new PixelOperations<TPixel>().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.ToVector4(this.source.Span, this.destination.Span, this.Count);
PixelOperations<TPixel>.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
}

14
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats;
public abstract class ToXyz<TPixel>
@ -22,8 +22,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup]
public void Setup()
{
this.source = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryManager.Allocate<byte>(this.Count * 3);
this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 3);
}
[GlobalCleanup]
@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
Span<TPixel> s = this.source.Span;
Span<byte> d = this.destination.Span;
Span<TPixel> s = this.source.GetSpan();
Span<byte> d = this.destination.GetSpan();
var rgb = default(Rgb24);
@ -55,13 +55,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().ToRgb24Bytes(this.source.Span, this.destination.Span, this.Count);
new PixelOperations<TPixel>().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.ToRgb24Bytes(this.source.Span, this.destination.Span, this.Count);
PixelOperations<TPixel>.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
}

14
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats;
public abstract class ToXyzw<TPixel>
@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup]
public void Setup()
{
this.source = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryManager.Allocate<byte>(this.Count * 4);
this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 4);
}
[GlobalCleanup]
@ -38,8 +38,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)]
public void PerElement()
{
Span<TPixel> s = this.source.Span;
Span<byte> d = this.destination.Span;
Span<TPixel> s = this.source.GetSpan();
Span<byte> d = this.destination.GetSpan();
var rgba = default(Rgba32);
@ -58,13 +58,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().ToRgba32Bytes(this.source.Span, this.destination.Span, this.Count);
new PixelOperations<TPixel>().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.ToRgba32Bytes(this.source.Span, this.destination.Span, this.Count);
PixelOperations<TPixel>.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
}

2
tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs

@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
/// <summary>
/// This benchmark compares different methods for fetching memory data into <see cref="Vector{T}"/>

16
tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks
using CoreSize = SixLabors.Primitives.Size;
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats.PixelBlenders;
public class PorterDuffBulkVsPixel : BenchmarkBase
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Benchmarks
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (IBuffer<Vector4> buffer = Configuration.Default.MemoryManager.Allocate<Vector4>(destination.Length * 3))
using (IBuffer<Vector4> buffer = Configuration.Default.MemoryAllocator.Allocate<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
@ -59,16 +59,16 @@ namespace SixLabors.ImageSharp.Benchmarks
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
{
using (IBuffer<float> amounts = Configuration.Default.MemoryManager.Allocate<float>(image.Width))
using (IBuffer<float> amounts = Configuration.Default.MemoryAllocator.Allocate<float>(image.Width))
{
amounts.Span.Fill(1);
amounts.GetSpan().Fill(1);
using (PixelAccessor<Rgba32> pixels = image.Lock())
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> span = pixels.GetRowSpan(y);
this.BulkVectorConvert(span, span, span, amounts.Span);
this.BulkVectorConvert(span, span, span, amounts.GetSpan());
}
}
return new CoreSize(image.Width, image.Height);
@ -81,15 +81,15 @@ namespace SixLabors.ImageSharp.Benchmarks
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
{
using (IBuffer<float> amounts = Configuration.Default.MemoryManager.Allocate<float>(image.Width))
using (IBuffer<float> amounts = Configuration.Default.MemoryAllocator.Allocate<float>(image.Width))
{
amounts.Span.Fill(1);
amounts.GetSpan().Fill(1);
using (PixelAccessor<Rgba32> pixels = image.Lock())
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> span = pixels.GetRowSpan(y);
this.BulkPixelConvert(span, span, span, amounts.Span);
this.BulkPixelConvert(span, span, span, amounts.GetSpan());
}
}

6
tests/ImageSharp.Benchmarks/Samplers/Glow.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
using SixLabors.ImageSharp.Processing.Overlays.Processors;
using SixLabors.ImageSharp.Processing.Processors;
@ -102,10 +102,10 @@ namespace SixLabors.ImageSharp.Benchmarks
}
int width = maxX - minX;
using (IBuffer<TPixel> rowColors = Configuration.Default.MemoryManager.Allocate<TPixel>(width))
using (IBuffer<TPixel> rowColors = Configuration.Default.MemoryAllocator.Allocate<TPixel>(width))
using (PixelAccessor<TPixel> sourcePixels = source.Lock())
{
rowColors.Span.Fill(glowColor);
rowColors.GetSpan().Fill(glowColor);
Parallel.For(
minY,

119
tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs

@ -1,15 +1,134 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Advanced
{
using System.Buffers;
using SixLabors.Memory;
public class AdvancedImageExtensionsTests
{
public class GetPixelMemory
{
[Theory]
[WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32)]
[WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)]
public void WhenMemoryIsOwned<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image0 = provider.GetImage())
{
var targetBuffer = new TPixel[image0.Width * image0.Height];
// Act:
Memory<TPixel> memory = image0.GetPixelMemory();
// Assert:
Assert.Equal(image0.Width * image0.Height, memory.Length);
memory.Span.CopyTo(targetBuffer);
using (Image<TPixel> image1 = provider.GetImage())
{
// We are using a copy of the original image for assertion
image1.ComparePixelBufferTo(targetBuffer);
}
}
}
[Theory]
[WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32 | PixelTypes.Bgr24)]
[WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)]
public void WhenMemoryIsConsumed<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image0 = provider.GetImage())
{
var targetBuffer = new TPixel[image0.Width * image0.Height];
image0.GetPixelSpan().CopyTo(targetBuffer);
var managerOfExeternalMemory = new TestMemoryManager<TPixel>(targetBuffer);
Memory<TPixel> externalMemory = managerOfExeternalMemory.Memory;
using (Image<TPixel> image1 = Image.WrapMemory(externalMemory, image0.Width, image0.Height))
{
Memory<TPixel> internalMemory = image1.GetPixelMemory();
Assert.Equal(targetBuffer.Length, internalMemory.Length);
Assert.True(Unsafe.AreSame(ref targetBuffer[0], ref internalMemory.Span[0]));
image0.ComparePixelBufferTo(internalMemory.Span);
}
// Make sure externalMemory works after destruction:
image0.ComparePixelBufferTo(externalMemory.Span);
}
}
}
[Theory]
[WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32)]
[WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)]
public void GetPixelRowMemory<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
var targetBuffer = new TPixel[image.Width * image.Height];
// Act:
for (int y = 0; y < image.Height; y++)
{
Memory<TPixel> rowMemory = image.GetPixelRowMemory(y);
rowMemory.Span.CopyTo(targetBuffer.AsSpan(image.Width * y));
}
// Assert:
using (Image<TPixel> image1 = provider.GetImage())
{
// We are using a copy of the original image for assertion
image1.ComparePixelBufferTo(targetBuffer);
}
}
}
[Theory]
[WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32)]
[WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)]
public void GetPixelRowSpan<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
var targetBuffer = new TPixel[image.Width * image.Height];
// Act:
for (int y = 0; y < image.Height; y++)
{
Span<TPixel> rowMemory = image.GetPixelRowSpan(y);
rowMemory.CopyTo(targetBuffer.AsSpan(image.Width * y));
}
// Assert:
using (Image<TPixel> image1 = provider.GetImage())
{
// We are using a copy of the original image for assertion
image1.ComparePixelBufferTo(targetBuffer);
}
}
}
#pragma warning disable 0618
[Theory]
[WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)]
public unsafe void DangerousGetPinnableReference_CopyToBuffer<TPixel>(TestImageProvider<TPixel> provider)

46
tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs

@ -4,7 +4,8 @@
using System.Numerics;
using Moq;
using System;
using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing;
@ -13,13 +14,15 @@ using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.ImageSharp.Processing.Drawing.Processors;
using SixLabors.Primitives;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Drawing
{
public class FillRegionProcessorTests
{
[Theory]
[InlineData(true, 1, 4)]
[InlineData(true, 2, 4)]
@ -29,21 +32,20 @@ namespace SixLabors.ImageSharp.Tests.Drawing
[InlineData(false, 16, 4)] // we always do 4 sub=pixels when antialising is off.
public void MinimumAntialiasSubpixelDepth(bool antialias, int antialiasSubpixelDepth, int expectedAntialiasSubpixelDepth)
{
var bounds = new SixLabors.Primitives.Rectangle(0, 0, 1, 1);
var bounds = new Rectangle(0, 0, 1, 1);
var brush = new Mock<IBrush<Rgba32>>();
var region = new Mock<Region>();
region.Setup(x => x.Bounds).Returns(bounds);
var region = new MockRegion2(bounds);
var options = new GraphicsOptions(antialias)
{
AntialiasSubpixelDepth = 1
};
var processor = new FillRegionProcessor<Rgba32>(brush.Object, region.Object, options);
var processor = new FillRegionProcessor<Rgba32>(brush.Object, region, options);
var img = new Image<Rgba32>(1, 1);
processor.Apply(img, bounds);
region.Verify(x => x.Scan(It.IsAny<float>(), It.IsAny<float[]>(), It.IsAny<int>()), Times.Exactly(4));
Assert.Equal(4, region.ScanInvocationCounter);
}
[Fact]
@ -52,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing
var bounds = new Rectangle(-100, -10, 10, 10);
var brush = new Mock<IBrush<Rgba32>>();
var options = new GraphicsOptions(true);
var processor = new FillRegionProcessor<Rgba32>(brush.Object, new MockRegion(), options);
var processor = new FillRegionProcessor<Rgba32>(brush.Object, new MockRegion1(), options);
var img = new Image<Rgba32>(10, 10);
processor.Apply(img, bounds);
}
@ -71,13 +73,11 @@ namespace SixLabors.ImageSharp.Tests.Drawing
}
// Mocking the region throws an error in netcore2.0
private class MockRegion : Region
private class MockRegion1 : Region
{
public override Rectangle Bounds => new Rectangle(-100, -10, 10, 10);
public override int MaxIntersections => 10;
public override int Scan(float y, float[] buffer, int offset)
public override int Scan(float y, Span<float> buffer, Configuration configuration)
{
if (y < 5)
{
@ -87,6 +87,28 @@ namespace SixLabors.ImageSharp.Tests.Drawing
}
return 0;
}
public override int MaxIntersections => 10;
}
private class MockRegion2 : Region
{
public MockRegion2(Rectangle bounds)
{
this.Bounds = bounds;
}
public override int MaxIntersections => 100;
public override Rectangle Bounds { get; }
public int ScanInvocationCounter { get; private set; }
public override int Scan(float y, Span<float> buffer, Configuration configuration)
{
this.ScanInvocationCounter++;
return 0;
}
}
}
}

18
tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs

@ -12,7 +12,10 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Drawing
{
using System;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.Primitives;
[GroupOutput("Drawing")]
public class FillSolidBrushTests
@ -67,6 +70,19 @@ namespace SixLabors.ImageSharp.Tests.Drawing
}
}
[Theory]
[WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 5, 7, 3, 8)]
[WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 8, 5, 6, 4)]
public void FillRegion<TPixel>(TestImageProvider<TPixel> provider, int x0, int y0, int w, int h)
where TPixel : struct, IPixel<TPixel>
{
FormattableString testDetails = $"(x{x0},y{y0},w{w},h{h})";
var region = new RectangleF(x0, y0, w, h);
TPixel color = TestUtils.GetPixelOfNamedColor<TPixel>("Blue");
provider.RunValidatingProcessorTest(c => c.Fill(color, region), testDetails, ImageComparer.Exact);
}
public static readonly TheoryData<bool, string, float, PixelBlenderMode, float> BlendData =
new TheoryData<bool, string, float, PixelBlenderMode, float>()
{

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save