From 4a84bffab3437db347471ab9068e826d7061d241 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 6 Feb 2020 19:47:36 +0100 Subject: [PATCH] Refactor ConvolutionProcessor --- .../ConvolutionProcessor{TPixel}.cs | 162 +++++++++++------- 1 file changed, 98 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index 33b80688ca..95e5107c76 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{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; @@ -50,76 +51,109 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source) { - DenseMatrix matrix = this.KernelXY; - bool preserveAlpha = this.PreserveAlpha; + using Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size()); + + 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.Size())) + + ParallelRowIterator.IterateRows( + interest, + this.Configuration, + new RowIntervalAction(interest, targetPixels, source.PixelBuffer, this.KernelXY, 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 kernel; + 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 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 kernel, + Configuration configuration, + bool preserveAlpha) + { + this.bounds = bounds; + this.targetPixels = targetPixels; + this.sourcePixels = sourcePixels; + this.kernel = kernel; + 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.Convolve3( + in this.kernel, + 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.Convolve3( - in matrix, - source.PixelBuffer, - ref vectorSpanRef, - y, - x, - startY, - maxY, - startX, - maxX); - } - } - else - { - for (int x = 0; x < width; x++) - { - DenseMatrixUtils.Convolve4( - in matrix, - source.PixelBuffer, - ref vectorSpanRef, - y, - x, - startY, - maxY, - startX, - maxX); - } - } - - PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, targetRowSpan); - } - }); - - Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); + DenseMatrixUtils.Convolve4( + in this.kernel, + this.sourcePixels, + ref vectorSpanRef, + y, + x, + this.bounds.Y, + maxY, + this.bounds.X, + maxX); + } + } + + PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan); + } } } }