From 8fb9c466d8cd4a886c3912e86194eb90d7a29468 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 01:53:32 +0100 Subject: [PATCH 01/27] Renamed ParallelRowIterator.IterateRows to IterateRowIntervals --- src/ImageSharp/Advanced/ParallelRowIterator.cs | 12 ++++++------ src/ImageSharp/ImageFrame{TPixel}.cs | 2 +- .../BinaryThresholdProcessor{TPixel}.cs | 2 +- .../Convolution/BokehBlurProcessor{TPixel}.cs | 8 ++++---- .../Convolution2DProcessor{TPixel}.cs | 2 +- .../Convolution2PassProcessor{TPixel}.cs | 4 ++-- .../ConvolutionProcessor{TPixel}.cs | 2 +- .../EdgeDetectorCompassProcessor{TPixel}.cs | 2 +- .../Processors/Dithering/OrderedDither.cs | 4 ++-- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 2 +- .../Effects/OilPaintingProcessor{TPixel}.cs | 2 +- ...elRowDelegateProcessor{TPixel,TDelegate}.cs | 2 +- .../Filters/FilterProcessor{TPixel}.cs | 2 +- ...veHistogramEqualizationProcessor{TPixel}.cs | 4 ++-- ...alHistogramEqualizationProcessor{TPixel}.cs | 4 ++-- .../BackgroundColorProcessor{TPixel}.cs | 2 +- .../Overlays/GlowProcessor{TPixel}.cs | 2 +- .../Overlays/VignetteProcessor{TPixel}.cs | 2 +- .../Quantization/FrameQuantizerExtensions.cs | 2 +- .../Quantization/QuantizeProcessor{TPixel}.cs | 2 +- .../Transforms/CropProcessor{TPixel}.cs | 2 +- .../Linear/AffineTransformProcessor{TPixel}.cs | 4 ++-- .../Transforms/Linear/FlipProcessor{TPixel}.cs | 2 +- .../ProjectiveTransformProcessor{TPixel}.cs | 4 ++-- .../Linear/RotateProcessor{TPixel}.cs | 6 +++--- .../Resize/ResizeProcessor{TPixel}.cs | 2 +- .../Helpers/ParallelRowIteratorTests.cs | 18 +++++++++--------- .../TestUtilities/TestImageExtensions.cs | 2 +- 28 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs index 123784c57f..70b48aee94 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs @@ -25,11 +25,11 @@ namespace SixLabors.ImageSharp.Advanced /// The . /// The operation defining the iteration logic on a single . [MethodImpl(InliningOptions.ShortMethod)] - public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation) + public static void IterateRowIntervals(Configuration configuration, Rectangle rectangle, in T operation) where T : struct, IRowIntervalOperation { var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); - IterateRows(rectangle, in parallelSettings, in operation); + IterateRowIntervals(rectangle, in parallelSettings, in operation); } /// @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Advanced /// The . /// The . /// The operation defining the iteration logic on a single . - public static void IterateRows( + public static void IterateRowIntervals( Rectangle rectangle, in ParallelExecutionSettings parallelSettings, in T operation) @@ -84,12 +84,12 @@ namespace SixLabors.ImageSharp.Advanced /// The to get the parallel settings from. /// The . /// The operation defining the iteration logic on a single . - public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation) + public static void IterateRowIntervals(Configuration configuration, Rectangle rectangle, in T operation) where T : struct, IRowIntervalOperation where TBuffer : unmanaged { var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); - IterateRows(rectangle, in parallelSettings, in operation); + IterateRowIntervals(rectangle, in parallelSettings, in operation); } /// @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Advanced /// The . /// The . /// The operation defining the iteration logic on a single . - public static void IterateRows( + public static void IterateRowIntervals( Rectangle rectangle, in ParallelExecutionSettings parallelSettings, in T operation) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 85488c12d4..f5f1e4079c 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -277,7 +277,7 @@ namespace SixLabors.ImageSharp var target = new ImageFrame(configuration, this.Width, this.Height, this.Metadata.DeepClone()); var operation = new RowIntervalOperation(this, target, configuration); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, this.Bounds(), in operation); diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs index ed14a44e95..c3189427fd 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization bool isAlphaOnly = typeof(TPixel) == typeof(A8); var operation = new RowIntervalOperation(interest, source, upper, lower, threshold, isAlphaOnly); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index 36d36223a9..9a910ae29b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { // Preliminary gamma highlight pass var gammaOperation = new ApplyGammaExposureRowIntervalOperation(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, this.SourceRectangle, in gammaOperation); @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution // Apply the inverse gamma exposure pass, and write the final pixel data var operation = new ApplyInverseGammaExposureRowIntervalOperation(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, this.SourceRectangle, in operation); @@ -121,14 +121,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution // Compute the vertical 1D convolution var verticalOperation = new ApplyVerticalConvolutionRowIntervalOperation(sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, sourceRectangle, in verticalOperation); // Compute the horizontal 1D convolutions and accumulate the partial results on the target buffer var horizontalOperation = new ApplyHorizontalConvolutionRowIntervalOperation(sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, sourceRectangle, in horizontalOperation); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index 1c4987c799..219c816178 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var operation = new RowIntervalOperation(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index 33a8ab7d14..833c03308e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -65,14 +65,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution // Horizontal convolution var horizontalOperation = new RowIntervalOperation(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in horizontalOperation); // Vertical convolution var verticalOperation = new RowIntervalOperation(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in verticalOperation); diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index 542ee389b7..fae222714c 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var operation = new RowIntervalOperation(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index c4da1e4b0e..f15acd39a8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } var operation = new RowIntervalOperation(source.PixelBuffer, pass.PixelBuffer, interest); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 69e323bd53..4e5cfefdfd 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering palette, ImageMaths.GetBitsNeededForColorDepth(palette.Span.Length)); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( quantizer.Configuration, bounds, in ditherOperation); @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering scale, ImageMaths.GetBitsNeededForColorDepth(palette.Span.Length)); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, bounds, in ditherOperation); diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index c1ce30cae1..7a26a03a1f 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing } var operation = new RowIntervalOperation(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, workingRect, in operation); diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs index 50c0a22d3b..42bd4de6d6 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects source.CopyTo(targetPixels); var operation = new RowIntervalOperation(this.SourceRectangle, targetPixels, source, this.Configuration, brushSize >> 1, this.definition.Levels); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, this.SourceRectangle, in operation); diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs index 44ade727a7..f94cd50800 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var operation = new RowIntervalOperation(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index 19142ceb06..a677f60277 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var operation = new RowIntervalOperation(interest.X, source, this.definition.Matrix, this.Configuration); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs index eb666a4f18..362a62ff9f 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization } var operation = new RowIntervalOperation(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, new Rectangle(0, 0, sourceWidth, tileYStartPositions.Count), in operation); @@ -522,7 +522,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization this.luminanceLevels, source); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.configuration, new Rectangle(0, 0, this.sourceWidth, this.tileYStartPositions.Count), in operation); diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs index 07fa55c5d0..0567151bc0 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization // Build the histogram of the grayscale levels var grayscaleOperation = new GrayscaleLevelsRowIntervalOperation(interest, histogramBuffer, source, this.LuminanceLevels); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in grayscaleOperation); @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization // Apply the cdf to each pixel of the image var cdfOperation = new CdfApplicationRowIntervalOperation(interest, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( this.Configuration, interest, in cdfOperation); diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs index b796016d1a..3f4174d6ed 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays PixelBlender blender = PixelOperations.Instance.GetPixelBlender(graphicsOptions); var operation = new RowIntervalOperation(configuration, interest, blender, amount, colors, source); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs index 21a4e13452..ff148e8398 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays rowColors.GetSpan().Fill(glowColor); var operation = new RowIntervalOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs index 3515a2891e..ce69de2fd7 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays rowColors.GetSpan().Fill(vignetteColor); var operation = new RowIntervalOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs index 5b49fe9e86..8dd6d984e3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (dither is null) { var operation = new RowIntervalOperation(quantizer, source, output, bounds, palette); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( quantizer.Configuration, bounds, in operation); diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index bfcc26ae25..da191728f7 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization using QuantizedFrame quantized = frameQuantizer.QuantizeFrame(source, interest); var operation = new RowIntervalOperation(this.SourceRectangle, source, quantized); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, interest, in operation); diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs index a80eef2bcd..d72790ea15 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms var operation = new RowIntervalOperation(bounds, source, destination); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( bounds, in parallelSettings, in operation); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs index 72bfa4c0be..26475922fa 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (sampler is NearestNeighborResampler) { var nnOperation = new NNAffineOperation(source, destination, matrix); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, destination.Bounds(), in nnOperation); @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms radialExtents, maxSourceExtents); - ParallelRowIterator.IterateRows, Vector4>( + ParallelRowIterator.IterateRowIntervals, Vector4>( configuration, destination.Bounds(), in operation); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs index 877fa074e9..f5fde8a229 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private void FlipY(ImageFrame source, Configuration configuration) { var operation = new RowIntervalOperation(source); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, source.Bounds(), in operation); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs index b3315fa554..07178117a4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (sampler is NearestNeighborResampler) { var nnOperation = new NNProjectiveOperation(source, destination, matrix); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, destination.Bounds(), in nnOperation); @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms radialExtents, maxSourceExtents); - ParallelRowIterator.IterateRows, Vector4>( + ParallelRowIterator.IterateRowIntervals, Vector4>( configuration, destination.Bounds(), in operation); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs index 198e142d07..d6755e8ba2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private void Rotate180(ImageFrame source, ImageFrame destination, Configuration configuration) { var operation = new Rotate180RowIntervalOperation(source.Width, source.Height, source, destination); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, source.Bounds(), in operation); @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private void Rotate270(ImageFrame source, ImageFrame destination, Configuration configuration) { var operation = new Rotate270RowIntervalOperation(destination.Bounds(), source.Width, source.Height, source, destination); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, source.Bounds(), in operation); @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private void Rotate90(ImageFrame source, ImageFrame destination, Configuration configuration) { var operation = new Rotate90RowIntervalOperation(destination.Bounds(), source.Width, source.Height, source, destination); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, source.Bounds(), in operation); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 1a6b8030db..c0dc886885 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -152,7 +152,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms source, destination); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, interest, in operation); diff --git a/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs index 332a141e9d..08d64a738d 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( rectangle, in parallelSettings, in operation); @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( rectangle, in parallelSettings, in operation); @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); - ParallelRowIterator.IterateRows, Vector4>( + ParallelRowIterator.IterateRowIntervals, Vector4>( rectangle, in parallelSettings, in operation); @@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); - ParallelRowIterator.IterateRows, Vector4>( + ParallelRowIterator.IterateRowIntervals, Vector4>( rectangle, in parallelSettings, in operation); @@ -249,7 +249,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( rectangle, in parallelSettings, in operation); @@ -291,7 +291,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); - ParallelRowIterator.IterateRows, Vector4>( + ParallelRowIterator.IterateRowIntervals, Vector4>( rectangle, in parallelSettings, in operation); @@ -355,7 +355,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( rect, settings, in operation); @@ -383,7 +383,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); ArgumentOutOfRangeException ex = Assert.Throws( - () => ParallelRowIterator.IterateRows(rect, in parallelSettings, in operation)); + () => ParallelRowIterator.IterateRowIntervals(rect, in parallelSettings, in operation)); Assert.Contains(width <= 0 ? "Width" : "Height", ex.Message); } @@ -406,7 +406,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var operation = new TestRowIntervalOperation(RowAction); ArgumentOutOfRangeException ex = Assert.Throws( - () => ParallelRowIterator.IterateRows, Rgba32>(rect, in parallelSettings, in operation)); + () => ParallelRowIterator.IterateRowIntervals, Rgba32>(rect, in parallelSettings, in operation)); Assert.Contains(width <= 0 ? "Width" : "Height", ex.Message); } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 502a5bf46d..4605165684 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -713,7 +713,7 @@ namespace SixLabors.ImageSharp.Tests var operation = new RowOperation(configuration, sourceRectangle, source); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRowIntervals( configuration, sourceRectangle, in operation); From 0d90e57e218b1360cfbc85a4ccea8c2035fbb230 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 12:46:45 +0100 Subject: [PATCH 02/27] Removed unnecessary using directives --- src/ImageSharp/Advanced/IRowIntervalOperation.cs | 2 -- src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/ImageSharp/Advanced/IRowIntervalOperation.cs b/src/ImageSharp/Advanced/IRowIntervalOperation.cs index 3e1b086218..980ed91a78 100644 --- a/src/ImageSharp/Advanced/IRowIntervalOperation.cs +++ b/src/ImageSharp/Advanced/IRowIntervalOperation.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Advanced diff --git a/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs b/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs index c18842a92c..47fcf253eb 100644 --- a/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs +++ b/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; -using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Advanced From 872015fe5585bfd7b2b948d8d69acb474da977fa Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 12:46:58 +0100 Subject: [PATCH 03/27] Added single row value delegate interfaces --- src/ImageSharp/Advanced/IRowAction.cs | 17 ++++++++++++++ .../Advanced/IRowAction{TBuffer}.cs | 22 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/ImageSharp/Advanced/IRowAction.cs create mode 100644 src/ImageSharp/Advanced/IRowAction{TBuffer}.cs diff --git a/src/ImageSharp/Advanced/IRowAction.cs b/src/ImageSharp/Advanced/IRowAction.cs new file mode 100644 index 0000000000..b541160af9 --- /dev/null +++ b/src/ImageSharp/Advanced/IRowAction.cs @@ -0,0 +1,17 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Defines the contract for an action that operates on a row. + /// + public interface IRowAction + { + /// + /// Invokes the method passing the row y coordinate. + /// + /// The row y coordinate. + void Invoke(int y); + } +} diff --git a/src/ImageSharp/Advanced/IRowAction{TBuffer}.cs b/src/ImageSharp/Advanced/IRowAction{TBuffer}.cs new file mode 100644 index 0000000000..aff043aa2a --- /dev/null +++ b/src/ImageSharp/Advanced/IRowAction{TBuffer}.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Defines the contract for an action that operates on a row with a temporary buffer. + /// + /// The type of buffer elements. + public interface IRowAction + where TBuffer : unmanaged + { + /// + /// Invokes the method passing the row and a buffer. + /// + /// The row y coordinate. + /// The contiguous region of memory. + void Invoke(int y, Span span); + } +} From ec8942605481b87d95c89299fb104b2751f919c1 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 12:47:07 +0100 Subject: [PATCH 04/27] Added single row value delegate wrappers --- .../Advanced/ParallelRowIterator.Wrappers.cs | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs index adbad0d662..bd30d4ff4f 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs @@ -38,6 +38,81 @@ namespace SixLabors.ImageSharp.Advanced } } + private readonly struct WrappingRowAction + where T : struct, IRowAction + { + private readonly IterationParameters info; + private readonly T action; + + [MethodImpl(InliningOptions.ShortMethod)] + public WrappingRowAction(in IterationParameters info, in T 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); + + for (int y = yMin; y < yMax; y++) + { + // Skip the safety copy when invoking a potentially impure method on a readonly field + Unsafe.AsRef(this.action).Invoke(y); + } + } + } + + private readonly struct WrappingRowAction + where T : struct, IRowAction + where TBuffer : unmanaged + { + private readonly IterationParameters info; + private readonly MemoryAllocator allocator; + private readonly T action; + + [MethodImpl(InliningOptions.ShortMethod)] + public WrappingRowAction( + in IterationParameters info, + MemoryAllocator allocator, + in T 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); + + using IMemoryOwner buffer = this.allocator.Allocate(this.info.MaxX); + + Span span = buffer.Memory.Span; + + for (int y = yMin; y < yMax; y++) + { + Unsafe.AsRef(this.action).Invoke(y, span); + } + } + } + private readonly struct RowIntervalOperationWrapper where T : struct, IRowIntervalOperation { From 9db12514726c40700eb4f3e720c69cfe95c8048e Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 12:54:40 +0100 Subject: [PATCH 05/27] Renamed new APIs --- .../Advanced/{IRowAction.cs => IRowOperation.cs} | 2 +- ...ction{TBuffer}.cs => IRowOperation{TBuffer}.cs} | 2 +- .../Advanced/ParallelRowIterator.Wrappers.cs | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) rename src/ImageSharp/Advanced/{IRowAction.cs => IRowOperation.cs} (92%) rename src/ImageSharp/Advanced/{IRowAction{TBuffer}.cs => IRowOperation{TBuffer}.cs} (94%) diff --git a/src/ImageSharp/Advanced/IRowAction.cs b/src/ImageSharp/Advanced/IRowOperation.cs similarity index 92% rename from src/ImageSharp/Advanced/IRowAction.cs rename to src/ImageSharp/Advanced/IRowOperation.cs index b541160af9..0a6065e4b1 100644 --- a/src/ImageSharp/Advanced/IRowAction.cs +++ b/src/ImageSharp/Advanced/IRowOperation.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Advanced /// /// Defines the contract for an action that operates on a row. /// - public interface IRowAction + public interface IRowOperation { /// /// Invokes the method passing the row y coordinate. diff --git a/src/ImageSharp/Advanced/IRowAction{TBuffer}.cs b/src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs similarity index 94% rename from src/ImageSharp/Advanced/IRowAction{TBuffer}.cs rename to src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs index aff043aa2a..7a13930fad 100644 --- a/src/ImageSharp/Advanced/IRowAction{TBuffer}.cs +++ b/src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Advanced /// Defines the contract for an action that operates on a row with a temporary buffer. /// /// The type of buffer elements. - public interface IRowAction + public interface IRowOperation where TBuffer : unmanaged { /// diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs index bd30d4ff4f..7c3861fdf5 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs @@ -38,14 +38,14 @@ namespace SixLabors.ImageSharp.Advanced } } - private readonly struct WrappingRowAction - where T : struct, IRowAction + private readonly struct RowOperationWrapper + where T : struct, IRowOperation { private readonly IterationParameters info; private readonly T action; [MethodImpl(InliningOptions.ShortMethod)] - public WrappingRowAction(in IterationParameters info, in T action) + public RowOperationWrapper(in IterationParameters info, in T action) { this.info = info; this.action = action; @@ -71,8 +71,8 @@ namespace SixLabors.ImageSharp.Advanced } } - private readonly struct WrappingRowAction - where T : struct, IRowAction + private readonly struct RowOperationWrapper + where T : struct, IRowOperation where TBuffer : unmanaged { private readonly IterationParameters info; @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Advanced private readonly T action; [MethodImpl(InliningOptions.ShortMethod)] - public WrappingRowAction( + public RowOperationWrapper( in IterationParameters info, MemoryAllocator allocator, in T action) @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Advanced int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); - using IMemoryOwner buffer = this.allocator.Allocate(this.info.MaxX); + using IMemoryOwner buffer = this.allocator.Allocate(this.info.Width); Span span = buffer.Memory.Span; From d922602a26fa139b97dee86681b7dfcec188df68 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 12:54:51 +0100 Subject: [PATCH 06/27] Introduced single row parallel helpers --- .../Advanced/ParallelRowIterator.cs | 138 +++++++++++++++++- 1 file changed, 134 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs index 70b48aee94..86442ede73 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs @@ -17,6 +17,137 @@ namespace SixLabors.ImageSharp.Advanced /// public static partial class ParallelRowIterator { + /// + /// Iterate through the rows of a rectangle in optimized batches. + /// + /// The type of row operation to perform. + /// The to get the parallel settings from. + /// The . + /// The operation defining the iteration logic on a single row. + [MethodImpl(InliningOptions.ShortMethod)] + public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation) + where T : struct, IRowOperation + { + var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); + IterateRows(rectangle, in parallelSettings, in operation); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches. + /// + /// The type of row operation to perform. + /// The . + /// The . + /// The operation defining the iteration logic on a single row. + public static void IterateRows( + Rectangle rectangle, + in ParallelExecutionSettings parallelSettings, + in T operation) + where T : struct, IRowOperation + { + ValidateRectangle(rectangle); + + int top = rectangle.Top; + int bottom = rectangle.Bottom; + int width = rectangle.Width; + int height = rectangle.Height; + + int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask); + int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); + + // Avoid TPL overhead in this trivial case: + if (numOfSteps == 1) + { + for (int y = top; y < bottom; y++) + { + Unsafe.AsRef(operation).Invoke(y); + } + + return; + } + + int verticalStep = DivideCeil(rectangle.Height, numOfSteps); + var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; + var info = new IterationParameters(top, bottom, verticalStep); + var wrappingOperation = new RowOperationWrapper(in info, in operation); + + Parallel.For( + 0, + numOfSteps, + parallelOptions, + wrappingOperation.Invoke); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches. + /// instantiating a temporary buffer for each invocation. + /// + /// The type of row operation to perform. + /// The type of buffer elements. + /// The to get the parallel settings from. + /// The . + /// The operation defining the iteration logic on a single row. + public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation) + where T : struct, IRowOperation + where TBuffer : unmanaged + { + var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); + IterateRows(rectangle, in parallelSettings, in operation); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches. + /// instantiating a temporary buffer for each invocation. + /// + /// The type of row operation to perform. + /// The type of buffer elements. + /// The . + /// The . + /// The operation defining the iteration logic on a single row. + public static void IterateRows( + Rectangle rectangle, + in ParallelExecutionSettings parallelSettings, + in T operation) + where T : struct, IRowOperation + where TBuffer : unmanaged + { + ValidateRectangle(rectangle); + + int top = rectangle.Top; + int bottom = rectangle.Bottom; + int width = rectangle.Width; + int height = rectangle.Height; + + int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask); + int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); + MemoryAllocator allocator = parallelSettings.MemoryAllocator; + + // Avoid TPL overhead in this trivial case: + if (numOfSteps == 1) + { + using IMemoryOwner buffer = allocator.Allocate(width); + Span span = buffer.Memory.Span; + + for (int y = top; y < bottom; y++) + { + Unsafe.AsRef(operation).Invoke(y, span); + } + + return; + } + + int verticalStep = DivideCeil(height, numOfSteps); + var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; + var info = new IterationParameters(top, bottom, verticalStep, width); + var wrappingOperation = new RowOperationWrapper(in info, allocator, in operation); + + Parallel.For( + 0, + numOfSteps, + parallelOptions, + wrappingOperation.Invoke); + } + /// /// Iterate through the rows of a rectangle in optimized batches defined by -s. /// @@ -123,10 +254,9 @@ namespace SixLabors.ImageSharp.Advanced if (numOfSteps == 1) { var rows = new RowInterval(top, bottom); - using (IMemoryOwner buffer = allocator.Allocate(width)) - { - Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); - } + using IMemoryOwner buffer = allocator.Allocate(width); + + Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); return; } From 086040cd815d3929f333c4cd135d5b77cb68e16f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 13:00:17 +0100 Subject: [PATCH 07/27] Removed IterationParameters type --- .../Advanced/ParallelRowIterator.Wrappers.cs | 107 ++++++++++-------- .../Advanced/ParallelRowIterator.cs | 12 +- 2 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs index 7c3861fdf5..3f0f77ca39 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs @@ -17,51 +17,38 @@ namespace SixLabors.ImageSharp.Advanced /// public static partial class ParallelRowIterator { - private readonly struct IterationParameters - { - public readonly int MinY; - public readonly int MaxY; - public readonly int StepY; - public readonly int Width; - - public IterationParameters(int minY, int maxY, int stepY) - : this(minY, maxY, stepY, 0) - { - } - - public IterationParameters(int minY, int maxY, int stepY, int width) - { - this.MinY = minY; - this.MaxY = maxY; - this.StepY = stepY; - this.Width = width; - } - } - private readonly struct RowOperationWrapper where T : struct, IRowOperation { - private readonly IterationParameters info; + private readonly int minY; + private readonly int maxY; + private readonly int stepY; private readonly T action; [MethodImpl(InliningOptions.ShortMethod)] - public RowOperationWrapper(in IterationParameters info, in T action) + public RowOperationWrapper( + int minY, + int maxY, + int stepY, + in T action) { - this.info = info; + this.minY = minY; + this.maxY = maxY; + this.stepY = stepY; this.action = action; } [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(int i) { - int yMin = this.info.MinY + (i * this.info.StepY); + int yMin = this.minY + (i * this.stepY); - if (yMin >= this.info.MaxY) + if (yMin >= this.maxY) { return; } - int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); + int yMax = Math.Min(yMin + this.stepY, this.maxY); for (int y = yMin; y < yMax; y++) { @@ -75,17 +62,26 @@ namespace SixLabors.ImageSharp.Advanced where T : struct, IRowOperation where TBuffer : unmanaged { - private readonly IterationParameters info; + private readonly int minY; + private readonly int maxY; + private readonly int stepY; + private readonly int width; private readonly MemoryAllocator allocator; private readonly T action; [MethodImpl(InliningOptions.ShortMethod)] public RowOperationWrapper( - in IterationParameters info, + int minY, + int maxY, + int stepY, + int width, MemoryAllocator allocator, in T action) { - this.info = info; + this.minY = minY; + this.maxY = maxY; + this.stepY = stepY; + this.width = width; this.allocator = allocator; this.action = action; } @@ -93,16 +89,16 @@ namespace SixLabors.ImageSharp.Advanced [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(int i) { - int yMin = this.info.MinY + (i * this.info.StepY); + int yMin = this.minY + (i * this.stepY); - if (yMin >= this.info.MaxY) + if (yMin >= this.maxY) { return; } - int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); + int yMax = Math.Min(yMin + this.stepY, this.maxY); - using IMemoryOwner buffer = this.allocator.Allocate(this.info.Width); + using IMemoryOwner buffer = this.allocator.Allocate(this.width); Span span = buffer.Memory.Span; @@ -116,27 +112,35 @@ namespace SixLabors.ImageSharp.Advanced private readonly struct RowIntervalOperationWrapper where T : struct, IRowIntervalOperation { - private readonly IterationParameters info; + private readonly int minY; + private readonly int maxY; + private readonly int stepY; private readonly T operation; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperationWrapper(in IterationParameters info, in T operation) + public RowIntervalOperationWrapper( + int minY, + int maxY, + int stepY, + in T operation) { - this.info = info; + this.minY = minY; + this.maxY = maxY; + this.stepY = stepY; this.operation = operation; } [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(int i) { - int yMin = this.info.MinY + (i * this.info.StepY); + int yMin = this.minY + (i * this.stepY); - if (yMin >= this.info.MaxY) + if (yMin >= this.maxY) { return; } - int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); + int yMax = Math.Min(yMin + this.stepY, this.maxY); var rows = new RowInterval(yMin, yMax); // Skip the safety copy when invoking a potentially impure method on a readonly field @@ -148,17 +152,26 @@ namespace SixLabors.ImageSharp.Advanced where T : struct, IRowIntervalOperation where TBuffer : unmanaged { - private readonly IterationParameters info; + private readonly int minY; + private readonly int maxY; + private readonly int stepY; + private readonly int width; private readonly MemoryAllocator allocator; private readonly T operation; [MethodImpl(InliningOptions.ShortMethod)] public RowIntervalOperationWrapper( - in IterationParameters info, + int minY, + int maxY, + int stepY, + int width, MemoryAllocator allocator, in T operation) { - this.info = info; + this.minY = minY; + this.maxY = maxY; + this.stepY = stepY; + this.width = width; this.allocator = allocator; this.operation = operation; } @@ -166,17 +179,17 @@ namespace SixLabors.ImageSharp.Advanced [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(int i) { - int yMin = this.info.MinY + (i * this.info.StepY); + int yMin = this.minY + (i * this.stepY); - if (yMin >= this.info.MaxY) + if (yMin >= this.maxY) { return; } - int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); + int yMax = Math.Min(yMin + this.stepY, this.maxY); var rows = new RowInterval(yMin, yMax); - using IMemoryOwner buffer = this.allocator.Allocate(this.info.Width); + using IMemoryOwner buffer = this.allocator.Allocate(this.width); Unsafe.AsRef(in this.operation).Invoke(in rows, buffer.Memory.Span); } diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs index 86442ede73..fb85de9863 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs @@ -68,8 +68,7 @@ namespace SixLabors.ImageSharp.Advanced int verticalStep = DivideCeil(rectangle.Height, numOfSteps); var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; - var info = new IterationParameters(top, bottom, verticalStep); - var wrappingOperation = new RowOperationWrapper(in info, in operation); + var wrappingOperation = new RowOperationWrapper(top, bottom, verticalStep, in operation); Parallel.For( 0, @@ -138,8 +137,7 @@ namespace SixLabors.ImageSharp.Advanced int verticalStep = DivideCeil(height, numOfSteps); var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; - var info = new IterationParameters(top, bottom, verticalStep, width); - var wrappingOperation = new RowOperationWrapper(in info, allocator, in operation); + var wrappingOperation = new RowOperationWrapper(top, bottom, verticalStep, width, allocator, in operation); Parallel.For( 0, @@ -196,8 +194,7 @@ namespace SixLabors.ImageSharp.Advanced int verticalStep = DivideCeil(rectangle.Height, numOfSteps); var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; - var info = new IterationParameters(top, bottom, verticalStep); - var wrappingOperation = new RowIntervalOperationWrapper(in info, in operation); + var wrappingOperation = new RowIntervalOperationWrapper(top, bottom, verticalStep, in operation); Parallel.For( 0, @@ -263,8 +260,7 @@ namespace SixLabors.ImageSharp.Advanced int verticalStep = DivideCeil(height, numOfSteps); var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; - var info = new IterationParameters(top, bottom, verticalStep, width); - var wrappingOperation = new RowIntervalOperationWrapper(in info, allocator, in operation); + var wrappingOperation = new RowIntervalOperationWrapper(top, bottom, verticalStep, width, allocator, in operation); Parallel.For( 0, From 9803663d7399b2155e1467be68f4eb7db4172b75 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 13:22:16 +0100 Subject: [PATCH 08/27] Refactored BinaryThresholdProcessor --- .../BinaryThresholdProcessor{TPixel}.cs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs index c3189427fd..c46137e765 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Binarization @@ -44,8 +43,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); bool isAlphaOnly = typeof(TPixel) == typeof(A8); - var operation = new RowIntervalOperation(interest, source, upper, lower, threshold, isAlphaOnly); - ParallelRowIterator.IterateRowIntervals( + var operation = new RowOperation(interest, source, upper, lower, threshold, isAlphaOnly); + ParallelRowIterator.IterateRows( configuration, interest, in operation); @@ -54,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// /// A implementing the clone logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly ImageFrame source; private readonly TPixel upper; @@ -65,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization private readonly bool isAlphaOnly; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( Rectangle bounds, ImageFrame source, TPixel upper, @@ -84,22 +83,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { Rgba32 rgba = default; - for (int y = rows.Min; y < rows.Max; y++) - { - Span row = this.source.GetPixelRowSpan(y); + Span row = this.source.GetPixelRowSpan(y); - for (int x = this.minX; x < this.maxX; x++) - { - ref TPixel color = ref row[x]; - color.ToRgba32(ref rgba); + for (int x = this.minX; x < this.maxX; x++) + { + ref TPixel color = ref row[x]; + color.ToRgba32(ref rgba); - // Convert to grayscale using ITU-R Recommendation BT.709 if required - byte luminance = this.isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); - color = luminance >= this.threshold ? this.upper : this.lower; - } + // Convert to grayscale using ITU-R Recommendation BT.709 if required + byte luminance = this.isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); + color = luminance >= this.threshold ? this.upper : this.lower; } } } From b6748f93f7db0379d19da558fad3fc27ee8974b2 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 13:22:56 +0100 Subject: [PATCH 09/27] Micro-optimization in BinaryThresholdProcessor --- .../Binarization/BinaryThresholdProcessor{TPixel}.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs index c46137e765..7a53905647 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; @@ -87,10 +88,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization { Rgba32 rgba = default; Span row = this.source.GetPixelRowSpan(y); + ref TPixel rowRef = ref MemoryMarshal.GetReference(row); for (int x = this.minX; x < this.maxX; x++) { - ref TPixel color = ref row[x]; + ref TPixel color = ref Unsafe.Add(ref rowRef, x); color.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required From 36f354d07ab222fc553e89879df9d47ded5ebc1a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 13:23:13 +0100 Subject: [PATCH 10/27] Refactored BokehBlurProcessor --- .../Convolution/BokehBlurProcessor{TPixel}.cs | 114 ++++++++---------- 1 file changed, 51 insertions(+), 63 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index 9a910ae29b..e60063ee0f 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution protected override void OnFrameApply(ImageFrame source) { // Preliminary gamma highlight pass - var gammaOperation = new ApplyGammaExposureRowIntervalOperation(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma); - ParallelRowIterator.IterateRowIntervals( + var gammaOperation = new ApplyGammaExposureRowOperation(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma); + ParallelRowIterator.IterateRows( this.Configuration, this.SourceRectangle, in gammaOperation); @@ -87,8 +87,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution float inverseGamma = 1 / this.gamma; // Apply the inverse gamma exposure pass, and write the final pixel data - var operation = new ApplyInverseGammaExposureRowIntervalOperation(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma); - ParallelRowIterator.IterateRowIntervals( + var operation = new ApplyInverseGammaExposureRowOperation(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma); + ParallelRowIterator.IterateRows( this.Configuration, this.SourceRectangle, in operation); @@ -120,15 +120,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Vector4 parameters = Unsafe.Add(ref paramsRef, i); // Compute the vertical 1D convolution - var verticalOperation = new ApplyVerticalConvolutionRowIntervalOperation(sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel); - ParallelRowIterator.IterateRowIntervals( + var verticalOperation = new ApplyVerticalConvolutionRowOperation(sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel); + ParallelRowIterator.IterateRows( configuration, sourceRectangle, in verticalOperation); // Compute the horizontal 1D convolutions and accumulate the partial results on the target buffer - var horizontalOperation = new ApplyHorizontalConvolutionRowIntervalOperation(sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W); - ParallelRowIterator.IterateRowIntervals( + var horizontalOperation = new ApplyHorizontalConvolutionRowOperation(sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W); + ParallelRowIterator.IterateRows( configuration, sourceRectangle, in horizontalOperation); @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the vertical convolution logic for . /// - private readonly struct ApplyVerticalConvolutionRowIntervalOperation : IRowIntervalOperation + private readonly struct ApplyVerticalConvolutionRowOperation : IRowOperation { private readonly Rectangle bounds; private readonly Buffer2D targetValues; @@ -148,7 +148,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly int maxX; [MethodImpl(InliningOptions.ShortMethod)] - public ApplyVerticalConvolutionRowIntervalOperation( + public ApplyVerticalConvolutionRowOperation( Rectangle bounds, Buffer2D targetValues, Buffer2D sourcePixels, @@ -164,16 +164,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); - for (int x = 0; x < this.bounds.Width; x++) - { - Buffer2DUtils.Convolve4(this.kernel, this.sourcePixels, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX); - } + for (int x = 0; x < this.bounds.Width; x++) + { + Buffer2DUtils.Convolve4(this.kernel, this.sourcePixels, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX); } } } @@ -181,7 +178,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the horizontal convolution logic for . /// - private readonly struct ApplyHorizontalConvolutionRowIntervalOperation : IRowIntervalOperation + private readonly struct ApplyHorizontalConvolutionRowOperation : IRowOperation { private readonly Rectangle bounds; private readonly Buffer2D targetValues; @@ -193,7 +190,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly int maxX; [MethodImpl(InliningOptions.ShortMethod)] - public ApplyHorizontalConvolutionRowIntervalOperation( + public ApplyHorizontalConvolutionRowOperation( Rectangle bounds, Buffer2D targetValues, Buffer2D sourceValues, @@ -213,16 +210,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); - for (int x = 0; x < this.bounds.Width; x++) - { - Buffer2DUtils.Convolve4AndAccumulatePartials(this.kernel, this.sourceValues, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX, this.z, this.w); - } + for (int x = 0; x < this.bounds.Width; x++) + { + Buffer2DUtils.Convolve4AndAccumulatePartials(this.kernel, this.sourceValues, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX, this.z, this.w); } } } @@ -230,7 +224,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the gamma exposure logic for . /// - private readonly struct ApplyGammaExposureRowIntervalOperation : IRowIntervalOperation + private readonly struct ApplyGammaExposureRowOperation : IRowOperation { private readonly Rectangle bounds; private readonly Buffer2D targetPixels; @@ -238,7 +232,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly float gamma; [MethodImpl(InliningOptions.ShortMethod)] - public ApplyGammaExposureRowIntervalOperation( + public ApplyGammaExposureRowOperation( Rectangle bounds, Buffer2D targetPixels, Configuration configuration, @@ -252,31 +246,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span 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, span.Length), span, PixelConversionModifiers.Premultiply); + ref Vector4 baseRef = ref MemoryMarshal.GetReference(span); + + for (int x = 0; x < this.bounds.Width; x++) { - Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - 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++) - { - ref Vector4 v = ref Unsafe.Add(ref baseRef, x); - v.X = MathF.Pow(v.X, this.gamma); - v.Y = MathF.Pow(v.Y, this.gamma); - v.Z = MathF.Pow(v.Z, this.gamma); - } - - PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); + ref Vector4 v = ref Unsafe.Add(ref baseRef, x); + v.X = MathF.Pow(v.X, this.gamma); + v.Y = MathF.Pow(v.Y, this.gamma); + v.Z = MathF.Pow(v.Z, this.gamma); } + + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } } /// /// A implementing the inverse gamma exposure logic for . /// - private readonly struct ApplyInverseGammaExposureRowIntervalOperation : IRowIntervalOperation + private readonly struct ApplyInverseGammaExposureRowOperation : IRowOperation { private readonly Rectangle bounds; private readonly Buffer2D targetPixels; @@ -285,7 +276,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly float inverseGamma; [MethodImpl(InliningOptions.ShortMethod)] - public ApplyInverseGammaExposureRowIntervalOperation( + public ApplyInverseGammaExposureRowOperation( Rectangle bounds, Buffer2D targetPixels, Buffer2D sourceValues, @@ -301,28 +292,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { Vector4 low = Vector4.Zero; var high = new Vector4(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - for (int y = rows.Min; y < rows.Max; y++) + Span targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); + Span sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X); + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan); + + for (int x = 0; x < this.bounds.Width; x++) { - Span targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - Span sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan); - - for (int x = 0; x < this.bounds.Width; x++) - { - ref Vector4 v = ref Unsafe.Add(ref sourceRef, x); - var clamp = Vector4.Clamp(v, low, high); - v.X = MathF.Pow(clamp.X, this.inverseGamma); - v.Y = MathF.Pow(clamp.Y, this.inverseGamma); - v.Z = MathF.Pow(clamp.Z, this.inverseGamma); - } - - PixelOperations.Instance.FromVector4Destructive(this.configuration, sourceRowSpan.Slice(0, this.bounds.Width), targetPixelSpan, PixelConversionModifiers.Premultiply); + ref Vector4 v = ref Unsafe.Add(ref sourceRef, x); + var clamp = Vector4.Clamp(v, low, high); + v.X = MathF.Pow(clamp.X, this.inverseGamma); + v.Y = MathF.Pow(clamp.Y, this.inverseGamma); + v.Z = MathF.Pow(clamp.Z, this.inverseGamma); } + + PixelOperations.Instance.FromVector4Destructive(this.configuration, sourceRowSpan.Slice(0, this.bounds.Width), targetPixelSpan, PixelConversionModifiers.Premultiply); } } } From b90f087c7d2981f7b6c2717ebb0c96ed119c659f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 13:23:27 +0100 Subject: [PATCH 11/27] Refactored Convolution2DProcessor --- .../Convolution2DProcessor{TPixel}.cs | 78 +++++++++---------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index 219c816178..bd0c917ddc 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -65,9 +65,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution source.CopyTo(targetPixels); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - var operation = new RowIntervalOperation(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha); + var operation = new RowOperation(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( this.Configuration, interest, in operation); @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the convolution logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly Rectangle bounds; private readonly int maxY; @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly bool preserveAlpha; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( Rectangle bounds, Buffer2D targetPixels, Buffer2D sourcePixels, @@ -113,52 +113,48 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { ref Vector4 spanRef = ref MemoryMarshal.GetReference(span); + Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); - for (int y = rows.Min; y < rows.Max; y++) + if (this.preserveAlpha) { - Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); - - if (this.preserveAlpha) + for (int x = 0; x < this.bounds.Width; x++) { - for (int x = 0; x < this.bounds.Width; x++) - { - DenseMatrixUtils.Convolve2D3( - in this.kernelY, - in this.kernelX, - this.sourcePixels, - ref spanRef, - y, - x, - this.bounds.Y, - this.maxY, - this.bounds.X, - this.maxX); - } + DenseMatrixUtils.Convolve2D3( + in this.kernelY, + in this.kernelX, + this.sourcePixels, + ref spanRef, + y, + x, + this.bounds.Y, + this.maxY, + this.bounds.X, + this.maxX); } - else + } + else + { + for (int x = 0; x < this.bounds.Width; x++) { - for (int x = 0; x < this.bounds.Width; x++) - { - DenseMatrixUtils.Convolve2D4( - in this.kernelY, - in this.kernelX, - this.sourcePixels, - ref spanRef, - y, - x, - this.bounds.Y, - this.maxY, - this.bounds.X, - this.maxX); - } + DenseMatrixUtils.Convolve2D4( + in this.kernelY, + in this.kernelX, + this.sourcePixels, + ref spanRef, + y, + x, + this.bounds.Y, + this.maxY, + this.bounds.X, + this.maxX); } - - PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } + + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } } } From 05bd0312a864edbcf9bc44ec6416cea516cbddc3 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 13:23:38 +0100 Subject: [PATCH 12/27] Refactored Convolution2PassProcessor --- .../Convolution2PassProcessor{TPixel}.cs | 79 +++++++++---------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index 833c03308e..38945dd208 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -64,15 +64,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); // Horizontal convolution - var horizontalOperation = new RowIntervalOperation(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha); - ParallelRowIterator.IterateRowIntervals( + var horizontalOperation = new RowOperation(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha); + ParallelRowIterator.IterateRows( this.Configuration, interest, in horizontalOperation); // Vertical convolution - var verticalOperation = new RowIntervalOperation(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha); - ParallelRowIterator.IterateRowIntervals( + var verticalOperation = new RowOperation(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha); + ParallelRowIterator.IterateRows( this.Configuration, interest, in verticalOperation); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the convolution logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly Rectangle bounds; private readonly Buffer2D targetPixels; @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly bool preserveAlpha; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( Rectangle bounds, Buffer2D targetPixels, Buffer2D sourcePixels, @@ -109,53 +109,50 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { ref Vector4 spanRef = ref MemoryMarshal.GetReference(span); int maxY = this.bounds.Bottom - 1; int maxX = this.bounds.Right - 1; - 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, span.Length), span); + Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); - if (this.preserveAlpha) + if (this.preserveAlpha) + { + for (int x = 0; x < this.bounds.Width; x++) { - for (int x = 0; x < this.bounds.Width; x++) - { - DenseMatrixUtils.Convolve3( - in this.kernel, - this.sourcePixels, - ref spanRef, - y, - x, - this.bounds.Y, - maxY, - this.bounds.X, - maxX); - } + DenseMatrixUtils.Convolve3( + in this.kernel, + this.sourcePixels, + ref spanRef, + y, + x, + this.bounds.Y, + maxY, + this.bounds.X, + maxX); } - else + } + else + { + for (int x = 0; x < this.bounds.Width; x++) { - for (int x = 0; x < this.bounds.Width; x++) - { - DenseMatrixUtils.Convolve4( - in this.kernel, - this.sourcePixels, - ref spanRef, - y, - x, - this.bounds.Y, - maxY, - this.bounds.X, - maxX); - } + DenseMatrixUtils.Convolve4( + in this.kernel, + this.sourcePixels, + ref spanRef, + y, + x, + this.bounds.Y, + maxY, + this.bounds.X, + maxX); } - - PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } + + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } } } From 577d59790af8cb5f70563335659124f125b0766c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 13:23:48 +0100 Subject: [PATCH 13/27] Refactored ConvolutionProcessor --- .../ConvolutionProcessor{TPixel}.cs | 75 +++++++++---------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index fae222714c..c529641d24 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -56,8 +56,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution source.CopyTo(targetPixels); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - var operation = new RowIntervalOperation(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha); - ParallelRowIterator.IterateRowIntervals( + var operation = new RowOperation(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha); + ParallelRowIterator.IterateRows( this.Configuration, interest, in operation); @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the convolution logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly Rectangle bounds; private readonly int maxY; @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly bool preserveAlpha; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( Rectangle bounds, Buffer2D targetPixels, Buffer2D sourcePixels, @@ -100,50 +100,47 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { 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, span.Length), span); + Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); - if (this.preserveAlpha) + if (this.preserveAlpha) + { + for (int x = 0; x < this.bounds.Width; x++) { - for (int x = 0; x < this.bounds.Width; x++) - { - DenseMatrixUtils.Convolve3( - in this.kernel, - this.sourcePixels, - ref spanRef, - y, - x, - this.bounds.Y, - this.maxY, - this.bounds.X, - this.maxX); - } + DenseMatrixUtils.Convolve3( + in this.kernel, + this.sourcePixels, + ref spanRef, + y, + x, + this.bounds.Y, + this.maxY, + this.bounds.X, + this.maxX); } - else + } + else + { + for (int x = 0; x < this.bounds.Width; x++) { - for (int x = 0; x < this.bounds.Width; x++) - { - DenseMatrixUtils.Convolve4( - in this.kernel, - this.sourcePixels, - ref spanRef, - y, - x, - this.bounds.Y, - this.maxY, - this.bounds.X, - this.maxX); - } + DenseMatrixUtils.Convolve4( + in this.kernel, + this.sourcePixels, + ref spanRef, + y, + x, + this.bounds.Y, + this.maxY, + this.bounds.X, + this.maxX); } - - PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } + + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); } } } From ee572da8306bb99bbdb131bc4adc905cd8ab75af Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 13:23:59 +0100 Subject: [PATCH 14/27] Refactored EdgeDetectorCompassProcessor --- .../EdgeDetectorCompassProcessor{TPixel}.cs | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index f15acd39a8..bfd7ff1e68 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -78,8 +78,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution processor.Apply(pass); } - var operation = new RowIntervalOperation(source.PixelBuffer, pass.PixelBuffer, interest); - ParallelRowIterator.IterateRowIntervals( + var operation = new RowOperation(source.PixelBuffer, pass.PixelBuffer, interest); + ParallelRowIterator.IterateRows( this.Configuration, interest, in operation); @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the convolution logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly Buffer2D targetPixels; private readonly Buffer2D passPixels; @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly int maxX; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( Buffer2D targetPixels, Buffer2D passPixels, Rectangle bounds) @@ -110,23 +110,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpan(y)); - ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpan(y)); + ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpan(y)); + ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpan(y)); - for (int x = this.minX; x < this.maxX; x++) - { - // Grab the max components of the two pixels - ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, x); - ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, x); + for (int x = this.minX; x < this.maxX; x++) + { + // Grab the max components of the two pixels + ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, x); + ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, x); - var pixelValue = Vector4.Max(currentPassPixel.ToVector4(), currentTargetPixel.ToVector4()); + var pixelValue = Vector4.Max(currentPassPixel.ToVector4(), currentTargetPixel.ToVector4()); - currentTargetPixel.FromVector4(pixelValue); - } + currentTargetPixel.FromVector4(pixelValue); } } } From aa6e091fd9134884cb22ff3264e2199a50209d76 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:29:54 +0100 Subject: [PATCH 15/27] Refactored DrawImageProcessor --- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index 7a26a03a1f..2bca1ffc0d 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -99,8 +99,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing "Cannot draw image because the source image does not overlap the target image."); } - var operation = new RowIntervalOperation(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity); - ParallelRowIterator.IterateRowIntervals( + var operation = new RowOperation(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity); + ParallelRowIterator.IterateRows( configuration, workingRect, in operation); @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// /// A implementing the draw logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly ImageFrame sourceFrame; private readonly Image targetImage; @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing private readonly float opacity; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( ImageFrame sourceFrame, Image targetImage, PixelBlender blender, @@ -146,14 +146,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span background = this.sourceFrame.GetPixelRowSpan(y).Slice(this.minX, this.width); - Span foreground = this.targetImage.GetPixelRowSpan(y - this.locationY).Slice(this.targetX, this.width); - this.blender.Blend(this.configuration, background, background, foreground, this.opacity); - } + Span background = this.sourceFrame.GetPixelRowSpan(y).Slice(this.minX, this.width); + Span foreground = this.targetImage.GetPixelRowSpan(y - this.locationY).Slice(this.targetX, this.width); + this.blender.Blend(this.configuration, background, background, foreground, this.opacity); } } } From 08db1f0391ccdf6b1990f5730f12106cc86974d0 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:31:47 +0100 Subject: [PATCH 16/27] Refactored PixelRowDelegateProcessor --- ...lRowDelegateProcessor{TPixel,TDelegate}.cs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs index f94cd50800..d4b6f11f33 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs @@ -50,9 +50,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects protected override void OnFrameApply(ImageFrame source) { var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - var operation = new RowIntervalOperation(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate); + var operation = new RowOperation(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( this.Configuration, interest, in operation); @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects /// /// A implementing the convolution logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly int startX; private readonly ImageFrame source; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects private readonly TDelegate rowProcessor; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( int startX, ImageFrame source, Configuration configuration, @@ -86,18 +86,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); - PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span, 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(span, new Point(this.startX, y)); + // Run the user defined pixel shader to the current row of pixels + Unsafe.AsRef(this.rowProcessor).Invoke(span, new Point(this.startX, y)); - PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers); - } + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers); } } } From f066dc0bbd26ae6a62beb81dab861b9230ce67ea Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:32:52 +0100 Subject: [PATCH 17/27] Refactored FilterProcessor --- .../Filters/FilterProcessor{TPixel}.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index a677f60277..8d62a5c05d 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -36,9 +36,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters protected override void OnFrameApply(ImageFrame source) { var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - var operation = new RowIntervalOperation(interest.X, source, this.definition.Matrix, this.Configuration); + var operation = new RowOperation(interest.X, source, this.definition.Matrix, this.Configuration); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( this.Configuration, interest, in operation); @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters /// /// A implementing the convolution logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly int startX; private readonly ImageFrame source; @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters private readonly Configuration configuration; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( int startX, ImageFrame source, ColorMatrix matrix, @@ -69,17 +69,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); - PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span); + Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); + PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span); - Vector4Utils.Transform(span, ref Unsafe.AsRef(this.matrix)); + Vector4Utils.Transform(span, ref Unsafe.AsRef(this.matrix)); - PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan); - } + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan); } } } From babbcd8f7cecf4d2804ffdaa88c25b31637ed628 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:36:32 +0100 Subject: [PATCH 18/27] Refactored GlobalHistogramEqualizationProcessor --- ...lHistogramEqualizationProcessor{TPixel}.cs | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs index 0567151bc0..9bf8b9b742 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization using IMemoryOwner histogramBuffer = memoryAllocator.Allocate(this.LuminanceLevels, AllocationOptions.Clean); // Build the histogram of the grayscale levels - var grayscaleOperation = new GrayscaleLevelsRowIntervalOperation(interest, histogramBuffer, source, this.LuminanceLevels); - ParallelRowIterator.IterateRowIntervals( + var grayscaleOperation = new GrayscaleLevelsRowOperation(interest, histogramBuffer, source, this.LuminanceLevels); + ParallelRowIterator.IterateRows( this.Configuration, interest, in grayscaleOperation); @@ -75,8 +75,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization float numberOfPixelsMinusCdfMin = numberOfPixels - cdfMin; // Apply the cdf to each pixel of the image - var cdfOperation = new CdfApplicationRowIntervalOperation(interest, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin); - ParallelRowIterator.IterateRowIntervals( + var cdfOperation = new CdfApplicationRowOperation(interest, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin); + ParallelRowIterator.IterateRows( this.Configuration, interest, in cdfOperation); @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// /// A implementing the grayscale levels logic for . /// - private readonly struct GrayscaleLevelsRowIntervalOperation : IRowIntervalOperation + private readonly struct GrayscaleLevelsRowOperation : IRowOperation { private readonly Rectangle bounds; private readonly IMemoryOwner histogramBuffer; @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization private readonly int luminanceLevels; [MethodImpl(InliningOptions.ShortMethod)] - public GrayscaleLevelsRowIntervalOperation( + public GrayscaleLevelsRowOperation( Rectangle bounds, IMemoryOwner histogramBuffer, ImageFrame source, @@ -107,18 +107,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { ref int histogramBase = ref MemoryMarshal.GetReference(this.histogramBuffer.GetSpan()); - for (int y = rows.Min; y < rows.Max; y++) - { - ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); + ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); - for (int x = 0; x < this.bounds.Width; x++) - { - int luminance = GetLuminance(Unsafe.Add(ref pixelBase, x), this.luminanceLevels); - Unsafe.Add(ref histogramBase, luminance)++; - } + for (int x = 0; x < this.bounds.Width; x++) + { + int luminance = GetLuminance(Unsafe.Add(ref pixelBase, x), this.luminanceLevels); + Unsafe.Add(ref histogramBase, luminance)++; } } } @@ -126,7 +123,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// /// A implementing the cdf application levels logic for . /// - private readonly struct CdfApplicationRowIntervalOperation : IRowIntervalOperation + private readonly struct CdfApplicationRowOperation : IRowOperation { private readonly Rectangle bounds; private readonly IMemoryOwner cdfBuffer; @@ -135,7 +132,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization private readonly float numberOfPixelsMinusCdfMin; [MethodImpl(InliningOptions.ShortMethod)] - public CdfApplicationRowIntervalOperation( + public CdfApplicationRowOperation( Rectangle bounds, IMemoryOwner cdfBuffer, ImageFrame source, @@ -151,20 +148,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { ref int cdfBase = ref MemoryMarshal.GetReference(this.cdfBuffer.GetSpan()); - for (int y = rows.Min; y < rows.Max; y++) + ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); + + for (int x = 0; x < this.bounds.Width; x++) { - ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); - - for (int x = 0; x < this.bounds.Width; x++) - { - ref TPixel pixel = ref Unsafe.Add(ref pixelBase, x); - int luminance = GetLuminance(pixel, this.luminanceLevels); - float luminanceEqualized = Unsafe.Add(ref cdfBase, luminance) / this.numberOfPixelsMinusCdfMin; - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); - } + ref TPixel pixel = ref Unsafe.Add(ref pixelBase, x); + int luminance = GetLuminance(pixel, this.luminanceLevels); + float luminanceEqualized = Unsafe.Add(ref cdfBase, luminance) / this.numberOfPixelsMinusCdfMin; + pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); } } } From 08dc224f5d4876b5685bf6b285963be1e1409a81 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:37:31 +0100 Subject: [PATCH 19/27] Refactored BackgroundColorProcessor --- .../BackgroundColorProcessor{TPixel}.cs | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs index 3f4174d6ed..1c6b780251 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs @@ -49,14 +49,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays PixelBlender blender = PixelOperations.Instance.GetPixelBlender(graphicsOptions); - var operation = new RowIntervalOperation(configuration, interest, blender, amount, colors, source); - ParallelRowIterator.IterateRowIntervals( + var operation = new RowOperation(configuration, interest, blender, amount, colors, source); + ParallelRowIterator.IterateRows( configuration, interest, in operation); } - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly Configuration configuration; private readonly Rectangle bounds; @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays private readonly ImageFrame source; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( Configuration configuration, Rectangle bounds, PixelBlender blender, @@ -83,23 +83,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span destination = - this.source.GetPixelRowSpan(y) - .Slice(this.bounds.X, this.bounds.Width); + Span destination = + this.source.GetPixelRowSpan(y) + .Slice(this.bounds.X, this.bounds.Width); - // Switch color & destination in the 2nd and 3rd places because we are - // applying the target color under the current one. - this.blender.Blend( - this.configuration, - destination, - this.colors.GetSpan(), - destination, - this.amount.GetSpan()); - } + // Switch color & destination in the 2nd and 3rd places because we are + // applying the target color under the current one. + this.blender.Blend( + this.configuration, + destination, + this.colors.GetSpan(), + destination, + this.amount.GetSpan()); } } } From 7fed77d4e07fd2bfe9ac48074ccc8ffd3430779d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:38:13 +0100 Subject: [PATCH 20/27] Refactored GlowProcessor --- .../Overlays/GlowProcessor{TPixel}.cs | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs index ff148e8398..efa5ddf881 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs @@ -55,14 +55,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays using IMemoryOwner rowColors = allocator.Allocate(interest.Width); rowColors.GetSpan().Fill(glowColor); - var operation = new RowIntervalOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source); - ParallelRowIterator.IterateRowIntervals( + var operation = new RowOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source); + ParallelRowIterator.IterateRows( configuration, interest, in operation); } - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly Configuration configuration; private readonly Rectangle bounds; @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays private readonly ImageFrame source; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( Configuration configuration, Rectangle bounds, IMemoryOwner colors, @@ -95,27 +95,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { Span colorSpan = this.colors.GetSpan(); - for (int y = rows.Min; y < rows.Max; y++) + for (int i = 0; i < this.bounds.Width; i++) { - for (int i = 0; i < this.bounds.Width; i++) - { - float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); - span[i] = (this.blendPercent * (1 - (.95F * (distance / this.maxDistance)))).Clamp(0, 1); - } + float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); + 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); + Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width); - this.blender.Blend( - this.configuration, - destination, - destination, - colorSpan, - span); - } + this.blender.Blend( + this.configuration, + destination, + destination, + colorSpan, + span); } } } From 851f491aa19c889d8e031fb8bdfbdfda0cbd7484 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:38:52 +0100 Subject: [PATCH 21/27] Refactored VignetteProcessor --- .../Overlays/VignetteProcessor{TPixel}.cs | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs index ce69de2fd7..de7bce1695 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs @@ -63,14 +63,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays using IMemoryOwner rowColors = allocator.Allocate(interest.Width); rowColors.GetSpan().Fill(vignetteColor); - var operation = new RowIntervalOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source); - ParallelRowIterator.IterateRowIntervals( + var operation = new RowOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source); + ParallelRowIterator.IterateRows( configuration, interest, in operation); } - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly Configuration configuration; private readonly Rectangle bounds; @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays private readonly ImageFrame source; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation( + public RowOperation( Configuration configuration, Rectangle bounds, IMemoryOwner colors, @@ -103,27 +103,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { Span colorSpan = this.colors.GetSpan(); - for (int y = rows.Min; y < rows.Max; y++) + for (int i = 0; i < this.bounds.Width; i++) { - for (int i = 0; i < this.bounds.Width; i++) - { - float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); - span[i] = (this.blendPercent * (.9F * (distance / this.maxDistance))).Clamp(0, 1); - } - - Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width); - - this.blender.Blend( - this.configuration, - destination, - destination, - colorSpan, - span); + float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); + span[i] = (this.blendPercent * (.9F * (distance / this.maxDistance))).Clamp(0, 1); } + + Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width); + + this.blender.Blend( + this.configuration, + destination, + destination, + colorSpan, + span); } } } From a71bcd2a21ecf0f4165fb35c6e33de910248b1a6 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:47:03 +0100 Subject: [PATCH 22/27] Refactored AffineTransformProcessor --- .../AffineTransformProcessor{TPixel}.cs | 83 +++++++++---------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs index 26475922fa..338064d234 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (sampler is NearestNeighborResampler) { var nnOperation = new NNAffineOperation(source, destination, matrix); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( configuration, destination.Bounds(), in nnOperation); @@ -105,13 +105,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms radialExtents, maxSourceExtents); - ParallelRowIterator.IterateRowIntervals, Vector4>( + ParallelRowIterator.IterateRows, Vector4>( configuration, destination.Bounds(), in operation); } - private readonly struct NNAffineOperation : IRowIntervalOperation + private readonly struct NNAffineOperation : IRowOperation { private readonly ImageFrame source; private readonly ImageFrame destination; @@ -133,28 +133,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) + Span destRow = this.destination.GetPixelRowSpan(y); + + for (int x = 0; x < this.maxX; x++) { - Span destRow = this.destination.GetPixelRowSpan(y); + var point = Vector2.Transform(new Vector2(x, y), this.matrix); + int px = (int)MathF.Round(point.X); + int py = (int)MathF.Round(point.Y); - for (int x = 0; x < this.maxX; x++) + if (this.bounds.Contains(px, py)) { - var point = Vector2.Transform(new Vector2(x, y), this.matrix); - int px = (int)MathF.Round(point.X); - int py = (int)MathF.Round(point.Y); - - if (this.bounds.Contains(px, py)) - { - destRow[x] = this.source[px, py]; - } + destRow[x] = this.source[px, py]; } } } } - private readonly struct AffineOperation : IRowIntervalOperation + private readonly struct AffineOperation : IRowOperation where TResampler : struct, IResampler { private readonly Configuration configuration; @@ -193,41 +190,39 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { Buffer2D sourceBuffer = this.source.PixelBuffer; - for (int y = rows.Min; y < rows.Max; y++) - { - PixelOperations.Instance.ToVector4( - this.configuration, - this.destination.GetPixelRowSpan(y), - span); - ref float yKernelSpanRef = ref MemoryMarshal.GetReference(this.yKernelBuffer.GetRowSpan(y)); - ref float xKernelSpanRef = ref MemoryMarshal.GetReference(this.xKernelBuffer.GetRowSpan(y)); + PixelOperations.Instance.ToVector4( + this.configuration, + this.destination.GetPixelRowSpan(y), + span); - for (int x = 0; x < this.maxX; x++) - { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - var point = Vector2.Transform(new Vector2(x, y), this.matrix); - LinearTransformUtilities.Convolve( - in this.sampler, - point, - sourceBuffer, - span, - x, - ref yKernelSpanRef, - ref xKernelSpanRef, - this.radialExtents, - this.maxSourceExtents); - } + ref float yKernelSpanRef = ref MemoryMarshal.GetReference(this.yKernelBuffer.GetRowSpan(y)); + ref float xKernelSpanRef = ref MemoryMarshal.GetReference(this.xKernelBuffer.GetRowSpan(y)); - PixelOperations.Instance.FromVector4Destructive( - this.configuration, + for (int x = 0; x < this.maxX; x++) + { + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + var point = Vector2.Transform(new Vector2(x, y), this.matrix); + LinearTransformUtilities.Convolve( + in this.sampler, + point, + sourceBuffer, span, - this.destination.GetPixelRowSpan(y)); + x, + ref yKernelSpanRef, + ref xKernelSpanRef, + this.radialExtents, + this.maxSourceExtents); } + + PixelOperations.Instance.FromVector4Destructive( + this.configuration, + span, + this.destination.GetPixelRowSpan(y)); } } } From 679d36d9c08897bf99b22a678ef87c78747a2143 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:47:53 +0100 Subject: [PATCH 23/27] Refactored FlipProcessor --- .../Transforms/Linear/FlipProcessor{TPixel}.cs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs index f5fde8a229..30d4132888 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs @@ -5,7 +5,6 @@ using System; using System.Buffers; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -76,28 +75,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The configuration. private void FlipY(ImageFrame source, Configuration configuration) { - var operation = new RowIntervalOperation(source); - ParallelRowIterator.IterateRowIntervals( + var operation = new RowOperation(source); + ParallelRowIterator.IterateRows( configuration, source.Bounds(), in operation); } - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly ImageFrame source; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation(ImageFrame source) => this.source = source; + public RowOperation(ImageFrame source) => this.source = source; [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) - { - for (int y = rows.Min; y < rows.Max; y++) - { - this.source.GetPixelRowSpan(y).Reverse(); - } - } + public void Invoke(int y) => this.source.GetPixelRowSpan(y).Reverse(); } } } From eaab2391123a3777a9ff38de5733b9f722628c9b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:48:48 +0100 Subject: [PATCH 24/27] Refactored ProjectiveTransformProcessor --- .../ProjectiveTransformProcessor{TPixel}.cs | 83 +++++++++---------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs index 07178117a4..879bfe7ee5 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (sampler is NearestNeighborResampler) { var nnOperation = new NNProjectiveOperation(source, destination, matrix); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( configuration, destination.Bounds(), in nnOperation); @@ -105,13 +105,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms radialExtents, maxSourceExtents); - ParallelRowIterator.IterateRowIntervals, Vector4>( + ParallelRowIterator.IterateRows, Vector4>( configuration, destination.Bounds(), in operation); } - private readonly struct NNProjectiveOperation : IRowIntervalOperation + private readonly struct NNProjectiveOperation : IRowOperation { private readonly ImageFrame source; private readonly ImageFrame destination; @@ -133,28 +133,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) + Span destRow = this.destination.GetPixelRowSpan(y); + + for (int x = 0; x < this.maxX; x++) { - Span destRow = this.destination.GetPixelRowSpan(y); + Vector2 point = TransformUtilities.ProjectiveTransform2D(x, y, this.matrix); + int px = (int)MathF.Round(point.X); + int py = (int)MathF.Round(point.Y); - for (int x = 0; x < this.maxX; x++) + if (this.bounds.Contains(px, py)) { - Vector2 point = TransformUtilities.ProjectiveTransform2D(x, y, this.matrix); - int px = (int)MathF.Round(point.X); - int py = (int)MathF.Round(point.Y); - - if (this.bounds.Contains(px, py)) - { - destRow[x] = this.source[px, py]; - } + destRow[x] = this.source[px, py]; } } } } - private readonly struct ProjectiveOperation : IRowIntervalOperation + private readonly struct ProjectiveOperation : IRowOperation where TResampler : struct, IResampler { private readonly Configuration configuration; @@ -193,41 +190,39 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows, Span span) + public void Invoke(int y, Span span) { Buffer2D sourceBuffer = this.source.PixelBuffer; - for (int y = rows.Min; y < rows.Max; y++) - { - PixelOperations.Instance.ToVector4( - this.configuration, - this.destination.GetPixelRowSpan(y), - span); - ref float yKernelSpanRef = ref MemoryMarshal.GetReference(this.yKernelBuffer.GetRowSpan(y)); - ref float xKernelSpanRef = ref MemoryMarshal.GetReference(this.xKernelBuffer.GetRowSpan(y)); + PixelOperations.Instance.ToVector4( + this.configuration, + this.destination.GetPixelRowSpan(y), + span); - for (int x = 0; x < this.maxX; x++) - { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - Vector2 point = TransformUtilities.ProjectiveTransform2D(x, y, this.matrix); - LinearTransformUtilities.Convolve( - in this.sampler, - point, - sourceBuffer, - span, - x, - ref yKernelSpanRef, - ref xKernelSpanRef, - this.radialExtents, - this.maxSourceExtents); - } + ref float yKernelSpanRef = ref MemoryMarshal.GetReference(this.yKernelBuffer.GetRowSpan(y)); + ref float xKernelSpanRef = ref MemoryMarshal.GetReference(this.xKernelBuffer.GetRowSpan(y)); - PixelOperations.Instance.FromVector4Destructive( - this.configuration, + for (int x = 0; x < this.maxX; x++) + { + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + Vector2 point = TransformUtilities.ProjectiveTransform2D(x, y, this.matrix); + LinearTransformUtilities.Convolve( + in this.sampler, + point, + sourceBuffer, span, - this.destination.GetPixelRowSpan(y)); + x, + ref yKernelSpanRef, + ref xKernelSpanRef, + this.radialExtents, + this.maxSourceExtents); } + + PixelOperations.Instance.FromVector4Destructive( + this.configuration, + span, + this.destination.GetPixelRowSpan(y)); } } } From f8f771dd916397133964a815b26597c9610b78d8 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:49:49 +0100 Subject: [PATCH 25/27] Refactored RotateProcessor --- .../Linear/RotateProcessor{TPixel}.cs | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs index d6755e8ba2..04d259e409 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs @@ -131,8 +131,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The configuration. private void Rotate180(ImageFrame source, ImageFrame destination, Configuration configuration) { - var operation = new Rotate180RowIntervalOperation(source.Width, source.Height, source, destination); - ParallelRowIterator.IterateRowIntervals( + var operation = new Rotate180RowOperation(source.Width, source.Height, source, destination); + ParallelRowIterator.IterateRows( configuration, source.Bounds(), in operation); @@ -161,14 +161,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The configuration. private void Rotate90(ImageFrame source, ImageFrame destination, Configuration configuration) { - var operation = new Rotate90RowIntervalOperation(destination.Bounds(), source.Width, source.Height, source, destination); - ParallelRowIterator.IterateRowIntervals( + var operation = new Rotate90RowOperation(destination.Bounds(), source.Width, source.Height, source, destination); + ParallelRowIterator.IterateRows( configuration, source.Bounds(), in operation); } - private readonly struct Rotate180RowIntervalOperation : IRowIntervalOperation + private readonly struct Rotate180RowOperation : IRowOperation { private readonly int width; private readonly int height; @@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public Rotate180RowIntervalOperation( + public Rotate180RowOperation( int width, int height, ImageFrame source, @@ -189,17 +189,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span sourceRow = this.source.GetPixelRowSpan(y); - Span targetRow = this.destination.GetPixelRowSpan(this.height - y - 1); + Span sourceRow = this.source.GetPixelRowSpan(y); + Span targetRow = this.destination.GetPixelRowSpan(this.height - y - 1); - for (int x = 0; x < this.width; x++) - { - targetRow[this.width - x - 1] = sourceRow[x]; - } + for (int x = 0; x < this.width; x++) + { + targetRow[this.width - x - 1] = sourceRow[x]; } } } @@ -248,7 +245,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } } - private readonly struct Rotate90RowIntervalOperation : IRowIntervalOperation + private readonly struct Rotate90RowOperation : IRowOperation { private readonly Rectangle bounds; private readonly int width; @@ -257,7 +254,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public Rotate90RowIntervalOperation( + public Rotate90RowOperation( Rectangle bounds, int width, int height, @@ -272,18 +269,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) + Span sourceRow = this.source.GetPixelRowSpan(y); + int newX = this.height - y - 1; + for (int x = 0; x < this.width; x++) { - Span sourceRow = this.source.GetPixelRowSpan(y); - int newX = this.height - y - 1; - for (int x = 0; x < this.width; x++) + if (this.bounds.Contains(newX, x)) { - if (this.bounds.Contains(newX, x)) - { - this.destination[newX, x] = sourceRow[x]; - } + this.destination[newX, x] = sourceRow[x]; } } } From 1350c08873127941e17ef72b34cc61effaf47edd Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:51:36 +0100 Subject: [PATCH 26/27] Refactored ResizeProcessor --- .../Resize/ResizeProcessor{TPixel}.cs | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index c0dc886885..a4f32f7499 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Implements resizing of images using various resamplers. /// /// The pixel format. - internal partial class ResizeProcessor : TransformProcessor, IResamplingTransformImageProcessor + internal class ResizeProcessor : TransformProcessor, IResamplingTransformImageProcessor where TPixel : struct, IPixel { private readonly int destinationWidth; @@ -144,7 +144,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float widthFactor = sourceRectangle.Width / (float)destinationRectangle.Width; float heightFactor = sourceRectangle.Height / (float)destinationRectangle.Height; - var operation = new NNRowIntervalOperation( + var operation = new NNRowOperation( sourceRectangle, destinationRectangle, widthFactor, @@ -152,7 +152,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms source, destination); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( configuration, interest, in operation); @@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } } - private readonly struct NNRowIntervalOperation : IRowIntervalOperation + private readonly struct NNRowOperation : IRowOperation { private readonly Rectangle sourceBounds; private readonly Rectangle destinationBounds; @@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public NNRowIntervalOperation( + public NNRowOperation( Rectangle sourceBounds, Rectangle destinationBounds, float widthFactor, @@ -220,7 +220,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { int sourceX = this.sourceBounds.X; int sourceY = this.sourceBounds.Y; @@ -229,17 +229,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int destLeft = this.destinationBounds.Left; int destRight = this.destinationBounds.Right; - for (int y = rows.Min; y < rows.Max; y++) + // Y coordinates of source points + Span sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY)); + Span targetRow = this.destination.GetPixelRowSpan(y); + + for (int x = destLeft; x < destRight; x++) { - // Y coordinates of source points - Span sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY)); - Span targetRow = this.destination.GetPixelRowSpan(y); - - for (int x = destLeft; x < destRight; x++) - { - // X coordinates of source points - targetRow[x] = sourceRow[(int)(((x - destX) * this.widthFactor) + sourceX)]; - } + // X coordinates of source points + targetRow[x] = sourceRow[(int)(((x - destX) * this.widthFactor) + sourceX)]; } } } From ab6cf8d4314df3416e3c2341d25b065b64246064 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 19:52:21 +0100 Subject: [PATCH 27/27] Refactored CropProcessor --- .../Transforms/CropProcessor{TPixel}.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs index d72790ea15..75509283f2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs @@ -51,9 +51,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ParallelExecutionSettings parallelSettings = ParallelExecutionSettings.FromConfiguration(this.Configuration).MultiplyMinimumPixelsPerTask(4); - var operation = new RowIntervalOperation(bounds, source, destination); + var operation = new RowOperation(bounds, source, destination); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( bounds, in parallelSettings, in operation); @@ -62,20 +62,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// A implementing the processor logic for . /// - private readonly struct RowIntervalOperation : IRowIntervalOperation + private readonly struct RowOperation : IRowOperation { private readonly Rectangle bounds; private readonly ImageFrame source; private readonly ImageFrame destination; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The target processing bounds for the current instance. /// The source for the current instance. /// The destination for the current instance. [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalOperation(Rectangle bounds, ImageFrame source, ImageFrame destination) + public RowOperation(Rectangle bounds, ImageFrame source, ImageFrame destination) { this.bounds = bounds; this.source = source; @@ -84,14 +84,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span sourceRow = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left); - Span targetRow = this.destination.GetPixelRowSpan(y - this.bounds.Top); - sourceRow.Slice(0, this.bounds.Width).CopyTo(targetRow); - } + Span sourceRow = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left); + Span targetRow = this.destination.GetPixelRowSpan(y - this.bounds.Top); + sourceRow.Slice(0, this.bounds.Width).CopyTo(targetRow); } } }