From 61e2a8d92babbc758a5196aeda53049baad75833 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Aug 2018 20:09:45 +0200 Subject: [PATCH 1/2] Replace Configuration.ParallelOptions with Configuration.MaxDegreeOfParallelism --- .../Processors/Drawing/DrawImageProcessor.cs | 4 +- .../Processors/Drawing/FillProcessor.cs | 8 ++-- .../Extensions/ConfigurationExtensions.cs | 22 +++++++++++ src/ImageSharp/Common/Helpers/ParallelFor.cs | 6 +-- src/ImageSharp/Configuration.cs | 21 ++++++++-- src/ImageSharp/ImageFrame{TPixel}.cs | 2 +- .../Binarization/BinaryThresholdProcessor.cs | 30 ++++++++------- .../Convolution/Convolution2DProcessor.cs | 4 +- .../Convolution/Convolution2PassProcessor.cs | 14 +++---- .../Convolution/ConvolutionProcessor.cs | 4 +- .../EdgeDetectorCompassProcessor.cs | 4 +- .../Effects/OilPaintingProcessor.cs | 4 +- .../Processors/Effects/PixelateProcessor.cs | 2 +- .../Processors/Filters/FilterProcessor.cs | 4 +- .../Overlays/BackgroundColorProcessor.cs | 4 +- .../Processors/Overlays/GlowProcessor.cs | 30 +++++++-------- .../Processors/Overlays/VignetteProcessor.cs | 38 +++++++++++-------- .../Transforms/AffineTransformProcessor.cs | 8 ++-- .../Processors/Transforms/CropProcessor.cs | 4 +- .../Processors/Transforms/FlipProcessor.cs | 8 ++-- .../ProjectiveTransformProcessor.cs | 8 ++-- .../Processors/Transforms/ResizeProcessor.cs | 8 ++-- .../Processors/Transforms/RotateProcessor.cs | 12 +++--- .../Codecs/CopyPixels.cs | 16 ++++---- .../Codecs/Jpeg/LoadResizeSave.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 4 +- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 2 +- tests/ImageSharp.Tests/ConfigurationTests.cs | 25 +++++++----- .../Drawing/SolidPolygonTests.cs | 6 +-- 29 files changed, 175 insertions(+), 129 deletions(-) create mode 100644 src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index 4a59dfe3e..1170f20a8 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -139,10 +139,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { amount.GetSpan().Fill(this.Opacity); - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { Span background = source.GetPixelRowSpan(y).Slice(minX, width); diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index e40ba5316..8d7778a33 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -54,10 +54,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing // If there's no reason for blending, then avoid it. if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) { - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); @@ -84,10 +84,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { amount.GetSpan().Fill(1f); - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { int offsetY = y - startY; diff --git a/src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs b/src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs new file mode 100644 index 000000000..6bb5adc06 --- /dev/null +++ b/src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Threading.Tasks; + +namespace SixLabors.ImageSharp +{ + /// + /// Contains extension methods for + /// + internal static class ConfigurationExtensions + { + /// + /// Creates a object based on , + /// having set to + /// + public static ParallelOptions GetParallelOptions(this Configuration configuration) + { + return new ParallelOptions() { MaxDegreeOfParallelism = configuration.MaxDegreeOfParallelism }; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/ParallelFor.cs b/src/ImageSharp/Common/Helpers/ParallelFor.cs index 02c6deda3..4c14bb6e3 100644 --- a/src/ImageSharp/Common/Helpers/ParallelFor.cs +++ b/src/ImageSharp/Common/Helpers/ParallelFor.cs @@ -11,11 +11,11 @@ namespace SixLabors.ImageSharp internal static class ParallelFor { /// - /// Helper method to execute Parallel.For using the settings in + /// Helper method to execute Parallel.For using the settings in /// public static void WithConfiguration(int fromInclusive, int toExclusive, Configuration configuration, Action body) { - Parallel.For(fromInclusive, toExclusive, configuration.ParallelOptions, body); + Parallel.For(fromInclusive, toExclusive, configuration.GetParallelOptions(), body); } /// @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp where T : struct { MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - ParallelOptions parallelOptions = configuration.ParallelOptions; + ParallelOptions parallelOptions = configuration.GetParallelOptions(); IMemoryOwner InitBuffer() { diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index e84674355..1b009bfed 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -27,6 +27,8 @@ namespace SixLabors.ImageSharp /// private static readonly Lazy Lazy = new Lazy(CreateDefaultInstance); + private int maxDegreeOfParallelism = Environment.ProcessorCount; + /// /// Initializes a new instance of the class. /// @@ -55,9 +57,22 @@ namespace SixLabors.ImageSharp public static Configuration Default { get; } = Lazy.Value; /// - /// Gets the global parallel options for processing tasks in parallel. + /// Gets or sets the maximum number of concurrent tasks enabled in ImageSharp algorithms + /// configured with this instance. /// - public ParallelOptions ParallelOptions { get; private set; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; + public int MaxDegreeOfParallelism + { + get => this.maxDegreeOfParallelism; + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(this.MaxDegreeOfParallelism)); + } + + this.maxDegreeOfParallelism = value; + } + } /// /// Gets the currently registered s. @@ -114,7 +129,7 @@ namespace SixLabors.ImageSharp { return new Configuration { - ParallelOptions = this.ParallelOptions, + MaxDegreeOfParallelism = this.MaxDegreeOfParallelism, ImageFormatsManager = this.ImageFormatsManager, MemoryAllocator = this.MemoryAllocator, ImageOperationsProvider = this.ImageOperationsProvider, diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 6c04d5aea..bd313d488 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(width, height); this.MetaData = metaData; - this.Clear(configuration.ParallelOptions, backgroundColor); + this.Clear(configuration.GetParallelOptions(), backgroundColor); } /// diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 57d4e00ae..c4f4266d9 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -70,25 +70,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); - Parallel.For( + ParallelFor.WithConfiguration( startY, endY, - configuration.ParallelOptions, + configuration, y => - { - Span row = source.GetPixelRowSpan(y); - Rgba32 rgba = default; - - for (int x = startX; x < endX; x++) { - ref TPixel color = ref row[x]; - color.ToRgba32(ref rgba); + Span row = source.GetPixelRowSpan(y); + Rgba32 rgba = default; + + for (int x = startX; x < endX; x++) + { + ref TPixel color = ref row[x]; + color.ToRgba32(ref rgba); - // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); - color = luminance >= threshold ? upper : lower; - } - }); + // Convert to grayscale using ITU-R Recommendation BT.709 if required + float luminance = isAlphaOnly + ? rgba.A + : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + color = luminance >= threshold ? upper : lower; + } + }); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 57f71a9ce..4b56f15cd 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -61,10 +61,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { source.CopyTo(targetPixels); - Parallel.For( + ParallelFor.WithConfiguration( startY, endY, - configuration.ParallelOptions, + configuration, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 6d7147cf7..56fd5c5e9 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -43,12 +43,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - ParallelOptions parallelOptions = configuration.ParallelOptions; - using (Buffer2D firstPassPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) { - this.ApplyConvolution(firstPassPixels, source.PixelBuffer, source.Bounds(), this.KernelX, parallelOptions); - this.ApplyConvolution(source.PixelBuffer, firstPassPixels, sourceRectangle, this.KernelY, parallelOptions); + this.ApplyConvolution(firstPassPixels, source.PixelBuffer, source.Bounds(), this.KernelX, configuration); + this.ApplyConvolution(source.PixelBuffer, firstPassPixels, sourceRectangle, this.KernelY, configuration); } } @@ -62,13 +60,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// The structure that specifies the portion of the image object to draw. /// /// The kernel operator. - /// The parallel options + /// The private void ApplyConvolution( Buffer2D targetPixels, Buffer2D sourcePixels, Rectangle sourceRectangle, DenseMatrix kernel, - ParallelOptions parallelOptions) + Configuration configuration) { int kernelHeight = kernel.Rows; int kernelWidth = kernel.Columns; @@ -82,10 +80,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution int maxY = endY - 1; int maxX = endX - 1; - Parallel.For( + ParallelFor.WithConfiguration( startY, endY, - parallelOptions, + configuration, y => { Span targetRow = targetPixels.GetRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index 84a166545..46b4ded2e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { source.CopyTo(targetPixels); - Parallel.For( + ParallelFor.WithConfiguration( startY, endY, - configuration.ParallelOptions, + configuration, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs index 22297b8f2..8969ba193 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs @@ -133,10 +133,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Buffer2D passPixels = pass.PixelBuffer; Buffer2D targetPixels = source.PixelBuffer; - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { int offsetY = y - shiftY; diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index b9329f4df..01816bedc 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -69,10 +69,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects { source.CopyTo(targetPixels); - Parallel.For( + ParallelFor.WithConfiguration( startY, maxY, - configuration.ParallelOptions, + configuration, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs index 56085e76c..50f76efed 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects Parallel.ForEach( range, - configuration.ParallelOptions, + configuration.GetParallelOptions(), y => { int offsetY = y - startY; diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs index e8a1fc9cb..6244d8bf7 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs @@ -41,10 +41,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters int endX = interest.Right; Matrix4x4 matrix = this.Matrix; - Parallel.For( + ParallelFor.WithConfiguration( startY, endY, - configuration.ParallelOptions, + configuration, y => { Span row = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index d2e89fcd0..faccdc294 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -81,10 +81,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } PixelBlender blender = PixelOperations.Instance.GetPixelBlender(this.GraphicsOptions.BlenderMode); - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { Span destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 17d131413..0f5967c28 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -122,27 +122,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays rowColorsSpan[i] = glowColor; } - Parallel.For( + ParallelFor.WithTemporaryBuffer( minY, maxY, - configuration.ParallelOptions, - y => + configuration, + width, + (y, amounts) => { - using (IMemoryOwner amounts = source.MemoryAllocator.Allocate(width)) + Span amountsSpan = amounts.GetSpan(); + int offsetY = y - startY; + int offsetX = minX - startX; + for (int i = 0; i < width; i++) { - Span amountsSpan = amounts.GetSpan(); - int offsetY = y - startY; - int offsetX = minX - startX; - for (int i = 0; i < width; i++) - { - float distance = Vector2.Distance(center, new Vector2(i + offsetX, offsetY)); - amountsSpan[i] = (this.GraphicsOptions.BlendPercentage * (1 - (.95F * (distance / maxDistance)))).Clamp(0, 1); - } - - Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); - - this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan); + float distance = Vector2.Distance(center, new Vector2(i + offsetX, offsetY)); + amountsSpan[i] = (this.GraphicsOptions.BlendPercentage * (1 - (.95F * (distance / maxDistance)))).Clamp(0, 1); } + + Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); + + this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan); }); } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index a306459d1..58a21c1d2 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -124,27 +124,33 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays rowColorsSpan[i] = vignetteColor; } - Parallel.For( + ParallelFor.WithTemporaryBuffer( minY, maxY, - configuration.ParallelOptions, - y => + configuration, + width, + (y, amounts) => { - using (IMemoryOwner amounts = source.MemoryAllocator.Allocate(width)) + Span amountsSpan = amounts.GetSpan(); + int offsetY = y - startY; + int offsetX = minX - startX; + for (int i = 0; i < width; i++) { - Span amountsSpan = amounts.GetSpan(); - int offsetY = y - startY; - int offsetX = minX - startX; - for (int i = 0; i < width; i++) - { - float distance = Vector2.Distance(centre, new Vector2(i + offsetX, offsetY)); - amountsSpan[i] = (this.GraphicsOptions.BlendPercentage * (.9F * (distance / maxDistance))).Clamp(0, 1); - } - - Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); - - this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan); + float distance = Vector2.Distance(centre, new Vector2(i + offsetX, offsetY)); + amountsSpan[i] = + (this.GraphicsOptions.BlendPercentage * (.9F * (distance / maxDistance))).Clamp( + 0, + 1); } + + Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); + + this.blender.Blend( + source.MemoryAllocator, + destination, + destination, + rowColors.GetSpan(), + amountsSpan); }); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index d9f35c892..a5333fda7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -77,10 +77,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (this.Sampler is NearestNeighborResampler) { - Parallel.For( + ParallelFor.WithConfiguration( 0, height, - configuration.ParallelOptions, + configuration, y => { Span destRow = destination.GetPixelRowSpan(y); @@ -115,10 +115,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) { - Parallel.For( + ParallelFor.WithConfiguration( 0, height, - configuration.ParallelOptions, + configuration, y => { ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 5d714eef5..0c5212375 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -58,10 +58,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int minX = Math.Max(this.CropRectangle.X, sourceRectangle.X); int maxX = Math.Min(this.CropRectangle.Right, sourceRectangle.Right); - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { Span sourceRow = source.GetPixelRowSpan(y).Slice(minX); diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs index 4ab4971b8..dbbdd1859 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs @@ -58,10 +58,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) { - Parallel.For( + ParallelFor.WithConfiguration( 0, halfHeight, - configuration.ParallelOptions, + configuration, y => { int newY = height - y - 1; @@ -91,10 +91,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) { - Parallel.For( + ParallelFor.WithConfiguration( 0, height, - configuration.ParallelOptions, + configuration, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 716133fb7..5a4fba177 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -74,10 +74,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (this.Sampler is NearestNeighborResampler) { - Parallel.For( + ParallelFor.WithConfiguration( 0, height, - configuration.ParallelOptions, + configuration, y => { Span destRow = destination.GetPixelRowSpan(y); @@ -120,10 +120,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) { - Parallel.For( + ParallelFor.WithConfiguration( 0, height, - configuration.ParallelOptions, + configuration, y => { ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 9c09b6a22..02e7948e1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -270,10 +270,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width; float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height; - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { // Y coordinates of source points @@ -331,10 +331,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms }); // Now process the rows. - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { // Ensure offsets are normalized for cropping and padding. diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index d57e9cbd9..b18d882c2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -147,10 +147,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int height = source.Height; Rectangle destinationBounds = destination.Bounds(); - Parallel.For( + ParallelFor.WithConfiguration( 0, height, - configuration.ParallelOptions, + configuration, y => { Span sourceRow = source.GetPixelRowSpan(y); @@ -179,10 +179,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int width = source.Width; int height = source.Height; - Parallel.For( + ParallelFor.WithConfiguration( 0, height, - configuration.ParallelOptions, + configuration, y => { Span sourceRow = source.GetPixelRowSpan(y); @@ -207,10 +207,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int height = source.Height; Rectangle destinationBounds = destination.Bounds(); - Parallel.For( + ParallelFor.WithConfiguration( 0, height, - configuration.ParallelOptions, + configuration, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs b/tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs index 8bf87fb62..65e59c20b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs @@ -24,10 +24,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { Buffer2D sourcePixels = source.GetRootFramePixelBuffer(); Buffer2D targetPixels = target.GetRootFramePixelBuffer(); - Parallel.For( + ParallelFor.WithConfiguration( 0, source.Height, - Configuration.Default.ParallelOptions, + Configuration.Default, y => { for (int x = 0; x < source.Width; x++) @@ -48,10 +48,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { Buffer2D sourcePixels = source.GetRootFramePixelBuffer(); Buffer2D targetPixels = target.GetRootFramePixelBuffer(); - Parallel.For( + ParallelFor.WithConfiguration( 0, source.Height, - Configuration.Default.ParallelOptions, + Configuration.Default, y => { Span sourceRow = sourcePixels.GetRowSpan(y); @@ -73,10 +73,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs using (var source = new Image(1024, 768)) using (var target = new Image(1024, 768)) { - Parallel.For( + ParallelFor.WithConfiguration( 0, source.Height, - Configuration.Default.ParallelOptions, + Configuration.Default, y => { for (int x = 0; x < source.Width; x++) @@ -95,10 +95,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs using (var source = new Image(1024, 768)) using (var target = new Image(1024, 768)) { - Parallel.For( + ParallelFor.WithConfiguration( 0, source.Height, - Configuration.Default.ParallelOptions, + Configuration.Default, y => { Span sourceRow = source.Frames.RootFrame.GetPixelRowSpan(y); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs index 1d485ee08..77ed828ef 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [GlobalSetup] public void Setup() { - this.configuration.ParallelOptions.MaxDegreeOfParallelism = + this.configuration.MaxDegreeOfParallelism = this.EnableParallelExecution ? Environment.ProcessorCount : 1; if (this.sourceBytes == null) diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index f7f54f4eb..6508537a3 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -109,10 +109,10 @@ namespace SixLabors.ImageSharp.Benchmarks Buffer2D sourcePixels = source.PixelBuffer; rowColors.GetSpan().Fill(glowColor); - Parallel.For( + ParallelFor.WithConfiguration( minY, maxY, - configuration.ParallelOptions, + configuration, y => { int offsetY = y - startY; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index d4506fc6a..86dc13e91 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Benchmarks [GlobalSetup] public void Setup() { - this.configuration.ParallelOptions.MaxDegreeOfParallelism = + this.configuration.MaxDegreeOfParallelism = this.EnableParallelExecution ? Environment.ProcessorCount : 1; } diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index d870b7bf7..1a7183df8 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.PixelFormats; using Moq; using Xunit; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests { @@ -45,15 +46,6 @@ namespace SixLabors.ImageSharp.Tests Assert.True(Configuration.Default != null); } - /// - /// Test that the default configuration parallel options is not null. - /// - [Fact] - public void TestDefaultConfigurationParallelOptionsIsNotNull() - { - Assert.True(Configuration.Default.ParallelOptions != null); - } - /// /// Test that the default configuration read origin options is set to begin. /// @@ -70,9 +62,22 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void TestDefaultConfigurationMaxDegreeOfParallelism() { - Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount); + Assert.True(Configuration.Default.MaxDegreeOfParallelism == Environment.ProcessorCount); + + var cfg = new Configuration(); + Assert.True(cfg.MaxDegreeOfParallelism == Environment.ProcessorCount); } + [Theory] + [InlineData(0)] + [InlineData(-42)] + public void Set_MaxDegreeOfParallelism_ToNonPositiveValue_Throws(int value) + { + var cfg = new Configuration(); + Assert.Throws(() => cfg.MaxDegreeOfParallelism = value); + } + + [Fact] public void ConstructorCallConfigureOnFormatProvider() { diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index e42b4b481..f727b74ee 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons"); var config = Configuration.CreateDefaultInstance(); - config.ParallelOptions.MaxDegreeOfParallelism = 1; + config.MaxDegreeOfParallelism = 1; using (var image = new Image(config, 100, 100)) { image.Mutate(x => x @@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons"); var config = Configuration.CreateDefaultInstance(); - config.ParallelOptions.MaxDegreeOfParallelism = 1; + config.MaxDegreeOfParallelism = 1; using (var image = new Image(config, 100, 100)) { image.Mutate(x => x @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons"); var config = Configuration.CreateDefaultInstance(); - config.ParallelOptions.MaxDegreeOfParallelism = 1; + config.MaxDegreeOfParallelism = 1; using (var image = new Image(config, 200, 200)) { image.Mutate(x => x From 2dc09c96372eea64c80b2793bc445c4fc7b5a1d4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Aug 2018 21:18:18 +0200 Subject: [PATCH 2/2] skip WrapSystemDrawingBitmap_* on most environments to avoid sporadic test failures --- .../Image/ImageTests.WrapMemory.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 815684d84..69572425c 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -8,6 +8,7 @@ using System.Drawing.Imaging; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Shapes; @@ -102,6 +103,11 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void WrapSystemDrawingBitmap_WhenObserved() { + if (ShouldSkipBitmapTest) + { + return; + } + using (var bmp = new Bitmap(51, 23)) { using (var memoryManager = new BitmapMemoryManager(bmp)) @@ -130,6 +136,11 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void WrapSystemDrawingBitmap_WhenOwned() { + if (ShouldSkipBitmapTest) + { + return; + } + using (var bmp = new Bitmap(51, 23)) { var memoryManager = new BitmapMemoryManager(bmp); @@ -151,6 +162,9 @@ namespace SixLabors.ImageSharp.Tests bmp.Save(fn, ImageFormat.Bmp); } } + + private static bool ShouldSkipBitmapTest => + !TestEnvironment.Is64BitProcess || TestHelpers.ImageSharpBuiltAgainst != "netcoreapp2.1"; } } } \ No newline at end of file