From f11a3a019b747d6036f205b2bc3f9a7a6689dc2b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 10 Feb 2020 00:02:05 +1100 Subject: [PATCH] Use Span as buffer param --- .../Advanced/IRowIntervalOperation.cs | 81 ------------- .../IRowIntervalOperation{TBuffer}.cs | 78 +------------ .../Advanced/ParallelRowIterator.Wrappers.cs | 110 ++++++++++++++++++ .../Advanced/ParallelRowIterator.cs | 4 +- .../Convolution/BokehBlurProcessor{TPixel}.cs | 11 +- .../Convolution2DProcessor{TPixel}.cs | 14 +-- .../Convolution2PassProcessor{TPixel}.cs | 14 +-- .../ConvolutionProcessor{TPixel}.cs | 14 +-- ...lRowDelegateProcessor{TPixel,TDelegate}.cs | 12 +- .../Filters/FilterProcessor{TPixel}.cs | 12 +- .../Overlays/GlowProcessor{TPixel}.cs | 7 +- .../Overlays/VignetteProcessor{TPixel}.cs | 7 +- .../AffineTransformProcessor{TPixel}.cs | 9 +- .../ProjectiveTransformProcessor{TPixel}.cs | 9 +- .../Helpers/ParallelRowIteratorTests.cs | 26 ++--- .../TestUtilities/TestImageExtensions.cs | 11 +- 16 files changed, 175 insertions(+), 244 deletions(-) create mode 100644 src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs diff --git a/src/ImageSharp/Advanced/IRowIntervalOperation.cs b/src/ImageSharp/Advanced/IRowIntervalOperation.cs index 9aa79e730..3e1b08621 100644 --- a/src/ImageSharp/Advanced/IRowIntervalOperation.cs +++ b/src/ImageSharp/Advanced/IRowIntervalOperation.cs @@ -18,85 +18,4 @@ namespace SixLabors.ImageSharp.Advanced /// The row interval. void Invoke(in RowInterval rows); } - - internal readonly struct WrappingRowIntervalInfo - { - public readonly int MinY; - public readonly int MaxY; - public readonly int StepY; - public readonly int MaxX; - - public WrappingRowIntervalInfo(int minY, int maxY, int stepY) - : this(minY, maxY, stepY, 0) - { - } - - public WrappingRowIntervalInfo(int minY, int maxY, int stepY, int maxX) - { - this.MinY = minY; - this.MaxY = maxY; - this.StepY = stepY; - this.MaxX = maxX; - } - } - - internal readonly struct WrappingRowIntervalOperation - { - private readonly WrappingRowIntervalInfo info; - private readonly Action action; - - [MethodImpl(InliningOptions.ShortMethod)] - public WrappingRowIntervalOperation(in WrappingRowIntervalInfo info, Action action) - { - this.info = info; - this.action = action; - } - - [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(int i) - { - int yMin = this.info.MinY + (i * this.info.StepY); - - if (yMin >= this.info.MaxY) - { - return; - } - - int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); - var rows = new RowInterval(yMin, yMax); - - this.action(rows); - } - } - - internal readonly struct WrappingRowIntervalOperation - where T : struct, IRowIntervalOperation - { - private readonly WrappingRowIntervalInfo info; - private readonly T operation; - - [MethodImpl(InliningOptions.ShortMethod)] - public WrappingRowIntervalOperation(in WrappingRowIntervalInfo info, in T operation) - { - this.info = info; - this.operation = operation; - } - - [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(int i) - { - int yMin = this.info.MinY + (i * this.info.StepY); - - if (yMin >= this.info.MaxY) - { - return; - } - - int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); - var rows = new RowInterval(yMin, yMax); - - // Skip the safety copy when invoking a potentially impure method on a readonly field - Unsafe.AsRef(this.operation).Invoke(in rows); - } - } } diff --git a/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs b/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs index 18ebc9fb9..c18842a92 100644 --- a/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs +++ b/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs @@ -19,81 +19,7 @@ namespace SixLabors.ImageSharp.Advanced /// Invokes the method passing the row interval and a buffer. /// /// The row interval. - /// The contiguous region of memory. - void Invoke(in RowInterval rows, Memory memory); - } - - internal readonly struct WrappingRowIntervalBufferOperation - where TBuffer : unmanaged - { - private readonly WrappingRowIntervalInfo info; - private readonly MemoryAllocator allocator; - private readonly Action> action; - - [MethodImpl(InliningOptions.ShortMethod)] - public WrappingRowIntervalBufferOperation( - in WrappingRowIntervalInfo info, - MemoryAllocator allocator, - Action> action) - { - this.info = info; - this.allocator = allocator; - this.action = action; - } - - [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(int i) - { - int yMin = this.info.MinY + (i * this.info.StepY); - - if (yMin >= this.info.MaxY) - { - return; - } - - int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); - var rows = new RowInterval(yMin, yMax); - - using IMemoryOwner buffer = this.allocator.Allocate(this.info.MaxX); - this.action(rows, buffer.Memory); - } - } - - internal readonly struct WrappingRowIntervalBufferOperation - where T : struct, IRowIntervalOperation - where TBuffer : unmanaged - { - private readonly WrappingRowIntervalInfo info; - private readonly MemoryAllocator allocator; - private readonly T operation; - - [MethodImpl(InliningOptions.ShortMethod)] - public WrappingRowIntervalBufferOperation( - in WrappingRowIntervalInfo info, - MemoryAllocator allocator, - in T operation) - { - this.info = info; - this.allocator = allocator; - this.operation = operation; - } - - [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(int i) - { - int yMin = this.info.MinY + (i * this.info.StepY); - - if (yMin >= this.info.MaxY) - { - return; - } - - int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); - var rows = new RowInterval(yMin, yMax); - - using IMemoryOwner buffer = this.allocator.Allocate(this.info.MaxX); - - Unsafe.AsRef(this.operation).Invoke(in rows, buffer.Memory); - } + /// The contiguous region of memory. + void Invoke(in RowInterval rows, Span span); } } diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs new file mode 100644 index 000000000..4abcd1a3e --- /dev/null +++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs @@ -0,0 +1,110 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Utility methods for batched processing of pixel row intervals. + /// Parallel execution is optimized for image processing based on values defined + /// or . + /// Using this class is preferred over direct usage of utility methods. + /// + public static partial class ParallelRowIterator + { + private readonly struct WrappingRowIntervalInfo + { + public readonly int MinY; + public readonly int MaxY; + public readonly int StepY; + public readonly int MaxX; + + public WrappingRowIntervalInfo(int minY, int maxY, int stepY) + : this(minY, maxY, stepY, 0) + { + } + + public WrappingRowIntervalInfo(int minY, int maxY, int stepY, int maxX) + { + this.MinY = minY; + this.MaxY = maxY; + this.StepY = stepY; + this.MaxX = maxX; + } + } + + private readonly struct WrappingRowIntervalOperation + where T : struct, IRowIntervalOperation + { + private readonly WrappingRowIntervalInfo info; + private readonly T operation; + + [MethodImpl(InliningOptions.ShortMethod)] + public WrappingRowIntervalOperation(in WrappingRowIntervalInfo info, in T operation) + { + this.info = info; + this.operation = operation; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void Invoke(int i) + { + int yMin = this.info.MinY + (i * this.info.StepY); + + if (yMin >= this.info.MaxY) + { + return; + } + + int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); + var rows = new RowInterval(yMin, yMax); + + // Skip the safety copy when invoking a potentially impure method on a readonly field + Unsafe.AsRef(this.operation).Invoke(in rows); + } + } + + private readonly struct WrappingRowIntervalBufferOperation + where T : struct, IRowIntervalOperation + where TBuffer : unmanaged + { + private readonly WrappingRowIntervalInfo info; + private readonly MemoryAllocator allocator; + private readonly T operation; + + [MethodImpl(InliningOptions.ShortMethod)] + public WrappingRowIntervalBufferOperation( + in WrappingRowIntervalInfo info, + MemoryAllocator allocator, + in T operation) + { + this.info = info; + this.allocator = allocator; + this.operation = operation; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void Invoke(int i) + { + int yMin = this.info.MinY + (i * this.info.StepY); + + if (yMin >= this.info.MaxY) + { + return; + } + + int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); + var rows = new RowInterval(yMin, yMax); + + using IMemoryOwner buffer = this.allocator.Allocate(this.info.MaxX); + + Unsafe.AsRef(this.operation).Invoke(in rows, buffer.Memory.Span); + } + } + } +} diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs index d7939478b..e9d522966 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Advanced /// or . /// Using this class is preferred over direct usage of utility methods. /// - public static class ParallelRowIterator + public static partial class ParallelRowIterator { /// /// Iterate through the rows of a rectangle in optimized batches defined by -s. @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.Advanced var rows = new RowInterval(top, bottom); using (IMemoryOwner buffer = allocator.Allocate(width)) { - Unsafe.AsRef(operation).Invoke(rows, buffer.Memory); + Unsafe.AsRef(operation).Invoke(rows, buffer.Memory.Span); } return; diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index 16acc2407..e388fdaad 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -448,16 +448,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span vectorSpan = memory.Span; - int length = vectorSpan.Length; - for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan, PixelConversionModifiers.Premultiply); - ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectorSpan); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span, PixelConversionModifiers.Premultiply); + ref Vector4 baseRef = ref MemoryMarshal.GetReference(span); for (int x = 0; x < this.bounds.Width; x++) { @@ -467,7 +464,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution v.Z = MathF.Pow(v.Z, this.gamma); } - PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index d8179c6d5..1c4987c79 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -113,16 +113,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span vectorSpan = memory.Span; - int length = vectorSpan.Length; - ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan); + ref Vector4 spanRef = ref MemoryMarshal.GetReference(span); for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); if (this.preserveAlpha) { @@ -132,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution in this.kernelY, in this.kernelX, this.sourcePixels, - ref vectorSpanRef, + ref spanRef, y, x, this.bounds.Y, @@ -149,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution in this.kernelY, in this.kernelX, this.sourcePixels, - ref vectorSpanRef, + ref spanRef, y, x, this.bounds.Y, @@ -159,7 +157,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } } - PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index fb477e2d6..33a8ab7d1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -109,11 +109,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span vectorSpan = memory.Span; - int length = vectorSpan.Length; - ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan); + ref Vector4 spanRef = ref MemoryMarshal.GetReference(span); int maxY = this.bounds.Bottom - 1; int maxX = this.bounds.Right - 1; @@ -121,7 +119,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); if (this.preserveAlpha) { @@ -130,7 +128,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve3( in this.kernel, this.sourcePixels, - ref vectorSpanRef, + ref spanRef, y, x, this.bounds.Y, @@ -146,7 +144,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve4( in this.kernel, this.sourcePixels, - ref vectorSpanRef, + ref spanRef, y, x, this.bounds.Y, @@ -156,7 +154,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } } - PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index feb27ac62..542ee389b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -100,16 +100,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span vectorSpan = memory.Span; - int length = vectorSpan.Length; - ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan); + ref Vector4 spanRef = ref MemoryMarshal.GetReference(span); for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); if (this.preserveAlpha) { @@ -118,7 +116,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve3( in this.kernel, this.sourcePixels, - ref vectorSpanRef, + ref spanRef, y, x, this.bounds.Y, @@ -134,7 +132,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve4( in this.kernel, this.sourcePixels, - ref vectorSpanRef, + ref spanRef, y, x, this.bounds.Y, @@ -144,7 +142,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } } - PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } } } diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs index a22af8ce2..44ade727a 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs @@ -86,19 +86,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { for (int y = rows.Min; y < rows.Max; y++) { - Span vectorSpan = memory.Span; - int length = vectorSpan.Length; - Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length); - PixelOperations.Instance.ToVector4(this.configuration, rowSpan, vectorSpan, this.modifiers); + Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); + PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers); // Run the user defined pixel shader to the current row of pixels - Unsafe.AsRef(this.rowProcessor).Invoke(vectorSpan, new Point(this.startX, y)); + Unsafe.AsRef(this.rowProcessor).Invoke(span, new Point(this.startX, y)); - PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, rowSpan, this.modifiers); + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers); } } } diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index cae8b14b8..19142ceb0 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -69,18 +69,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { for (int y = rows.Min; y < rows.Max; y++) { - Span vectorSpan = memory.Span; - int length = vectorSpan.Length; - Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length); - PixelOperations.Instance.ToVector4(this.configuration, rowSpan, vectorSpan); + Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); + PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span); - Vector4Utils.Transform(vectorSpan, ref Unsafe.AsRef(this.matrix)); + Vector4Utils.Transform(span, ref Unsafe.AsRef(this.matrix)); - PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, rowSpan); + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan); } } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs index 83d9bd1ef..21a4e1345 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs @@ -95,9 +95,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span amountsSpan = memory.Span; Span colorSpan = this.colors.GetSpan(); for (int y = rows.Min; y < rows.Max; y++) @@ -105,7 +104,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays for (int i = 0; i < this.bounds.Width; i++) { float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); - amountsSpan[i] = (this.blendPercent * (1 - (.95F * (distance / this.maxDistance)))).Clamp(0, 1); + span[i] = (this.blendPercent * (1 - (.95F * (distance / this.maxDistance)))).Clamp(0, 1); } Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width); @@ -115,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays destination, destination, colorSpan, - amountsSpan); + span); } } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs index b36e6b534..3515a2891 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs @@ -103,9 +103,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span amountsSpan = memory.Span; Span colorSpan = this.colors.GetSpan(); for (int y = rows.Min; y < rows.Max; y++) @@ -113,7 +112,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays for (int i = 0; i < this.bounds.Width; i++) { float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); - amountsSpan[i] = (this.blendPercent * (.9F * (distance / this.maxDistance))).Clamp(0, 1); + span[i] = (this.blendPercent * (.9F * (distance / this.maxDistance))).Clamp(0, 1); } Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width); @@ -123,7 +122,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays destination, destination, colorSpan, - amountsSpan); + span); } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs index 2b579541c..0d9055f34 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs @@ -154,13 +154,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span vectorSpan = memory.Span; for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = this.destination.GetPixelRowSpan(y); - PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan, span); ref float ySpanRef = ref this.kernelMap.GetYStartReference(y); ref float xSpanRef = ref this.kernelMap.GetXStartReference(y); @@ -175,12 +174,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ref ySpanRef, ref xSpanRef, this.source.PixelBuffer, - vectorSpan); + span); } PixelOperations.Instance.FromVector4Destructive( this.configuration, - vectorSpan, + span, targetRowSpan); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs index 3969a8c3e..83bc540eb 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs @@ -150,13 +150,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span vectorSpan = memory.Span; for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = this.destination.GetPixelRowSpan(y); - PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan, span); ref float ySpanRef = ref this.kernelMap.GetYStartReference(y); ref float xSpanRef = ref this.kernelMap.GetXStartReference(y); @@ -171,12 +170,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ref ySpanRef, ref xSpanRef, this.source.PixelBuffer, - vectorSpan); + span); } PixelOperations.Instance.FromVector4Destructive( this.configuration, - vectorSpan, + span, targetRowSpan); } } diff --git a/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs index 80ac384fd..3f5e9040d 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Concurrent; using System.Linq; using System.Numerics; using System.Threading; @@ -17,6 +16,8 @@ namespace SixLabors.ImageSharp.Tests.Helpers { public class ParallelRowIteratorTests { + public delegate void RowIntervalAction(RowInterval rows, Span span); + private readonly ITestOutputHelper output; public ParallelRowIteratorTests(ITestOutputHelper output) @@ -140,17 +141,13 @@ namespace SixLabors.ImageSharp.Tests.Helpers var rectangle = new Rectangle(0, minY, 10, maxY - minY); - var bufferHashes = new ConcurrentBag(); - int actualNumberOfSteps = 0; - void RowAction(RowInterval rows, Memory buffer) + void RowAction(RowInterval rows, Span buffer) { Assert.True(rows.Min >= minY); Assert.True(rows.Max <= maxY); - bufferHashes.Add(buffer.GetHashCode()); - int step = rows.Max - rows.Min; int expected = rows.Max < maxY ? expectedStepLength : expectedLastStepLength; @@ -166,9 +163,6 @@ namespace SixLabors.ImageSharp.Tests.Helpers in operation); Assert.Equal(expectedNumberOfSteps, actualNumberOfSteps); - - int numberOfDifferentBuffers = bufferHashes.Distinct().Count(); - Assert.Equal(actualNumberOfSteps, numberOfDifferentBuffers); } [Theory] @@ -191,7 +185,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers int[] expectedData = Enumerable.Repeat(0, minY).Concat(Enumerable.Range(minY, maxY - minY)).ToArray(); var actualData = new int[maxY]; - void RowAction(RowInterval rows, Memory buffer) + void RowAction(RowInterval rows, Span buffer) { for (int y = rows.Min; y < rows.Max; y++) { @@ -283,7 +277,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers int actualNumberOfSteps = 0; - void RowAction(RowInterval rows, Memory buffer) + void RowAction(RowInterval rows, Span buffer) { Assert.True(rows.Min >= 0); Assert.True(rows.Max <= height); @@ -405,7 +399,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var rect = new Rectangle(0, 0, width, height); - void RowAction(RowInterval rows, Memory memory) + void RowAction(RowInterval rows, Span memory) { } @@ -430,13 +424,13 @@ namespace SixLabors.ImageSharp.Tests.Helpers private readonly struct TestRowIntervalOperation : IRowIntervalOperation where TBuffer : unmanaged { - private readonly Action> action; + private readonly RowIntervalAction action; - public TestRowIntervalOperation(Action> action) + public TestRowIntervalOperation(RowIntervalAction action) => this.action = action; - public void Invoke(in RowInterval rows, Memory memory) - => this.action(rows, memory); + public void Invoke(in RowInterval rows, Span span) + => this.action(rows, span); } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index d570b4d05..2ef62ed1c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -724,20 +724,19 @@ namespace SixLabors.ImageSharp.Tests this.source = source; } - public void Invoke(in RowInterval rows, Memory memory) + public void Invoke(in RowInterval rows, Span span) { - Span tempSpan = memory.Span; for (int y = rows.Min; y < rows.Max; y++) { Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left, this.bounds.Width); - PixelOperations.Instance.ToVector4(this.configuration, rowSpan, tempSpan, PixelConversionModifiers.Scale); - for (int i = 0; i < tempSpan.Length; i++) + PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span, PixelConversionModifiers.Scale); + for (int i = 0; i < span.Length; i++) { - ref Vector4 v = ref tempSpan[i]; + ref Vector4 v = ref span[i]; v.W = 1F; } - PixelOperations.Instance.FromVector4Destructive(this.configuration, tempSpan, rowSpan, PixelConversionModifiers.Scale); + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, PixelConversionModifiers.Scale); } } }