From 0f94c5ed41c32ef7409762dca1d34714af1c82a3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 6 Dec 2020 13:54:23 +0000 Subject: [PATCH] Avoid per-index multiply. --- .../Processors/Convolution/Convolution2DState.cs | 12 ++++++------ .../Processors/Convolution/ConvolutionState.cs | 10 +++++----- .../Processing/Processors/Convolution/Convolver.cs | 12 ++++++++---- .../Processors/Convolution/KernelSamplingMap.cs | 6 ++++-- tests/ImageSharp.Benchmarks/Config.cs | 8 ++++++++ tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs | 2 +- 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs index e36d458a4a..9d17ebab05 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs @@ -31,24 +31,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution this.columnOffsetMap = map.GetColumnOffsetSpan(); } - public ReadOnlyKernel KernelY + public readonly ReadOnlyKernel KernelY { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; } - public ReadOnlyKernel KernelX + public readonly ReadOnlyKernel KernelX { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetRowSampleOffset(int row, int kernelRow) - => Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), (row * this.kernelHeight) + kernelRow); + public readonly ref int GetSampleOffsetRow(int row) + => ref Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), row * this.kernelHeight); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetColumnSampleOffset(int column, int kernelColumn) - => Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), (column * this.kernelWidth) + kernelColumn); + public readonly ref int GetSampleOffsetColumn(int column) + => ref Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), column * this.kernelWidth); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs index 97a3af342e..851eeec247 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs @@ -28,18 +28,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution this.columnOffsetMap = map.GetColumnOffsetSpan(); } - public ReadOnlyKernel Kernel + public readonly ReadOnlyKernel Kernel { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetRowSampleOffset(int row, int kernelRow) - => Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), (row * this.kernelHeight) + kernelRow); + public readonly ref int GetSampleOffsetRow(int row) + => ref Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), row * this.kernelHeight); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetColumnSampleOffset(int column, int kernelColumn) - => Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), (column * this.kernelWidth) + kernelColumn); + public readonly ref int GetSampleOffsetColumn(int column) + => ref Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), column * this.kernelWidth); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolver.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolver.cs index 5ddc8e85c6..c23b71b330 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolver.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolver.cs @@ -100,14 +100,16 @@ namespace SixLabors.ImageSharp Vector4 vectorY = default; Vector4 vectorX = default; + ref int sampleOffsetRowBase = ref state.GetSampleOffsetRow(row); for (int y = 0; y < kernelHeight; y++) { - int offsetY = state.GetRowSampleOffset(row, y); + int offsetY = Unsafe.Add(ref sampleOffsetRowBase, y); ref TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourcePixels.GetRowSpan(offsetY)); + ref int sampleOffsetColumnBase = ref state.GetSampleOffsetColumn(column); for (int x = 0; x < kernelWidth; x++) { - int offsetX = state.GetColumnSampleOffset(column, x); + int offsetX = Unsafe.Add(ref sampleOffsetColumnBase, x); var sample = Unsafe.Add(ref sourceRowBase, offsetX).ToVector4(); Numerics.Premultiply(ref sample); vectorX += kernelX[y, x] * sample; @@ -199,14 +201,16 @@ namespace SixLabors.ImageSharp int kernelHeight = kernel.Rows; int kernelWidth = kernel.Columns; + ref int sampleOffsetRowBase = ref state.GetSampleOffsetRow(row); for (int y = 0; y < kernelHeight; y++) { - int offsetY = state.GetRowSampleOffset(row, y); + int offsetY = Unsafe.Add(ref sampleOffsetRowBase, y); ref TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourcePixels.GetRowSpan(offsetY)); + ref int sampleOffsetColumnBase = ref state.GetSampleOffsetColumn(column); for (int x = 0; x < kernelWidth; x++) { - int offsetX = state.GetColumnSampleOffset(column, x); + int offsetX = Unsafe.Add(ref sampleOffsetColumnBase, x); var sample = Unsafe.Add(ref sourceRowBase, offsetX).ToVector4(); Numerics.Premultiply(ref sample); targetVector += kernel[y, x] * sample; diff --git a/src/ImageSharp/Processing/Processors/Convolution/KernelSamplingMap.cs b/src/ImageSharp/Processing/Processors/Convolution/KernelSamplingMap.cs index 144d356c6e..e4b7dbea09 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KernelSamplingMap.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KernelSamplingMap.cs @@ -52,9 +52,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ref int ySpanBase = ref MemoryMarshal.GetReference(ySpan); for (int row = 0; row < bounds.Height; row++) { + int rowBase = row * kernelHeight; for (int y = 0; y < kernelHeight; y++) { - Unsafe.Add(ref ySpanBase, (row * kernelHeight) + y) = row + y + minY - radiusY; + Unsafe.Add(ref ySpanBase, rowBase + y) = row + y + minY - radiusY; } } @@ -67,9 +68,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ref int xSpanBase = ref MemoryMarshal.GetReference(xSpan); for (int column = 0; column < bounds.Width; column++) { + int columnBase = column * kernelWidth; for (int x = 0; x < kernelWidth; x++) { - Unsafe.Add(ref xSpanBase, (column * kernelWidth) + x) = column + x + minX - radiusX; + Unsafe.Add(ref xSpanBase, columnBase + x) = column + x + minX - radiusX; } } diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index 4c9f6c06db..d08e2f2d66 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -27,6 +27,14 @@ namespace SixLabors.ImageSharp.Benchmarks } + public class MultiFramework : Config + { + public MultiFramework() => this.AddJob( + Job.Default.WithRuntime(ClrRuntime.Net472), + Job.Default.WithRuntime(CoreRuntime.Core21), + Job.Default.WithRuntime(CoreRuntime.Core31)); + } + public class ShortClr : Config { public ShortClr() => this.AddJob( diff --git a/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs b/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs index 62d5806037..8f009e58f1 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Benchmarks.Samplers { - [Config(typeof(Config.ShortClr))] + [Config(typeof(Config.MultiFramework))] public class GaussianBlur { [Benchmark]