From 1042a97b72bb3676af2afdb7a512545f796fc9fe Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 18 Mar 2017 20:16:17 +0100 Subject: [PATCH] improved, sequential ResizeProcessor --- .../Common/Memory/PinnedImageBuffer{T}.cs | 9 +- .../ResamplingWeightedProcessor.Weights.cs | 19 +++- .../Processors/Transforms/ResizeProcessor.cs | 104 ++++++++---------- tests/ImageSharp.Sandbox46/Program.cs | 9 +- .../Processors/Filters/ResizeTests.cs | 2 +- 5 files changed, 76 insertions(+), 67 deletions(-) diff --git a/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs index 380545d70..3ff174c5d 100644 --- a/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs @@ -53,7 +53,14 @@ namespace ImageSharp /// The x coordinate (row) /// The y coordinate (position at row) /// A reference to the element. - public ref T this[int x, int y] => ref this.Array[(this.Width * y) + x]; + public ref T this[int x, int y] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return ref this.Array[(this.Width * y) + x]; + } + } /// /// Creates a clean instance of initializing it's elements with 'default(T)'. diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs index c7386487a..785a1f20c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs @@ -51,19 +51,22 @@ namespace ImageSharp.Processing.Processors /// /// The input span of vectors /// The weighted sum + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ComputeWeightedRowSum(BufferSpan rowSpan) { float* horizontalValues = this.Ptr; int left = this.Left; + Vector4* vecPtr = (Vector4*)rowSpan.PointerAtOffset; + vecPtr += left; // Destination color components Vector4 result = Vector4.Zero; for (int i = 0; i < this.Length; i++) { - float xw = horizontalValues[i]; - int index = left + i; - result += rowSpan[index] * xw; + float weight = horizontalValues[i]; + result += (*vecPtr) * weight; + vecPtr++; } return result; @@ -75,19 +78,22 @@ namespace ImageSharp.Processing.Processors /// /// The input span of vectors /// The weighted sum + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ComputeExpandedWeightedRowSum(BufferSpan rowSpan) { float* horizontalValues = this.Ptr; int left = this.Left; + Vector4* vecPtr = (Vector4*)rowSpan.PointerAtOffset; + vecPtr += left; // Destination color components Vector4 result = Vector4.Zero; for (int i = 0; i < this.Length; i++) { - float xw = horizontalValues[i]; - int index = left + i; - result += rowSpan[index].Expand() * xw; + float weight = horizontalValues[i]; + result += (*vecPtr).Expand() * weight; + vecPtr++; } return result; @@ -100,6 +106,7 @@ namespace ImageSharp.Processing.Processors /// The buffer of input vectors in row first order /// The column position /// The weighted sum + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ComputeWeightedColumnSum(PinnedImageBuffer firstPassPixels, int x) { float* verticalValues = this.Ptr; diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 944e245ac..0e1a215e0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -110,76 +110,64 @@ namespace ImageSharp.Processing.Processors { firstPassPixels.Clear(); - Parallel.For( - 0, - sourceRectangle.Bottom, - this.ParallelOptions, - y => - { - // TODO: Without Parallel.For() this buffer object could be reused: - using (PinnedBuffer tempRowBuffer = new PinnedBuffer(sourcePixels.Width)) - { - BufferSpan sourceRow = sourcePixels.GetRowSpan(y); - - BulkPixelOperations.Instance.ToVector4( - sourceRow, - tempRowBuffer, - sourceRow.Length); - - if (this.Compand) - { - for (int x = minX; x < maxX; x++) - { - WeightsWindow window = this.HorizontalWeights.Weights[x - startX]; - firstPassPixels[x, y] = window.ComputeExpandedWeightedRowSum(tempRowBuffer); - } - } - else - { - for (int x = minX; x < maxX; x++) - { - WeightsWindow window = this.HorizontalWeights.Weights[x - startX]; - firstPassPixels[x, y] = window.ComputeWeightedRowSum(tempRowBuffer); - } - } - } - }); - - // Now process the rows. - Parallel.For( - minY, - maxY, - this.ParallelOptions, - y => + using (PinnedBuffer tempRowBuffer = new PinnedBuffer(sourcePixels.Width)) + { + for (int y = 0; y < sourceRectangle.Bottom; y++) { - // Ensure offsets are normalised for cropping and padding. - WeightsWindow window = this.VerticalWeights.Weights[y - startY]; + BufferSpan sourceRow = sourcePixels.GetRowSpan(y); + + BulkPixelOperations.Instance.ToVector4(sourceRow, tempRowBuffer, sourceRow.Length); if (this.Compand) { - for (int x = 0; x < width; x++) + for (int x = minX; x < maxX; x++) { - // Destination color components - Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x); - destination = destination.Compress(); - TColor d = default(TColor); - d.PackFromVector4(destination); - targetPixels[x, y] = d; + WeightsWindow window = this.HorizontalWeights.Weights[x - startX]; + firstPassPixels[x, y] = window.ComputeExpandedWeightedRowSum(tempRowBuffer); } } else { - for (int x = 0; x < width; x++) + for (int x = minX; x < maxX; x++) { - // Destination color components - Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x); - - TColor d = default(TColor); - d.PackFromVector4(destination); - targetPixels[x, y] = d; + WeightsWindow window = this.HorizontalWeights.Weights[x - startX]; + firstPassPixels[x, y] = window.ComputeWeightedRowSum(tempRowBuffer); } } - }); + } + } + + // Now process the rows. + for (int y = minY; y < maxY; y++) + { + // Ensure offsets are normalised for cropping and padding. + WeightsWindow window = this.VerticalWeights.Weights[y - startY]; + + if (this.Compand) + { + for (int x = 0; x < width; x++) + { + // Destination color components + Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x); + destination = destination.Compress(); + TColor d = default(TColor); + d.PackFromVector4(destination); + targetPixels[x, y] = d; + } + } + else + { + for (int x = 0; x < width; x++) + { + // Destination color components + Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x); + + TColor d = default(TColor); + d.PackFromVector4(destination); + targetPixels[x, y] = d; + } + } + } } source.SwapPixelsBuffers(targetPixels); diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 467663a53..dad603523 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -38,12 +38,19 @@ namespace ImageSharp.Sandbox46 public static void Main(string[] args) { // RunDecodeJpegProfilingTests(); + // RunToVector4ProfilingTest(); - RunToVector4ProfilingTest(); + RunResizeProfilingTest(); Console.ReadLine(); } + private static void RunResizeProfilingTest() + { + ResizeProfilingBenchmarks test = new ResizeProfilingBenchmarks(new ConsoleOutput()); + test.ResizeBicubic(2000, 2000); + } + private static void RunToVector4ProfilingTest() { BulkPixelOperationsTests.Color tests = new BulkPixelOperationsTests.Color(new ConsoleOutput()); diff --git a/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs b/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs index 35994e028..a95b196b7 100644 --- a/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs @@ -21,7 +21,7 @@ namespace ImageSharp.Tests [Theory] [InlineData(100, 100)] - [InlineData(1000, 1000)] + [InlineData(2000, 2000)] public void ResizeBicubic(int width, int height) { this.Measure(this.ExecutionCount,