diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs
index 095c91bac..50004655f 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs
@@ -40,10 +40,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- using (var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle))
- {
- processor.Apply(source);
- }
+ using var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle);
+
+ processor.Apply(source);
}
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
index e2088084a..cc48ec474 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Numerics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
@@ -59,79 +60,115 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- DenseMatrix matrixY = this.KernelY;
- DenseMatrix matrixX = this.KernelX;
- bool preserveAlpha = this.PreserveAlpha;
+ using Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Width, source.Height);
+
+ source.CopyTo(targetPixels);
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- int startY = interest.Y;
- int endY = interest.Bottom;
- int startX = interest.X;
- int endX = interest.Right;
- int maxY = endY - 1;
- int maxX = endX - 1;
-
- using (Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Width, source.Height))
+
+ ParallelRowIterator.IterateRows(
+ interest,
+ this.Configuration,
+ new RowIntervalAction(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha));
+
+ Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
+ }
+
+ ///
+ /// A implementing the convolution logic for .
+ ///
+ private readonly struct RowIntervalAction : IRowIntervalAction
+ {
+ private readonly Rectangle bounds;
+ private readonly Buffer2D targetPixels;
+ private readonly Buffer2D sourcePixels;
+ private readonly DenseMatrix kernelY;
+ private readonly DenseMatrix kernelX;
+ private readonly Configuration configuration;
+ private readonly bool preserveAlpha;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The target processing bounds for the current instance.
+ /// The target pixel buffer to adjust.
+ /// The source pixels. Cannot be null.
+ /// The vertical kernel operator.
+ /// The horizontal kernel operator.
+ /// The
+ /// Whether the convolution filter is applied to alpha as well as the color channels.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalAction(
+ Rectangle bounds,
+ Buffer2D targetPixels,
+ Buffer2D sourcePixels,
+ DenseMatrix kernelY,
+ DenseMatrix kernelX,
+ Configuration configuration,
+ bool preserveAlpha)
+ {
+ this.bounds = bounds;
+ this.targetPixels = targetPixels;
+ this.sourcePixels = sourcePixels;
+ this.kernelY = kernelY;
+ this.kernelX = kernelX;
+ this.configuration = configuration;
+ this.preserveAlpha = preserveAlpha;
+ }
+
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows, Memory memory)
{
- source.CopyTo(targetPixels);
+ Span vectorSpan = memory.Span;
+ int length = vectorSpan.Length;
+ ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
- var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
- int width = workingRectangle.Width;
+ int maxY = this.bounds.Bottom - 1;
+ int maxX = this.bounds.Right - 1;
- ParallelRowIterator.IterateRows(
- workingRectangle,
- this.Configuration,
- (rows, vectorBuffer) =>
+ 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);
+
+ if (this.preserveAlpha)
+ {
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve2D3(
+ in this.kernelY,
+ in this.kernelX,
+ this.sourcePixels,
+ ref vectorSpanRef,
+ y,
+ x,
+ this.bounds.Y,
+ maxY,
+ this.bounds.X,
+ maxX);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < this.bounds.Width; x++)
{
- Span vectorSpan = vectorBuffer.Span;
- int length = vectorSpan.Length;
- ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
-
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX);
- PixelOperations.Instance.ToVector4(this.Configuration, targetRowSpan.Slice(0, length), vectorSpan);
-
- if (preserveAlpha)
- {
- for (int x = 0; x < width; x++)
- {
- DenseMatrixUtils.Convolve2D3(
- in matrixY,
- in matrixX,
- source.PixelBuffer,
- ref vectorSpanRef,
- y,
- x,
- startY,
- maxY,
- startX,
- maxX);
- }
- }
- else
- {
- for (int x = 0; x < width; x++)
- {
- DenseMatrixUtils.Convolve2D4(
- in matrixY,
- in matrixX,
- source.PixelBuffer,
- ref vectorSpanRef,
- y,
- x,
- startY,
- maxY,
- startX,
- maxX);
- }
- }
-
- PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, targetRowSpan);
- }
- });
-
- Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
+ DenseMatrixUtils.Convolve2D4(
+ in this.kernelY,
+ in this.kernelX,
+ this.sourcePixels,
+ ref vectorSpanRef,
+ y,
+ x,
+ this.bounds.Y,
+ maxY,
+ this.bounds.X,
+ maxX);
+ }
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs
index 31c4fad79..c8c57fc29 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs
@@ -63,10 +63,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- using (var processor = new Convolution2DProcessor(this.Configuration, this.KernelX, this.KernelY, true, this.Source, this.SourceRectangle))
- {
- processor.Apply(source);
- }
+ using var processor = new Convolution2DProcessor(this.Configuration, this.KernelX, this.KernelY, true, this.Source, this.SourceRectangle);
+
+ processor.Apply(source);
}
}
}