Browse Source

Replace BufferSpan<T> with Span<T>

- Add System.Memory
- Update System.Runtime.CompilerServices.Unsafe
- Move memory classes/structs to ImageSharp.Memory
- Replace BufferSpan<T> with Span<T> and adjust methods accordingly
af/merge-core
James Jackson-South 9 years ago
parent
commit
9984ffa348
  1. 9
      src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs
  2. 6
      src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs
  3. 6
      src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
  4. 7
      src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs
  5. 7
      src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs
  6. 6
      src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
  7. 4
      src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
  8. 2
      src/ImageSharp.Drawing/Processors/FillProcessor.cs
  9. 2
      src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
  10. 4
      src/ImageSharp/Common/Helpers/DebugGuard.cs
  11. 205
      src/ImageSharp/Common/Memory/BufferSpan{T}.cs
  12. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Atkinson.cs
  13. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Burks.cs
  14. 1
      src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs
  15. 2
      src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinberg.cs
  16. 2
      src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinke.cs
  17. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Sierra2.cs
  18. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Sierra3.cs
  19. 2
      src/ImageSharp/Dithering/ErrorDiffusion/SierraLite.cs
  20. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Stucki.cs
  21. 2
      src/ImageSharp/Dithering/Ordered/Bayer.cs
  22. 2
      src/ImageSharp/Dithering/Ordered/Ordered.cs
  23. 1
      src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs
  24. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs
  25. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs
  26. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs
  27. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs
  28. 1
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  29. 5
      src/ImageSharp/Formats/Png/Filters/AverageFilter.cs
  30. 6
      src/ImageSharp/Formats/Png/Filters/NoneFilter.cs
  31. 5
      src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
  32. 5
      src/ImageSharp/Formats/Png/Filters/SubFilter.cs
  33. 5
      src/ImageSharp/Formats/Png/Filters/UpFilter.cs
  34. 9
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  35. 14
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  36. 2
      src/ImageSharp/Image/ImageBase{TPixel}.cs
  37. 54
      src/ImageSharp/Image/PixelAccessor{TPixel}.cs
  38. 8
      src/ImageSharp/Image/PixelArea{TPixel}.cs
  39. 3
      src/ImageSharp/ImageSharp.csproj
  40. 31
      src/ImageSharp/Memory/Buffer.cs
  41. 3
      src/ImageSharp/Memory/Buffer2D.cs
  42. 14
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  43. 6
      src/ImageSharp/Memory/Fast2DArray{T}.cs
  44. 8
      src/ImageSharp/Memory/IBuffer2D.cs
  45. 3
      src/ImageSharp/Memory/PixelDataPool{T}.cs
  46. 24
      src/ImageSharp/Memory/SpanHelper.cs
  47. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs
  48. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs
  49. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs
  50. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs
  51. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs
  52. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs
  53. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs
  54. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs
  55. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs
  56. 4
      src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs
  57. 75
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  58. 35
      src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs
  59. 7
      src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs
  60. 1
      src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
  61. 1
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
  62. 1
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
  63. 1
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
  64. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs
  65. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
  66. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs
  67. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
  68. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs
  69. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
  70. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
  71. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
  72. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
  73. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
  74. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs
  75. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
  76. 1
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs
  77. 1
      src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs
  78. 1
      src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs
  79. 3
      src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs
  80. 3
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
  81. 3
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
  82. 16
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
  83. 3
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  84. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs
  85. 1
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
  86. 1
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  87. 5
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  88. 8
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
  89. 2
      tests/ImageSharp.Benchmarks/General/Array2D.cs
  90. 3
      tests/ImageSharp.Benchmarks/General/ClearBuffer.cs
  91. 2
      tests/ImageSharp.Benchmarks/General/IterateArray.cs
  92. 2
      tests/ImageSharp.Benchmarks/General/PixelIndexing.cs
  93. 6
      tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs
  94. 17
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  95. 2
      tests/ImageSharp.Benchmarks/Samplers/Glow.cs
  96. 54
      tests/ImageSharp.Benchmarks/Samplers/Resize.cs
  97. 17
      tests/ImageSharp.Tests/Colors/PixelOperationsTests.cs
  98. 12
      tests/ImageSharp.Tests/Common/Buffer2DTests.cs
  99. 115
      tests/ImageSharp.Tests/Common/BufferSpanTests.cs
  100. 30
      tests/ImageSharp.Tests/Common/BufferTests.cs

9
src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs

@ -5,7 +5,10 @@
namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processors;
@ -114,7 +117,7 @@ namespace ImageSharp.Drawing.Brushes
}
/// <inheritdoc />
internal override void Apply(BufferSpan<float> scanline, int x, int y)
internal override void Apply(Span<float> scanline, int x, int y)
{
// create a span for colors
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
@ -122,7 +125,7 @@ namespace ImageSharp.Drawing.Brushes
{
int sourceY = (y - this.offsetY) % this.yLength;
int offsetX = x - this.offsetX;
BufferSpan<TPixel> sourceRow = this.source.GetRowSpan(sourceY);
Span<TPixel> sourceRow = this.source.GetRowSpan(sourceY);
for (int i = 0; i < scanline.Length; i++)
{
@ -133,7 +136,7 @@ namespace ImageSharp.Drawing.Brushes
overlay[i] = pixel;
}
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}

6
src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processors;
@ -147,7 +149,7 @@ namespace ImageSharp.Drawing.Brushes
}
/// <inheritdoc />
internal override void Apply(BufferSpan<float> scanline, int x, int y)
internal override void Apply(Span<float> scanline, int x, int y)
{
int patternY = y % this.pattern.Height;
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
@ -161,7 +163,7 @@ namespace ImageSharp.Drawing.Brushes
overlay[i] = this.pattern[patternY, patternX];
}
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}

6
src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs

@ -7,6 +7,8 @@ namespace ImageSharp.Drawing.Processors
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -64,7 +66,7 @@ namespace ImageSharp.Drawing.Processors
/// <param name="x">The x position in the target pixel space that the start of the scanline data corresponds to.</param>
/// <param name="y">The y position in the target pixel space that whole scanline corresponds to.</param>
/// <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(BufferSpan<float> scanline, int x, int y)
internal virtual void Apply(Span<float> scanline, int x, int y)
{
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
using (Buffer<TPixel> overlay = new Buffer<TPixel>(scanline.Length))
@ -79,7 +81,7 @@ namespace ImageSharp.Drawing.Processors
overlay[i] = this[x + i, y];
}
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}

7
src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs

@ -5,7 +5,10 @@
namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processors;
@ -139,7 +142,7 @@ namespace ImageSharp.Drawing.Brushes
}
/// <inheritdoc />
internal override void Apply(BufferSpan<float> scanline, int x, int y)
internal override void Apply(Span<float> scanline, int x, int y)
{
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
using (Buffer<TPixel> overlay = new Buffer<TPixel>(scanline.Length))
@ -155,7 +158,7 @@ namespace ImageSharp.Drawing.Brushes
overlay[i] = this[offsetX, y];
}
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}

7
src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs

@ -5,7 +5,10 @@
namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processors;
@ -87,9 +90,9 @@ namespace ImageSharp.Drawing.Brushes
}
/// <inheritdoc />
internal override void Apply(BufferSpan<float> scanline, int x, int y)
internal override void Apply(Span<float> scanline, int x, int y)
{
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
{

6
src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs

@ -8,6 +8,8 @@ namespace ImageSharp.Drawing.Processors
using System;
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
@ -97,8 +99,8 @@ namespace ImageSharp.Drawing.Processors
this.ParallelOptions,
y =>
{
BufferSpan<TPixel> background = sourcePixels.GetRowSpan(y).Slice(minX, width);
BufferSpan<TPixel> foreground = toBlendPixels.GetRowSpan(y - this.Location.Y).Slice(0, width);
Span<TPixel> background = sourcePixels.GetRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = toBlendPixels.GetRowSpan(y - this.Location.Y).Slice(0, width);
this.blender.Blend(background, background, foreground, amount);
});
}

4
src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs

@ -8,6 +8,8 @@ namespace ImageSharp.Drawing.Processors
using System;
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
using Pens;
@ -110,7 +112,7 @@ namespace ImageSharp.Drawing.Processors
colors[i] = color.Color;
}
BufferSpan<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(minX - startX, width);
Span<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(minX - startX, width);
blender.Blend(destination, destination, colors, amount);
}
});

2
src/ImageSharp.Drawing/Processors/FillProcessor.cs

@ -10,6 +10,8 @@ namespace ImageSharp.Drawing.Processors
using System.Threading.Tasks;
using Drawing;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;

2
src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs

@ -8,6 +8,8 @@ namespace ImageSharp.Drawing.Processors
using System;
using System.Buffers;
using Drawing;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;

4
src/ImageSharp/Common/Helpers/DebugGuard.cs

@ -170,7 +170,7 @@ namespace ImageSharp
/// <exception cref="ArgumentException">
/// <paramref name="target"/> is true
/// </exception>
public static void MustBeSameSized<T>(BufferSpan<T> target, BufferSpan<T> other, string parameterName)
public static void MustBeSameSized<T>(Span<T> target, Span<T> other, string parameterName)
where T : struct
{
if (target.Length != other.Length)
@ -189,7 +189,7 @@ namespace ImageSharp
/// <exception cref="ArgumentException">
/// <paramref name="target"/> is true
/// </exception>
public static void MustBeSizedAtLeast<T>(BufferSpan<T> target, BufferSpan<T> minSpan, string parameterName)
public static void MustBeSizedAtLeast<T>(Span<T> target, Span<T> minSpan, string parameterName)
where T : struct
{
if (target.Length < minSpan.Length)

205
src/ImageSharp/Common/Memory/BufferSpan{T}.cs

@ -1,205 +0,0 @@
// <copyright file="BufferSpan{T}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Represents a contiguous region of a pinned managed array.
/// The array is usually owned by a <see cref="Buffer{T}"/> instance.
/// </summary>
/// <remarks>
/// <see cref="BufferSpan{T}"/> is very similar to corefx System.Span&lt;T&gt;, and we try to maintain a compatible API.
/// There are several differences though:
/// - It's not possible to use it with stack objects or pointers to unmanaged memory, only with managed arrays.
/// - It's possible to retrieve a reference to the array (<see cref="Array"/>) so we can pass it to API-s like <see cref="Marshal.Copy(byte[], int, IntPtr, int)"/>
/// - It's possible to retrieve the pinned pointer. This enables optimized (unchecked) unsafe operations.
/// - There is no bounds checking for performance reasons, only in debug mode. This makes <see cref="BufferSpan{T}"/> an unsafe type!
/// </remarks>
/// <typeparam name="T">The type of elements of the array</typeparam>
internal unsafe struct BufferSpan<T>
where T : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
/// </summary>
/// <param name="array">The pinned array</param>
/// <param name="start">The index at which to begin the span.</param>
/// <param name="length">The length</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array, int start, int length)
{
GuardArray(array);
DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
DebugGuard.MustBeLessThanOrEqualTo(length, array.Length - start, nameof(length));
this.Array = array;
this.Length = length;
this.Start = start;
}
/// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
/// </summary>
/// <param name="array">The pinned array</param>
/// <param name="start">The index at which to begin the span.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array, int start)
{
GuardArray(array);
DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
this.Array = array;
this.Length = array.Length - start;
this.Start = start;
}
/// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array.
/// </summary>
/// <param name="array">The pinned array</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array)
{
GuardArray(array);
this.Array = array;
this.Start = 0;
this.Length = array.Length;
}
/// <summary>
/// Gets the backing array.
/// </summary>
public T[] Array { get; private set; }
/// <summary>
/// Gets the length of the <see cref="BufferSpan{T}"/>
/// </summary>
public int Length { get; private set; }
/// <summary>
/// Gets the start inside <see cref="Array"/>
/// </summary>
public int Start { get; private set; }
/// <summary>
/// Gets the start inside <see cref="Array"/> in bytes.
/// </summary>
public int ByteOffset => this.Start * Unsafe.SizeOf<T>();
/// <summary>
/// Returns a reference to specified element of the span.
/// </summary>
/// <param name="index">The index</param>
/// <returns>The reference to the specified element</returns>
public ref T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
ref T startRef = ref this.DangerousGetPinnableReference();
return ref Unsafe.Add(ref startRef, index);
}
}
/// <summary>
/// Converts generic <see cref="BufferSpan{T}"/> to a <see cref="BufferSpan{T}"/> of bytes
/// setting it's <see cref="Start"/> and <see cref="Length"/> to correct values.
/// </summary>
/// <returns>The span of bytes</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<byte> AsBytes()
{
BufferSpan<byte> result = default(BufferSpan<byte>);
result.Array = Unsafe.As<byte[]>(this.Array);
result.Start = this.Start * Unsafe.SizeOf<T>();
result.Length = this.Length * Unsafe.SizeOf<T>();
return result;
}
/// <summary>
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
/// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
/// </summary>
/// <returns>The reference to the 0th element</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T DangerousGetPinnableReference()
{
ref T origin = ref this.Array[0];
return ref Unsafe.Add(ref origin, this.Start);
}
/// <summary>
/// Forms a slice out of the given BufferSpan, beginning at 'start'.
/// </summary>
/// <param name="start">TThe index at which to begin this slice.</param>
/// <returns>The offseted (sliced) BufferSpan</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<T> Slice(int start)
{
DebugGuard.MustBeLessThan(start, this.Length, nameof(start));
BufferSpan<T> result = default(BufferSpan<T>);
result.Array = this.Array;
result.Start = this.Start + start;
result.Length = this.Length - start;
return result;
}
/// <summary>
/// Forms a slice out of the given BufferSpan, beginning at 'start'.
/// </summary>
/// <param name="start">The index at which to begin this slice.</param>
/// <param name="length">The desired length for the slice (exclusive).</param>
/// <returns>The sliced BufferSpan</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<T> Slice(int start, int length)
{
DebugGuard.MustBeLessThanOrEqualTo(start, this.Length, nameof(start));
DebugGuard.MustBeLessThanOrEqualTo(length, this.Length - start, nameof(length));
BufferSpan<T> result = default(BufferSpan<T>);
result.Array = this.Array;
result.Start = this.Start + start;
result.Length = length;
return result;
}
/// <summary>
/// Clears `count` elements from the beginning of the span.
/// </summary>
/// <param name="count">The number of elements to clear</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear(int count)
{
DebugGuard.MustBeLessThanOrEqualTo(count, this.Length, nameof(count));
// TODO: Use Unsafe.InitBlock(ref T) for small arrays, when it get's official
System.Array.Clear(this.Array, this.Start, count);
}
/// <summary>
/// Clears the the span
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
this.Clear(this.Length);
}
[Conditional("DEBUG")]
private static void GuardArray(T[] array)
{
DebugGuard.NotNull(array, nameof(array));
}
}
}

2
src/ImageSharp/Dithering/ErrorDiffusion/Atkinson.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Atkinson image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/Burks.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Burks image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

1
src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Dithering
using System.Numerics;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

2
src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinberg.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Floyd–Steinberg image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinke.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the JarvisJudiceNinke image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/Sierra2.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Sierra2 image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/Sierra3.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Sierra3 image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/SierraLite.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the SierraLite image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/Stucki.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Stucki image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/Ordered/Bayer.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering.Ordered
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the 4x4 Bayer dithering matrix.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/Ordered/Ordered.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering.Ordered
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the 4x4 ordered dithering matrix.
/// <see href="https://en.wikipedia.org/wiki/Ordered_dithering"/>

1
src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Dithering.Ordered
{
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

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

@ -8,6 +8,8 @@ namespace ImageSharp.Formats.Jpg
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ImageSharp.Memory;
/// <summary>
/// Encapsulates the implementation of processing "raw" <see cref="Buffer{T}"/>-s into Jpeg image channels.
/// </summary>

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

@ -6,6 +6,8 @@ namespace ImageSharp.Formats.Jpg
{
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
/// <summary>
/// Represents an area of a Jpeg subimage (channel)
/// </summary>

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

@ -9,6 +9,8 @@ namespace ImageSharp.Formats.Jpg
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ImageSharp.Memory;
/// <summary>
/// Encapsulates the impementation of Jpeg SOS Huffman decoding. See JpegScanDecoder.md!
///

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

@ -7,6 +7,8 @@ namespace ImageSharp.Formats.Jpg
using System;
using System.Buffers;
using ImageSharp.Memory;
/// <summary>
/// Represents an image made up of three color components (luminance, blue chroma, red chroma)
/// </summary>

1
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -11,6 +11,7 @@ namespace ImageSharp.Formats
using System.Threading.Tasks;
using ImageSharp.Formats.Jpg;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

5
src/ImageSharp/Formats/Png/Filters/AverageFilter.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Formats
{
using System;
using System.Runtime.CompilerServices;
/// <summary>
@ -21,7 +22,7 @@ namespace ImageSharp.Formats
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, int bytesPerPixel)
public static void Decode(Span<byte> scanline, Span<byte> previousScanline, int bytesPerPixel)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
@ -55,7 +56,7 @@ namespace ImageSharp.Formats
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> result, int bytesPerPixel)
public static void Encode(Span<byte> scanline, Span<byte> previousScanline, Span<byte> result, int bytesPerPixel)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));

6
src/ImageSharp/Formats/Png/Filters/NoneFilter.cs

@ -8,6 +8,8 @@ namespace ImageSharp.Formats
using System;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
/// <summary>
/// The None filter, the scanline is transmitted unmodified; it is only necessary to
/// insert a filter type byte before the data.
@ -21,12 +23,12 @@ namespace ImageSharp.Formats
/// <param name="scanline">The scanline to encode</param>
/// <param name="result">The filtered scanline result.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> result)
public static void Encode(Span<byte> scanline, Span<byte> result)
{
// Insert a byte before the data.
result[0] = 0;
result = result.Slice(1);
BufferSpan.Copy(scanline, result);
SpanHelper.Copy(scanline, result);
}
}
}

5
src/ImageSharp/Formats/Png/Filters/PaethFilter.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Formats
{
using System;
using System.Runtime.CompilerServices;
/// <summary>
@ -22,7 +23,7 @@ namespace ImageSharp.Formats
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, int bytesPerPixel)
public static void Decode(Span<byte> scanline, Span<byte> previousScanline, int bytesPerPixel)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
@ -57,7 +58,7 @@ namespace ImageSharp.Formats
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> result, int bytesPerPixel)
public static void Encode(Span<byte> scanline, Span<byte> previousScanline, Span<byte> result, int bytesPerPixel)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));

5
src/ImageSharp/Formats/Png/Filters/SubFilter.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Formats
{
using System;
using System.Runtime.CompilerServices;
/// <summary>
@ -20,7 +21,7 @@ namespace ImageSharp.Formats
/// <param name="scanline">The scanline to decode</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(BufferSpan<byte> scanline, int bytesPerPixel)
public static void Decode(Span<byte> scanline, int bytesPerPixel)
{
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
@ -48,7 +49,7 @@ namespace ImageSharp.Formats
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> result, int bytesPerPixel)
public static void Encode(Span<byte> scanline, Span<byte> result, int bytesPerPixel)
{
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));

5
src/ImageSharp/Formats/Png/Filters/UpFilter.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Formats
{
using System;
using System.Runtime.CompilerServices;
/// <summary>
@ -20,7 +21,7 @@ namespace ImageSharp.Formats
/// <param name="scanline">The scanline to decode</param>
/// <param name="previousScanline">The previous scanline.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline)
public static void Decode(Span<byte> scanline, Span<byte> previousScanline)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
@ -43,7 +44,7 @@ namespace ImageSharp.Formats
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="result">The filtered scanline result.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> result)
public static void Encode(Span<byte> scanline, Span<byte> previousScanline, Span<byte> result)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));

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

@ -12,6 +12,7 @@ namespace ImageSharp.Formats
using System.Linq;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using static ComparableExtensions;
@ -503,8 +504,8 @@ namespace ImageSharp.Formats
this.currentRowBytesRead = 0;
BufferSpan<byte> scanSpan = this.scanline.Slice(0, bytesPerInterlaceScanline);
BufferSpan<byte> prevSpan = this.previousScanline.Span.Slice(0, bytesPerInterlaceScanline);
Span<byte> scanSpan = this.scanline.Slice(0, bytesPerInterlaceScanline);
Span<byte> prevSpan = this.previousScanline.Span.Slice(0, bytesPerInterlaceScanline);
var filterType = (FilterType)scanSpan[0];
switch (filterType)
@ -565,8 +566,8 @@ namespace ImageSharp.Formats
where TPixel : struct, IPixel<TPixel>
{
var color = default(TPixel);
BufferSpan<TPixel> pixelBuffer = pixels.GetRowSpan(this.currentRow);
var scanlineBuffer = new BufferSpan<byte>(defilteredScanline, 1);
Span<TPixel> pixelBuffer = pixels.GetRowSpan(this.currentRow);
var scanlineBuffer = new Span<byte>(defilteredScanline, 1);
switch (this.PngColorType)
{

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

@ -10,6 +10,8 @@ namespace ImageSharp.Formats
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Quantizers;
@ -340,15 +342,15 @@ namespace ImageSharp.Formats
private void CollecTPixelBytes<TPixel>(PixelAccessor<TPixel> pixels, int row)
where TPixel : struct, IPixel<TPixel>
{
BufferSpan<TPixel> rowSpan = pixels.GetRowSpan(row);
Span<TPixel> rowSpan = pixels.GetRowSpan(row);
if (this.bytesPerPixel == 4)
{
PixelOperations<TPixel>.Instance.ToXyzwBytes(rowSpan, this.rawScanline, this.width);
PixelOperations<TPixel>.Instance.ToXyzwBytes(rowSpan, this.rawScanline, 0, this.width);
}
else
{
PixelOperations<TPixel>.Instance.ToXyzBytes(rowSpan, this.rawScanline, this.width);
PixelOperations<TPixel>.Instance.ToXyzBytes(rowSpan, this.rawScanline, 0, this.width);
}
}
@ -387,8 +389,8 @@ namespace ImageSharp.Formats
/// <returns>The <see cref="T:byte[]"/></returns>
private Buffer<byte> GetOptimalFilteredScanline()
{
BufferSpan<byte> scanSpan = this.rawScanline.Span;
BufferSpan<byte> prevSpan = this.previousScanline.Span;
Span<byte> scanSpan = this.rawScanline.Span;
Span<byte> prevSpan = this.previousScanline.Span;
// Palette images don't compress well with adaptive filtering.
if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8)
@ -442,7 +444,7 @@ namespace ImageSharp.Formats
/// <param name="lastSum">The last variation sum</param>
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int CalculateTotalVariation(BufferSpan<byte> scanline, int lastSum)
private int CalculateTotalVariation(Span<byte> scanline, int lastSum)
{
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
int sum = 0;

2
src/ImageSharp/Image/ImageBase{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp
{
using System;
using System.Diagnostics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processing;

54
src/ImageSharp/Image/PixelAccessor{TPixel}.cs

@ -9,6 +9,8 @@ namespace ImageSharp
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -114,7 +116,7 @@ namespace ImageSharp
public ParallelOptions ParallelOptions { get; }
/// <inheritdoc />
BufferSpan<TPixel> IBuffer2D<TPixel>.Span => this.pixelBuffer;
Span<TPixel> IBuffer2D<TPixel>.Span => this.pixelBuffer;
private static PixelOperations<TPixel> Operations => PixelOperations<TPixel>.Instance;
@ -250,7 +252,7 @@ namespace ImageSharp
/// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TPixel> target)
{
BufferSpan.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span);
SpanHelper.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span);
}
/// <summary>
@ -266,8 +268,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<byte> source = area.GetRowSpan(y);
BufferSpan<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Span<byte> source = area.GetRowSpan(y);
Span<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromZyxBytes(source, destination, width);
}
@ -286,8 +288,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<byte> source = area.GetRowSpan(y);
BufferSpan<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Span<byte> source = area.GetRowSpan(y);
Span<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromZyxwBytes(source, destination, width);
}
@ -306,8 +308,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<byte> source = area.GetRowSpan(y);
BufferSpan<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Span<byte> source = area.GetRowSpan(y);
Span<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromXyzBytes(source, destination, width);
}
@ -326,8 +328,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<byte> source = area.GetRowSpan(y);
BufferSpan<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Span<byte> source = area.GetRowSpan(y);
Span<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromXyzwBytes(source, destination, width);
}
}
@ -345,9 +347,11 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
BufferSpan<byte> destination = area.GetRowSpan(y);
Operations.ToZyxBytes(source, destination, width);
Span<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
using (Buffer<byte> destination = new Buffer<byte>(area.Bytes))
{
Operations.ToZyxBytes(source, destination, y * area.RowStride, width);
}
}
}
@ -364,9 +368,11 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
BufferSpan<byte> destination = area.GetRowSpan(y);
Operations.ToZyxwBytes(source, destination, width);
Span<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
using (Buffer<byte> destination = new Buffer<byte>(area.Bytes))
{
Operations.ToZyxwBytes(source, destination, y * area.RowStride, width);
}
}
}
@ -383,9 +389,11 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
BufferSpan<byte> destination = area.GetRowSpan(y);
Operations.ToXyzBytes(source, destination, width);
Span<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
using (Buffer<byte> destination = new Buffer<byte>(area.Bytes))
{
Operations.ToXyzBytes(source, destination, y * area.RowStride, width);
}
}
}
@ -402,9 +410,11 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
BufferSpan<byte> destination = area.GetRowSpan(y);
Operations.ToXyzwBytes(source, destination, width);
Span<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
using (Buffer<byte> destination = new Buffer<byte>(area.Bytes))
{
Operations.ToXyzwBytes(source, destination, y * area.RowStride, width);
}
}
}

8
src/ImageSharp/Image/PixelArea{TPixel}.cs

@ -8,6 +8,8 @@ namespace ImageSharp
using System;
using System.Diagnostics;
using System.IO;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -191,11 +193,11 @@ namespace ImageSharp
}
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the row y.
/// Gets a <see cref="Span{T}"/> to the row y.
/// </summary>
/// <param name="y">The y coordinate</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
internal BufferSpan<byte> GetRowSpan(int y)
/// <returns>The <see cref="Span{T}"/></returns>
internal Span<byte> GetRowSpan(int y)
{
return this.byteBuffer.Slice(y * this.RowStride);
}

3
src/ImageSharp/ImageSharp.csproj

@ -38,8 +38,9 @@
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Buffers" Version="4.3.0" />
<PackageReference Include="System.Memory" Version="4.4.0-preview1-25305-02" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0-preview1-25305-02" />
<PackageReference Include="System.Numerics.Vectors" Version="4.3.0" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
</ItemGroup>

31
src/ImageSharp/Common/Memory/Buffer.cs → src/ImageSharp/Memory/Buffer.cs

@ -3,10 +3,9 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -97,9 +96,9 @@ namespace ImageSharp
public T[] Array { get; private set; }
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the backing buffer.
/// Gets a <see cref="Span{T}"/> to the backing buffer.
/// </summary>
public BufferSpan<T> Span => this;
public Span<T> Span => this;
/// <summary>
/// Returns a reference to specified element of the buffer.
@ -117,13 +116,13 @@ namespace ImageSharp
}
/// <summary>
/// Converts <see cref="Buffer{T}"/> to an <see cref="BufferSpan{T}"/>.
/// Converts <see cref="Buffer{T}"/> to an <see cref="Span{T}"/>.
/// </summary>
/// <param name="buffer">The <see cref="Buffer{T}"/> to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator BufferSpan<T>(Buffer<T> buffer)
public static implicit operator Span<T>(Buffer<T> buffer)
{
return new BufferSpan<T>(buffer.Array, 0, buffer.Length);
return new Span<T>(buffer.Array, 0, buffer.Length);
}
/// <summary>
@ -140,26 +139,26 @@ namespace ImageSharp
}
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to an offseted position inside the buffer.
/// Gets a <see cref="Span{T}"/> to an offseted position inside the buffer.
/// </summary>
/// <param name="start">The start</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<T> Slice(int start)
public Span<T> Slice(int start)
{
return new BufferSpan<T>(this.Array, start, this.Length - start);
return new Span<T>(this.Array, start, this.Length - start);
}
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to an offseted position inside the buffer.
/// Gets a <see cref="Span{T}"/> to an offsetted position inside the buffer.
/// </summary>
/// <param name="start">The start</param>
/// <param name="length">The length of the slice</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<T> Slice(int start, int length)
public Span<T> Slice(int start, int length)
{
return new BufferSpan<T>(this.Array, start, length);
return new Span<T>(this.Array, start, length);
}
/// <summary>
@ -210,7 +209,7 @@ namespace ImageSharp
}
/// <summary>
/// Clears the buffer, filling elements between 0 and <see cref="Length"/>-1 with default(T)
/// Clears the contents of this buffer.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()

3
src/ImageSharp/Common/Memory/Buffer2D.cs → src/ImageSharp/Memory/Buffer2D.cs

@ -3,9 +3,8 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Runtime.CompilerServices;
/// <summary>

14
src/ImageSharp/Common/Memory/Buffer2DExtensions.cs → src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Runtime.CompilerServices;
@ -14,29 +14,29 @@ namespace ImageSharp
internal static class Buffer2DExtensions
{
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// </summary>
/// <param name="buffer">The buffer</param>
/// <param name="x">The x coordinate (position in the row)</param>
/// <param name="y">The y (row) coordinate</param>
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BufferSpan<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int x, int y)
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);
}
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// </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="BufferSpan{T}"/></returns>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BufferSpan<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int y)
public static Span<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int y)
where T : struct
{
return buffer.Span.Slice(y * buffer.Width, buffer.Width);

6
src/ImageSharp/Common/Memory/Fast2DArray{T}.cs → src/ImageSharp/Memory/Fast2DArray{T}.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Diagnostics;
@ -94,11 +94,11 @@ namespace ImageSharp
}
/// <summary>
/// Performs an implicit conversion from a 2D array to a <see cref="ImageSharp.Fast2DArray{T}" />.
/// Performs an implicit conversion from a 2D array to a <see cref="Fast2DArray{T}" />.
/// </summary>
/// <param name="data">The source array.</param>
/// <returns>
/// The <see cref="ImageSharp.Fast2DArray{T}"/> represenation on the source data.
/// The <see cref="Fast2DArray{T}"/> represenation on the source data.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Fast2DArray<T>(T[,] data)

8
src/ImageSharp/Common/Memory/IBuffer2D.cs → src/ImageSharp/Memory/IBuffer2D.cs

@ -3,8 +3,10 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
/// <summary>
/// An interface that represents a pinned buffer of value type objects
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
@ -24,8 +26,8 @@ namespace ImageSharp
int Height { get; }
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the backing buffer.
/// Gets a <see cref="Span{T}"/> to the backing buffer.
/// </summary>
BufferSpan<T> Span { get; }
Span<T> Span { get; }
}
}

3
src/ImageSharp/Common/Memory/PixelDataPool{T}.cs → src/ImageSharp/Memory/PixelDataPool{T}.cs

@ -3,9 +3,8 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Buffers;
using ImageSharp.PixelFormats;

24
src/ImageSharp/Common/Memory/BufferSpan.cs → src/ImageSharp/Memory/SpanHelper.cs

@ -1,19 +1,18 @@
// <copyright file="BufferSpan.cs" company="James Jackson-South">
// <copyright file="SpanHelper.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Utility methods for <see cref="BufferSpan{T}"/>
/// Utility methods for <see cref="Span{T}"/>
/// </summary>
internal static class BufferSpan
internal static class SpanHelper
{
/// <summary>
/// Fetches a <see cref="Vector{T}"/> from the beginning of the span.
@ -22,7 +21,7 @@ namespace ImageSharp
/// <param name="span">The span to fetch the vector from</param>
/// <returns>A <see cref="Vector{T}"/> reference to the beginning of the span</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref Vector<T> FetchVector<T>(this BufferSpan<T> span)
public static ref Vector<T> FetchVector<T>(this Span<T> span)
where T : struct
{
return ref Unsafe.As<T, Vector<T>>(ref span.DangerousGetPinnableReference());
@ -32,11 +31,11 @@ namespace ImageSharp
/// Copy 'count' number of elements of the same type from 'source' to 'dest'
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The <see cref="BufferSpan{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="BufferSpan{T}"/>.</param>
/// <param name="source">The <see cref="Span{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="Span{T}"/>.</param>
/// <param name="count">The number of elements to copy</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Copy<T>(BufferSpan<T> source, BufferSpan<T> destination, int count)
public static unsafe void Copy<T>(Span<T> source, Span<T> destination, int count)
where T : struct
{
DebugGuard.MustBeLessThanOrEqualTo(count, source.Length, nameof(count));
@ -48,6 +47,7 @@ namespace ImageSharp
int byteCount = Unsafe.SizeOf<T>() * count;
// TODO: Use unfixed Unsafe.CopyBlock(ref T, ref T, int) for small blocks, when it gets available!
// This is now available. Check with Anton re intent. Do we replace both ifdefs?
fixed (byte* pSrc = &srcRef)
fixed (byte* pDest = &destRef)
{
@ -64,10 +64,10 @@ namespace ImageSharp
/// Copy all elements of 'source' into 'destination'.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The <see cref="BufferSpan{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="BufferSpan{T}"/>.</param>
/// <param name="source">The <see cref="Span{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="Span{T}"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy<T>(BufferSpan<T> source, BufferSpan<T> destination)
public static void Copy<T>(Span<T> source, Span<T> destination)
where T : struct
{
Copy(source, destination, source.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(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));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

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

@ -5,6 +5,8 @@
namespace ImageSharp.PixelFormats
{
using System;
/// <summary>
/// Abstract base class for calling pixel composition functions
/// </summary>
@ -34,6 +36,6 @@ namespace 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(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount);
public abstract void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount);
}
}

75
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs

@ -5,9 +5,12 @@
namespace ImageSharp.PixelFormats
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
/// <summary>
/// A stateless class implementing Strategy Pattern for batched pixel-data conversion operations
/// for pixel buffers of type <typeparamref name="TPixel"/>.
@ -24,10 +27,10 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.PackFromVector4(Vector4)"/>
/// </summary>
/// <param name="sourceVectors">The <see cref="BufferSpan{T}"/> to the source vectors.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="sourceVectors">The <see cref="Span{T}"/> to the source vectors.</param>
/// <param name="destColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromVector4(BufferSpan<Vector4> sourceVectors, BufferSpan<TPixel> destColors, int count)
internal virtual void PackFromVector4(Span<Vector4> sourceVectors, Span<TPixel> destColors, int count)
{
ref Vector4 sourceRef = ref sourceVectors.DangerousGetPinnableReference();
ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
@ -43,10 +46,10 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.ToVector4()"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="BufferSpan{T}"/> to the destination vectors.</param>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="Span{T}"/> to the destination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToVector4(BufferSpan<TPixel> sourceColors, BufferSpan<Vector4> destVectors, int count)
internal virtual void ToVector4(Span<TPixel> sourceColors, Span<Vector4> destVectors, int count)
{
ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref Vector4 destRef = ref destVectors.DangerousGetPinnableReference();
@ -62,10 +65,10 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.PackFromBytes(byte, byte, byte, byte)"/> that converts data in <see cref="ComponentOrder.Xyz"/>.
/// </summary>
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromXyzBytes(BufferSpan<byte> sourceBytes, BufferSpan<TPixel> destColors, int count)
internal virtual void PackFromXyzBytes(Span<byte> sourceBytes, Span<TPixel> destColors, int count)
{
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
@ -85,10 +88,11 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.ToXyzBytes(byte[], int)"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Buffer{T}"/> to the destination bytes.</param>
/// <param name="startIndex">The starting index of the <paramref name="destBytes"/>.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToXyzBytes(BufferSpan<TPixel> sourceColors, BufferSpan<byte> destBytes, int count)
internal virtual void ToXyzBytes(Span<TPixel> sourceColors, Buffer<byte> destBytes, int startIndex, int count)
{
ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
@ -96,17 +100,17 @@ namespace ImageSharp.PixelFormats
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
sp.ToXyzBytes(dest, destBytes.Start + (i * 3));
sp.ToXyzBytes(dest, startIndex + (i * 3));
}
}
/// <summary>
/// Bulk version of <see cref="IPixel.PackFromBytes(byte, byte, byte, byte)"/> that converts data in <see cref="ComponentOrder.Xyzw"/>.
/// </summary>
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromXyzwBytes(BufferSpan<byte> sourceBytes, BufferSpan<TPixel> destColors, int count)
internal virtual void PackFromXyzwBytes(Span<byte> sourceBytes, Span<TPixel> destColors, int count)
{
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
@ -126,10 +130,11 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.ToXyzwBytes(byte[], int)"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Buffer{T}"/> to the destination bytes.</param>
/// <param name="startIndex">The starting index of the <paramref name="destBytes"/>.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToXyzwBytes(BufferSpan<TPixel> sourceColors, BufferSpan<byte> destBytes, int count)
internal virtual void ToXyzwBytes(Span<TPixel> sourceColors, Buffer<byte> destBytes, int startIndex, int count)
{
ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
@ -137,17 +142,17 @@ namespace ImageSharp.PixelFormats
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
sp.ToXyzwBytes(dest, destBytes.Start + (i * 4));
sp.ToXyzwBytes(dest, startIndex + (i * 4));
}
}
/// <summary>
/// Bulk version of <see cref="IPixel.PackFromBytes(byte, byte, byte, byte)"/> that converts data in <see cref="ComponentOrder.Zyx"/>.
/// </summary>
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromZyxBytes(BufferSpan<byte> sourceBytes, BufferSpan<TPixel> destColors, int count)
internal virtual void PackFromZyxBytes(Span<byte> sourceBytes, Span<TPixel> destColors, int count)
{
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
@ -167,10 +172,11 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.ToZyxBytes(byte[], int)"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Buffer{T}"/> to the destination bytes.</param>
/// <param name="startIndex">The starting index of the <paramref name="destBytes"/>.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToZyxBytes(BufferSpan<TPixel> sourceColors, BufferSpan<byte> destBytes, int count)
internal virtual void ToZyxBytes(Span<TPixel> sourceColors, Buffer<byte> destBytes, int startIndex, int count)
{
ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
@ -178,17 +184,17 @@ namespace ImageSharp.PixelFormats
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
sp.ToZyxBytes(dest, destBytes.Start + (i * 3));
sp.ToZyxBytes(dest, startIndex + (i * 3));
}
}
/// <summary>
/// Bulk version of <see cref="IPixel.PackFromBytes(byte, byte, byte, byte)"/> that converts data in <see cref="ComponentOrder.Zyxw"/>.
/// </summary>
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromZyxwBytes(BufferSpan<byte> sourceBytes, BufferSpan<TPixel> destColors, int count)
internal virtual void PackFromZyxwBytes(Span<byte> sourceBytes, Span<TPixel> destColors, int count)
{
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
@ -208,10 +214,11 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.ToZyxwBytes(byte[], int)"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Buffer{T}"/> to the destination bytes.</param>
/// <param name="startIndex">The starting index of the <paramref name="destBytes"/>.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToZyxwBytes(BufferSpan<TPixel> sourceColors, BufferSpan<byte> destBytes, int count)
internal virtual void ToZyxwBytes(Span<TPixel> sourceColors, Buffer<byte> destBytes, int startIndex, int count)
{
ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
@ -219,7 +226,7 @@ namespace ImageSharp.PixelFormats
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
sp.ToZyxwBytes(dest, destBytes.Start + (i * 4));
sp.ToZyxwBytes(dest, startIndex + (i * 4));
}
}
}

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

@ -10,6 +10,7 @@ namespace ImageSharp
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <content>
@ -26,8 +27,8 @@ namespace ImageSharp
/// SIMD optimized bulk implementation of <see cref="IPixel.PackFromVector4(Vector4)"/>
/// that works only with `count` divisible by <see cref="Vector{UInt32}.Count"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="BufferSpan{T}"/> to the dstination vectors.</param>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="Span{T}"/> to the dstination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
/// <remarks>
/// Implementation adapted from:
@ -39,7 +40,7 @@ namespace ImageSharp
/// <cref>https://github.com/dotnet/corefx/issues/15957</cref>
/// </see>
/// </remarks>
internal static void ToVector4SimdAligned(BufferSpan<Rgba32> sourceColors, BufferSpan<Vector4> destVectors, int count)
internal static void ToVector4SimdAligned(Span<Rgba32> sourceColors, Span<Vector4> destVectors, int count)
{
if (!Vector.IsHardwareAccelerated)
{
@ -90,7 +91,7 @@ namespace ImageSharp
}
/// <inheritdoc />
internal override void ToVector4(BufferSpan<Rgba32> sourceColors, BufferSpan<Vector4> destVectors, int count)
internal override void ToVector4(Span<Rgba32> sourceColors, Span<Vector4> destVectors, int count)
{
if (count < 256 || !Vector.IsHardwareAccelerated)
{
@ -117,7 +118,7 @@ namespace ImageSharp
}
/// <inheritdoc />
internal override void PackFromXyzBytes(BufferSpan<byte> sourceBytes, BufferSpan<Rgba32> destColors, int count)
internal override void PackFromXyzBytes(Span<byte> sourceBytes, Span<Rgba32> destColors, int count)
{
ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
ref Rgba32 destRef = ref destColors.DangerousGetPinnableReference();
@ -133,10 +134,10 @@ namespace ImageSharp
}
/// <inheritdoc />
internal override void ToXyzBytes(BufferSpan<Rgba32> sourceColors, BufferSpan<byte> destBytes, int count)
internal override void ToXyzBytes(Span<Rgba32> sourceColors, Buffer<byte> destBytes, int startIndex, int count)
{
ref Rgba32 sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref destBytes.DangerousGetPinnableReference());
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref new Span<byte>(destBytes.Array, startIndex).DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{
@ -148,19 +149,19 @@ namespace ImageSharp
}
/// <inheritdoc />
internal override unsafe void PackFromXyzwBytes(BufferSpan<byte> sourceBytes, BufferSpan<Rgba32> destColors, int count)
internal override unsafe void PackFromXyzwBytes(Span<byte> sourceBytes, Span<Rgba32> destColors, int count)
{
BufferSpan.Copy(sourceBytes, destColors.AsBytes(), count * sizeof(Rgba32));
SpanHelper.Copy(sourceBytes, destColors.AsBytes(), count * sizeof(Rgba32));
}
/// <inheritdoc />
internal override unsafe void ToXyzwBytes(BufferSpan<Rgba32> sourceColors, BufferSpan<byte> destBytes, int count)
internal override unsafe void ToXyzwBytes(Span<Rgba32> sourceColors, Buffer<byte> destBytes, int startIndex, int count)
{
BufferSpan.Copy(sourceColors.AsBytes(), destBytes, count * sizeof(Rgba32));
SpanHelper.Copy(sourceColors.AsBytes(), new Span<byte>(destBytes.Array, startIndex), count * sizeof(Rgba32));
}
/// <inheritdoc />
internal override void PackFromZyxBytes(BufferSpan<byte> sourceBytes, BufferSpan<Rgba32> destColors, int count)
internal override void PackFromZyxBytes(Span<byte> sourceBytes, Span<Rgba32> destColors, int count)
{
ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
ref Rgba32 destRef = ref destColors.DangerousGetPinnableReference();
@ -176,10 +177,10 @@ namespace ImageSharp
}
/// <inheritdoc />
internal override void ToZyxBytes(BufferSpan<Rgba32> sourceColors, BufferSpan<byte> destBytes, int count)
internal override void ToZyxBytes(Span<Rgba32> sourceColors, Buffer<byte> destBytes, int startIndex, int count)
{
ref Rgba32 sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref destBytes.DangerousGetPinnableReference());
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref new Span<byte>(destBytes.Array, startIndex).DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{
@ -191,7 +192,7 @@ namespace ImageSharp
}
/// <inheritdoc />
internal override void PackFromZyxwBytes(BufferSpan<byte> sourceBytes, BufferSpan<Rgba32> destColors, int count)
internal override void PackFromZyxwBytes(Span<byte> sourceBytes, Span<Rgba32> destColors, int count)
{
ref RGBA32 sourceRef = ref Unsafe.As<byte, RGBA32>(ref sourceBytes.DangerousGetPinnableReference());
ref Rgba32 destRef = ref destColors.DangerousGetPinnableReference();
@ -206,10 +207,10 @@ namespace ImageSharp
}
/// <inheritdoc />
internal override void ToZyxwBytes(BufferSpan<Rgba32> sourceColors, BufferSpan<byte> destBytes, int count)
internal override void ToZyxwBytes(Span<Rgba32> sourceColors, Buffer<byte> destBytes, int startIndex, int count)
{
ref Rgba32 sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGBA32 destRef = ref Unsafe.As<byte, RGBA32>(ref destBytes.DangerousGetPinnableReference());
ref RGBA32 destRef = ref Unsafe.As<byte, RGBA32>(ref new Span<byte>(destBytes.Array, startIndex).DangerousGetPinnableReference());
for (int i = 0; i < count; i++)
{

7
src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs

@ -5,8 +5,11 @@
namespace ImageSharp.PixelFormats
{
using System;
using System.Numerics;
using ImageSharp.Memory;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
@ -18,9 +21,9 @@ namespace ImageSharp.PixelFormats
internal class PixelOperations : PixelOperations<RgbaVector>
{
/// <inheritdoc />
internal override unsafe void ToVector4(BufferSpan<RgbaVector> sourceColors, BufferSpan<Vector4> destVectors, int count)
internal override unsafe void ToVector4(Span<RgbaVector> sourceColors, Span<Vector4> destVectors, int count)
{
BufferSpan.Copy(sourceColors.AsBytes(), destVectors.AsBytes(), count * sizeof(Vector4));
SpanHelper.Copy(sourceColors.AsBytes(), destVectors.AsBytes(), count * sizeof(Vector4));
}
}
}

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

@ -7,6 +7,7 @@ namespace ImageSharp.Processing.Processors
{
using System;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

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

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

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

@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

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

@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs

@ -7,6 +7,7 @@ namespace ImageSharp.Processing.Processors
{
using System;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs

@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs

@ -7,6 +7,7 @@ namespace ImageSharp.Processing.Processors
{
using System;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

1
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

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

@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

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

@ -7,6 +7,7 @@ namespace ImageSharp.Processing.Processors
{
using System;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

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

@ -7,6 +7,7 @@ namespace ImageSharp.Processing.Processors
{
using System;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

3
src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs

@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -82,7 +83,7 @@ namespace ImageSharp.Processing.Processors
{
int offsetY = y - startY;
BufferSpan<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(minX - startX, width);
Span<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(minX - startX, width);
// this switched color & destination in the 2nd and 3rd places because we are applying the target colour under the current one
blender.Blend(destination, colors, destination, amount);

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

@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -96,7 +97,7 @@ namespace ImageSharp.Processing.Processors
amounts[i] = (this.options.BlendPercentage * (1 - (.95F * (distance / maxDistance)))).Clamp(0, 1);
}
BufferSpan<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(offsetX, width);
Span<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(destination, destination, rowColors, amounts);
}

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

@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -104,7 +105,7 @@ namespace ImageSharp.Processing.Processors
amounts[i] = (this.options.BlendPercentage * (.9F * (distance / maxDistance))).Clamp(0, 1);
}
BufferSpan<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(offsetX, width);
Span<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(destination, destination, rowColors, amounts);
}

16
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs

@ -4,6 +4,8 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
/// <content>
/// Conains the definition of <see cref="WeightsWindow"/> and <see cref="WeightsBuffer"/>.
/// </content>
@ -12,7 +14,7 @@ namespace ImageSharp.Processing.Processors
/// <summary>
/// Points to a collection of of weights allocated in <see cref="WeightsBuffer"/>.
/// </summary>
internal unsafe struct WeightsWindow
internal struct WeightsWindow
{
/// <summary>
/// The local left index position
@ -22,9 +24,7 @@ namespace ImageSharp.Processing.Processors
/// <summary>
/// The span of weights pointing to <see cref="WeightsBuffer"/>.
/// </summary>
// TODO: In the case of switching to official System.Memory and System.Buffers.Primitives this should be System.Buffers.Buffer<T> (formerly Memory<T>), because Span<T> is stack-only!
// see: https://github.com/dotnet/corefxlab/blob/873d35ebed7264e2f9adb556f3b61bebc12395d6/docs/specs/memory.md
public BufferSpan<float> Span;
public Span<float> Span;
/// <summary>
/// Initializes a new instance of the <see cref="WeightsWindow"/> struct.
@ -32,7 +32,7 @@ namespace ImageSharp.Processing.Processors
/// <param name="left">The local left index</param>
/// <param name="span">The span</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal WeightsWindow(int left, BufferSpan<float> span)
internal WeightsWindow(int left, Span<float> span)
{
this.Left = left;
this.Span = span;
@ -55,7 +55,7 @@ namespace ImageSharp.Processing.Processors
/// <param name="sourceX">The source row position.</param>
/// <returns>The weighted sum</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeWeightedRowSum(BufferSpan<Vector4> rowSpan, int sourceX)
public Vector4 ComputeWeightedRowSum(Span<Vector4> rowSpan, int sourceX)
{
ref float horizontalValues = ref this.Ptr;
int left = this.Left;
@ -82,7 +82,7 @@ namespace ImageSharp.Processing.Processors
/// <param name="sourceX">The source row position.</param>
/// <returns>The weighted sum</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeExpandedWeightedRowSum(BufferSpan<Vector4> rowSpan, int sourceX)
public Vector4 ComputeExpandedWeightedRowSum(Span<Vector4> rowSpan, int sourceX)
{
ref float horizontalValues = ref this.Ptr;
int left = this.Left;
@ -169,7 +169,7 @@ namespace ImageSharp.Processing.Processors
/// <returns>The weights</returns>
public WeightsWindow GetWeightsWindow(int destIdx, int leftIdx, int rightIdx)
{
BufferSpan<float> span = this.dataBuffer.GetRowSpan(destIdx).Slice(leftIdx, rightIdx - leftIdx + 1);
Span<float> span = this.dataBuffer.GetRowSpan(destIdx).Slice(leftIdx, rightIdx - leftIdx + 1);
return new WeightsWindow(leftIdx, span);
}
}

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

@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -121,7 +122,7 @@ namespace ImageSharp.Processing.Processors
// TODO: Without Parallel.For() this buffer object could be reused:
using (Buffer<Vector4> tempRowBuffer = new Buffer<Vector4>(sourcePixels.Width))
{
BufferSpan<TPixel> sourceRow = sourcePixels.GetRowSpan(y);
Span<TPixel> sourceRow = sourcePixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(
sourceRow,

2
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs

@ -6,7 +6,7 @@
using BenchmarkDotNet.Attributes;
using ImageSharp;
using ImageSharp.PixelFormats;
using ImageSharp.Memory;
/// <summary>
/// Compares two implementation candidates for general BulkPixelOperations.ToVector4():

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

@ -3,6 +3,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk
{
using BenchmarkDotNet.Attributes;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
public abstract class PackFromXyzw<TPixel>

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

@ -5,6 +5,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk
using BenchmarkDotNet.Attributes;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
public abstract class ToVector4<TPixel>

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

@ -3,6 +3,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk
{
using BenchmarkDotNet.Attributes;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
public abstract class ToXyz<TPixel>
@ -45,13 +46,13 @@ namespace ImageSharp.Benchmarks.Color.Bulk
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().ToXyzBytes(this.source, this.destination, this.Count);
new PixelOperations<TPixel>().ToXyzBytes(this.source, this.destination, 0, this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.ToXyzBytes(this.source, this.destination, this.Count);
PixelOperations<TPixel>.Instance.ToXyzBytes(this.source, this.destination, 0, this.Count);
}
}

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

@ -7,6 +7,8 @@ using System.Threading.Tasks;
namespace ImageSharp.Benchmarks.Color.Bulk
{
using BenchmarkDotNet.Attributes;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
public abstract class ToXyzw<TPixel>
@ -49,16 +51,16 @@ namespace ImageSharp.Benchmarks.Color.Bulk
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().ToXyzwBytes(this.source, this.destination, this.Count);
new PixelOperations<TPixel>().ToXyzwBytes(this.source, this.destination, 0, this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.ToXyzwBytes(this.source, this.destination, this.Count);
PixelOperations<TPixel>.Instance.ToXyzwBytes(this.source, this.destination, 0, this.Count);
}
}
public class ToXyzw_Rgba32 : ToXyzw<Rgba32>
{
}

2
tests/ImageSharp.Benchmarks/General/Array2D.cs

@ -9,6 +9,8 @@ namespace ImageSharp.Benchmarks.General
using BenchmarkDotNet.Attributes;
using ImageSharp.Memory;
public class Array2D
{
private float[] flatArray;

3
tests/ImageSharp.Benchmarks/General/ClearBuffer.cs

@ -3,11 +3,10 @@ namespace ImageSharp.Benchmarks.General
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using ImageSharp.PixelFormats;
using ImageSharp.Memory;
public unsafe class ClearBuffer
{

2
tests/ImageSharp.Benchmarks/General/IterateArray.cs

@ -5,6 +5,8 @@ namespace ImageSharp.Benchmarks.General
using BenchmarkDotNet.Attributes;
using ImageSharp.Memory;
public class IterateArray
{
// Usual pinned stuff

2
tests/ImageSharp.Benchmarks/General/PixelIndexing.cs

@ -5,6 +5,8 @@
using BenchmarkDotNet.Attributes;
using ImageSharp.Memory;
// Pixel indexing benchmarks compare different methods for getting/setting all pixel values in a subsegment of a single pixel row.
public abstract unsafe class PixelIndexing
{

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

@ -1,9 +1,11 @@
namespace ImageSharp.Benchmarks.General.Vectorization
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using ImageSharp.Memory;
/// <summary>
/// This benchmark compares different methods for fetching memory data into <see cref="Vector{T}"/>
@ -88,11 +90,11 @@ namespace ImageSharp.Benchmarks.General.Vectorization
}
[Benchmark]
public void FetchWithBufferSpanUtility()
public void FetchWithSpanUtility()
{
Vector<float> v = new Vector<float>(this.testValue);
BufferSpan<float> span = new BufferSpan<float>(this.data);
Span<float> span = new Span<float>(this.data);
ref Vector<float> start = ref span.FetchVector();

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

@ -5,16 +5,19 @@
namespace ImageSharp.Benchmarks
{
using System;
using BenchmarkDotNet.Attributes;
using ImageSharp.PixelFormats;
using CoreSize = ImageSharp.Size;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats.PixelBlenders;
public class PorterDuffBulkVsPixel : BenchmarkBase
{
private void BulkVectorConvert<TPixel>(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
private void BulkVectorConvert<TPixel>(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
where TPixel : struct, IPixel<TPixel>
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
@ -23,9 +26,9 @@ namespace ImageSharp.Benchmarks
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
@ -38,7 +41,7 @@ namespace ImageSharp.Benchmarks
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
private void BulkPixelConvert<TPixel>(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
private void BulkPixelConvert<TPixel>(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
where TPixel : struct, IPixel<TPixel>
{
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination));
@ -66,7 +69,7 @@ namespace ImageSharp.Benchmarks
{
for (int y = 0; y < image.Height; y++)
{
BufferSpan<Rgba32> span = pixels.GetRowSpan(y);
Span<Rgba32> span = pixels.GetRowSpan(y);
BulkVectorConvert(span, span, span, amounts);
}
}
@ -89,7 +92,7 @@ namespace ImageSharp.Benchmarks
{
for (int y = 0; y < image.Height; y++)
{
BufferSpan<Rgba32> span = pixels.GetRowSpan(y);
Span<Rgba32> span = pixels.GetRowSpan(y);
BulkPixelConvert(span, span, span, amounts);
}
}

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

@ -15,6 +15,8 @@ namespace ImageSharp.Benchmarks
using System;
using System.Threading.Tasks;
using ImageSharp.Memory;
public class Glow : BenchmarkBase
{
private GlowProcessor<Rgba32> bulk;

54
tests/ImageSharp.Benchmarks/Samplers/Resize.cs

@ -46,34 +46,34 @@ namespace ImageSharp.Benchmarks
}
}
[Benchmark(Description = "ImageSharp Vector Resize")]
public CoreSize ResizeCoreVector()
{
using (Image<RgbaVector> image = new Image<RgbaVector>(2000, 2000))
{
image.Resize(400, 400);
return new CoreSize(image.Width, image.Height);
}
}
//[Benchmark(Description = "ImageSharp Vector Resize")]
//public CoreSize ResizeCoreVector()
//{
// using (Image<RgbaVector> image = new Image<RgbaVector>(2000, 2000))
// {
// image.Resize(400, 400);
// return new CoreSize(image.Width, image.Height);
// }
//}
[Benchmark(Description = "ImageSharp Compand Resize")]
public CoreSize ResizeCoreCompand()
{
using (Image<Rgba32> image = new Image<Rgba32>(2000, 2000))
{
image.Resize(400, 400, true);
return new CoreSize(image.Width, image.Height);
}
}
//[Benchmark(Description = "ImageSharp Compand Resize")]
//public CoreSize ResizeCoreCompand()
//{
// using (Image<Rgba32> image = new Image<Rgba32>(2000, 2000))
// {
// image.Resize(400, 400, true);
// return new CoreSize(image.Width, image.Height);
// }
//}
[Benchmark(Description = "ImageSharp Vector Compand Resize")]
public CoreSize ResizeCoreVectorCompand()
{
using (Image<RgbaVector> image = new Image<RgbaVector>(2000, 2000))
{
image.Resize(400, 400, true);
return new CoreSize(image.Width, image.Height);
}
}
//[Benchmark(Description = "ImageSharp Vector Compand Resize")]
//public CoreSize ResizeCoreVectorCompand()
//{
// using (Image<RgbaVector> image = new Image<RgbaVector>(2000, 2000))
// {
// image.Resize(400, 400, true);
// return new CoreSize(image.Width, image.Height);
// }
//}
}
}

17
tests/ImageSharp.Tests/Colors/PixelOperationsTests.cs

@ -5,6 +5,7 @@ namespace ImageSharp.Tests.Colors
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Xunit;
@ -180,7 +181,7 @@ namespace ImageSharp.Tests.Colors
TestOperation(
source,
expected,
(s, d) => Operations.ToXyzBytes(s, d, count)
(s, d) => Operations.ToXyzBytes(s, d, 0, count)
);
}
@ -221,7 +222,7 @@ namespace ImageSharp.Tests.Colors
TestOperation(
source,
expected,
(s, d) => Operations.ToXyzwBytes(s, d, count)
(s, d) => Operations.ToXyzwBytes(s, d, 0, count)
);
}
@ -262,7 +263,7 @@ namespace ImageSharp.Tests.Colors
TestOperation(
source,
expected,
(s, d) => Operations.ToZyxBytes(s, d, count)
(s, d) => Operations.ToZyxBytes(s, d, 0, count)
);
}
@ -303,7 +304,7 @@ namespace ImageSharp.Tests.Colors
TestOperation(
source,
expected,
(s, d) => Operations.ToZyxwBytes(s, d, count)
(s, d) => Operations.ToZyxwBytes(s, d, 0, count)
);
}
@ -316,8 +317,8 @@ namespace ImageSharp.Tests.Colors
public Buffer<TDest> ActualDestBuffer { get; }
public Buffer<TDest> ExpectedDestBuffer { get; }
public BufferSpan<TSource> Source => this.SourceBuffer;
public BufferSpan<TDest> ActualDest => this.ActualDestBuffer;
public Span<TSource> Source => this.SourceBuffer;
public Span<TDest> ActualDest => this.ActualDestBuffer;
public TestBuffers(TSource[] source, TDest[] expectedDest)
{
@ -366,13 +367,13 @@ namespace ImageSharp.Tests.Colors
internal static void TestOperation<TSource, TDest>(
TSource[] source,
TDest[] expected,
Action<BufferSpan<TSource>, BufferSpan<TDest>> action)
Action<Span<TSource>, Buffer<TDest>> action)
where TSource : struct
where TDest : struct
{
using (TestBuffers<TSource, TDest> buffers = new TestBuffers<TSource, TDest>(source, expected))
{
action(buffers.Source, buffers.ActualDest);
action(buffers.Source, buffers.ActualDestBuffer);
buffers.Verify();
}
}

12
tests/ImageSharp.Tests/Common/Buffer2DTests.cs

@ -4,6 +4,8 @@ namespace ImageSharp.Tests.Common
using System;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
using Xunit;
using static TestStructs;
@ -13,7 +15,7 @@ namespace ImageSharp.Tests.Common
// ReSharper disable once ClassNeverInstantiated.Local
private class Assert : Xunit.Assert
{
public static void SpanPointsTo<T>(BufferSpan<T> span, Buffer<T> buffer, int bufferOffset = 0)
public static void SpanPointsTo<T>(Span<T> span, Buffer<T> buffer, int bufferOffset = 0)
where T : struct
{
ref T actual = ref span.DangerousGetPinnableReference();
@ -75,9 +77,9 @@ namespace ImageSharp.Tests.Common
{
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height))
{
BufferSpan<Foo> span = buffer.GetRowSpan(y);
Span<Foo> span = buffer.GetRowSpan(y);
Assert.Equal(width * y, span.Start);
// Assert.Equal(width * y, span.Start);
Assert.Equal(width, span.Length);
Assert.SpanPointsTo(span, buffer, width * y);
}
@ -91,9 +93,9 @@ namespace ImageSharp.Tests.Common
{
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height))
{
BufferSpan<Foo> span = buffer.GetRowSpan(x, y);
Span<Foo> span = buffer.GetRowSpan(x, y);
Assert.Equal(width * y + x, span.Start);
// Assert.Equal(width * y + x, span.Start);
Assert.Equal(width - x, span.Length);
Assert.SpanPointsTo(span, buffer, width * y + x);
}

115
tests/ImageSharp.Tests/Common/BufferSpanTests.cs

@ -7,13 +7,14 @@ namespace ImageSharp.Tests.Common
using System.Numerics;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Xunit;
using static TestStructs;
public unsafe class BufferSpanTests
public unsafe class SpanTests
{
// ReSharper disable once ClassNeverInstantiated.Local
private class Assert : Xunit.Assert
@ -31,7 +32,7 @@ namespace ImageSharp.Tests.Common
{
float[] stuff = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
BufferSpan<float> span = new BufferSpan<float>(stuff);
Span<float> span = new Span<float>(stuff);
ref Vector<float> v = ref span.FetchVector();
@ -48,10 +49,10 @@ namespace ImageSharp.Tests.Common
using (Buffer<Foo> colorBuf = new Buffer<Foo>(fooz))
{
BufferSpan<Foo> orig = colorBuf.Slice(1);
BufferSpan<byte> asBytes = orig.AsBytes();
Span<Foo> orig = colorBuf.Slice(1);
Span<byte> asBytes = orig.AsBytes();
Assert.Equal(asBytes.Start, sizeof(Foo));
// Assert.Equal(asBytes.Start, sizeof(Foo));
Assert.Equal(orig.Length * Unsafe.SizeOf<Foo>(), asBytes.Length);
Assert.SameRefs(ref orig.DangerousGetPinnableReference(), ref asBytes.DangerousGetPinnableReference());
}
@ -65,10 +66,10 @@ namespace ImageSharp.Tests.Common
Foo[] array = Foo.CreateArray(3);
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array);
Span<Foo> span = new Span<Foo>(array);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(array, span.ToArray());
Assert.Equal(3, span.Length);
Assert.SameRefs(ref array[0], ref span.DangerousGetPinnableReference());
}
@ -80,11 +81,9 @@ namespace ImageSharp.Tests.Common
int start = 2;
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, start);
Span<Foo> span = new Span<Foo>(array, start);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(start, span.Start);
Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
Assert.Equal(array.Length - start, span.Length);
}
@ -96,11 +95,9 @@ namespace ImageSharp.Tests.Common
int start = 2;
int length = 3;
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, start, length);
Span<Foo> span = new Span<Foo>(array, start, length);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(start, span.Start);
Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
Assert.Equal(length, span.Length);
}
@ -116,14 +113,12 @@ namespace ImageSharp.Tests.Common
int start1 = 2;
int totalOffset = start0 + start1;
BufferSpan<Foo> span = new BufferSpan<Foo>(array, start0);
Span<Foo> span = new Span<Foo>(array, start0);
// Act:
span = span.Slice(start1);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(totalOffset, span.Start);
Assert.SameRefs(ref array[totalOffset], ref span.DangerousGetPinnableReference());
Assert.Equal(array.Length - totalOffset, span.Length);
}
@ -137,37 +132,35 @@ namespace ImageSharp.Tests.Common
int totalOffset = start0 + start1;
int sliceLength = 3;
BufferSpan<Foo> span = new BufferSpan<Foo>(array, start0);
Span<Foo> span = new Span<Foo>(array, start0);
// Act:
span = span.Slice(start1, sliceLength);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(totalOffset, span.Start);
Assert.SameRefs(ref array[totalOffset], ref span.DangerousGetPinnableReference());
Assert.Equal(sliceLength, span.Length);
}
}
[Theory]
[InlineData(4)]
[InlineData(1500)]
public void Clear(int count)
{
Foo[] array = Foo.CreateArray(count + 42);
//[Theory]
//[InlineData(4)]
//[InlineData(1500)]
//public void Clear(int count)
//{
// Foo[] array = Foo.CreateArray(count + 42);
int offset = 2;
BufferSpan<Foo> ap = new BufferSpan<Foo>(array, offset);
// int offset = 2;
// Span<Foo> ap = new Span<Foo>(array, offset);
// Act:
ap.Clear(count);
// // Act:
// ap.Clear(count);
Assert.NotEqual(default(Foo), array[offset - 1]);
Assert.Equal(default(Foo), array[offset]);
Assert.Equal(default(Foo), array[offset + count - 1]);
Assert.NotEqual(default(Foo), array[offset + count]);
}
// Assert.NotEqual(default(Foo), array[offset - 1]);
// Assert.Equal(default(Foo), array[offset]);
// Assert.Equal(default(Foo), array[offset + count - 1]);
// Assert.NotEqual(default(Foo), array[offset + count]);
//}
public class Indexer
{
@ -187,7 +180,7 @@ namespace ImageSharp.Tests.Common
public void Read(int length, int start, int index)
{
Foo[] a = Foo.CreateArray(length);
BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
Span<Foo> span = new Span<Foo>(a, start);
Foo element = span[index];
@ -199,7 +192,7 @@ namespace ImageSharp.Tests.Common
public void Write(int length, int start, int index)
{
Foo[] a = Foo.CreateArray(length);
BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
Span<Foo> span = new Span<Foo>(a, start);
span[index] = new Foo(666, 666);
@ -214,9 +207,9 @@ namespace ImageSharp.Tests.Common
public void AsBytes_Read(int length, int start, int index, int byteOffset)
{
Foo[] a = Foo.CreateArray(length);
BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
Span<Foo> span = new Span<Foo>(a, start);
BufferSpan<byte> bytes = span.AsBytes();
Span<byte> bytes = span.AsBytes();
byte actual = bytes[index * Unsafe.SizeOf<Foo>() + byteOffset];
@ -234,7 +227,7 @@ namespace ImageSharp.Tests.Common
public void DangerousGetPinnableReference(int start, int length)
{
Foo[] a = Foo.CreateArray(length);
BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
Span<Foo> span = new Span<Foo>(a, start);
ref Foo r = ref span.DangerousGetPinnableReference();
Assert.True(Unsafe.AreSame(ref a[start], ref r));
@ -276,10 +269,10 @@ namespace ImageSharp.Tests.Common
Foo[] source = Foo.CreateArray(count + 2);
Foo[] dest = new Foo[count + 5];
BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, 1);
BufferSpan<Foo> apDest = new BufferSpan<Foo>(dest, 1);
Span<Foo> apSource = new Span<Foo>(source, 1);
Span<Foo> apDest = new Span<Foo>(dest, 1);
BufferSpan.Copy(apSource, apDest, count - 1);
SpanHelper.Copy(apSource, apDest, count - 1);
AssertNotDefault(source, 1);
AssertNotDefault(dest, 1);
@ -299,10 +292,10 @@ namespace ImageSharp.Tests.Common
AlignedFoo[] source = AlignedFoo.CreateArray(count + 2);
AlignedFoo[] dest = new AlignedFoo[count + 5];
BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, 1);
BufferSpan<AlignedFoo> apDest = new BufferSpan<AlignedFoo>(dest, 1);
Span<AlignedFoo> apSource = new Span<AlignedFoo>(source, 1);
Span<AlignedFoo> apDest = new Span<AlignedFoo>(dest, 1);
BufferSpan.Copy(apSource, apDest, count - 1);
SpanHelper.Copy(apSource, apDest, count - 1);
AssertNotDefault(source, 1);
AssertNotDefault(dest, 1);
@ -322,10 +315,10 @@ namespace ImageSharp.Tests.Common
int[] source = CreateTestInts(count + 2);
int[] dest = new int[count + 5];
BufferSpan<int> apSource = new BufferSpan<int>(source, 1);
BufferSpan<int> apDest = new BufferSpan<int>(dest, 1);
Span<int> apSource = new Span<int>(source, 1);
Span<int> apDest = new Span<int>(dest, 1);
BufferSpan.Copy(apSource, apDest, count - 1);
SpanHelper.Copy(apSource, apDest, count - 1);
AssertNotDefault(source, 1);
AssertNotDefault(dest, 1);
@ -346,10 +339,10 @@ namespace ImageSharp.Tests.Common
Foo[] source = Foo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(Foo) * 2];
BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, 1);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, sizeof(Foo));
Span<Foo> apSource = new Span<Foo>(source, 1);
Span<byte> apDest = new Span<byte>(dest, sizeof(Foo));
BufferSpan.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(Foo));
SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(Foo));
AssertNotDefault(source, 1);
@ -369,10 +362,10 @@ namespace ImageSharp.Tests.Common
AlignedFoo[] source = AlignedFoo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(AlignedFoo) * 2];
BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, 1);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, sizeof(AlignedFoo));
Span<AlignedFoo> apSource = new Span<AlignedFoo>(source, 1);
Span<byte> apDest = new Span<byte>(dest, sizeof(AlignedFoo));
BufferSpan.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(AlignedFoo));
SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(AlignedFoo));
AssertNotDefault(source, 1);
@ -392,10 +385,10 @@ namespace ImageSharp.Tests.Common
int[] source = CreateTestInts(count + 2);
byte[] dest = new byte[destCount + sizeof(int) + 1];
BufferSpan<int> apSource = new BufferSpan<int>(source);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest);
Span<int> apSource = new Span<int>(source);
Span<byte> apDest = new Span<byte>(dest);
BufferSpan.Copy(apSource.AsBytes(), apDest, count * sizeof(int));
SpanHelper.Copy(apSource.AsBytes(), apDest, count * sizeof(int));
AssertNotDefault(source, 1);
@ -413,10 +406,10 @@ namespace ImageSharp.Tests.Common
byte[] source = CreateTestBytes(srcCount);
Foo[] dest = new Foo[count + 2];
BufferSpan<byte> apSource = new BufferSpan<byte>(source);
BufferSpan<Foo> apDest = new BufferSpan<Foo>(dest);
Span<byte> apSource = new Span<byte>(source);
Span<Foo> apDest = new Span<Foo>(dest);
BufferSpan.Copy(apSource, apDest.AsBytes(), count * sizeof(Foo));
SpanHelper.Copy(apSource, apDest.AsBytes(), count * sizeof(Foo));
AssertNotDefault(source, sizeof(Foo) + 1);
AssertNotDefault(dest, 1);
@ -435,7 +428,7 @@ namespace ImageSharp.Tests.Common
using (Buffer<Rgba32> colorBuf = new Buffer<Rgba32>(colors))
using (Buffer<byte> byteBuf = new Buffer<byte>(colors.Length * 4))
{
BufferSpan.Copy(colorBuf.Span.AsBytes(), byteBuf, colorBuf.Length * sizeof(Rgba32));
SpanHelper.Copy(colorBuf.Span.AsBytes(), byteBuf, colorBuf.Length * sizeof(Rgba32));
byte[] a = byteBuf.Array;

30
tests/ImageSharp.Tests/Common/BufferTests.cs

@ -6,6 +6,8 @@ namespace ImageSharp.Tests.Common
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ImageSharp.Memory;
using Xunit;
using static TestStructs;
@ -15,7 +17,7 @@ namespace ImageSharp.Tests.Common
// ReSharper disable once ClassNeverInstantiated.Local
private class Assert : Xunit.Assert
{
public static void SpanPointsTo<T>(BufferSpan<T> span, Buffer<T> buffer, int bufferOffset = 0)
public static void SpanPointsTo<T>(Span<T> span, Buffer<T> buffer, int bufferOffset = 0)
where T : struct
{
ref T actual = ref span.DangerousGetPinnableReference();
@ -58,10 +60,8 @@ namespace ImageSharp.Tests.Common
}
}
[Theory]
[InlineData(42)]
[InlineData(1111)]
public void Clear(int count)
[Fact]
public void Clear()
{
Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } };
using (Buffer<Foo> buffer = new Buffer<Foo>(a))
@ -144,10 +144,10 @@ namespace ImageSharp.Tests.Common
{
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength))
{
BufferSpan<Foo> span = buffer;
Span<Foo> span = buffer;
Assert.Equal(buffer.Array, span.Array);
Assert.Equal(0, span.Start);
//Assert.Equal(buffer.Array, span.ToArray());
//Assert.Equal(0, span.Start);
Assert.SpanPointsTo(span, buffer);
Assert.Equal(span.Length, bufferLength);
}
@ -158,10 +158,10 @@ namespace ImageSharp.Tests.Common
{
using (Buffer<Foo> buffer = new Buffer<Foo>(42))
{
BufferSpan<Foo> span = buffer.Span;
Span<Foo> span = buffer.Span;
Assert.Equal(buffer.Array, span.Array);
Assert.Equal(0, span.Start);
// Assert.Equal(buffer.Array, span.ToArray());
// Assert.Equal(0, span.Start);
Assert.SpanPointsTo(span, buffer);
Assert.Equal(span.Length, 42);
}
@ -177,10 +177,8 @@ namespace ImageSharp.Tests.Common
{
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength))
{
BufferSpan<Foo> span = buffer.Slice(start);
Span<Foo> span = buffer.Slice(start);
Assert.Equal(buffer.Array, span.Array);
Assert.Equal(start, span.Start);
Assert.SpanPointsTo(span, buffer, start);
Assert.Equal(span.Length, bufferLength - start);
}
@ -193,10 +191,8 @@ namespace ImageSharp.Tests.Common
{
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength))
{
BufferSpan<Foo> span = buffer.Slice(start, spanLength);
Span<Foo> span = buffer.Slice(start, spanLength);
Assert.Equal(buffer.Array, span.Array);
Assert.Equal(start, span.Start);
Assert.SpanPointsTo(span, buffer, start);
Assert.Equal(span.Length, spanLength);
}

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

Loading…
Cancel
Save