Browse Source

Avoid per-index multiply.

js/color-alpha-handling
James Jackson-South 5 years ago
parent
commit
0f94c5ed41
  1. 12
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs
  2. 10
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs
  3. 12
      src/ImageSharp/Processing/Processors/Convolution/Convolver.cs
  4. 6
      src/ImageSharp/Processing/Processors/Convolution/KernelSamplingMap.cs
  5. 8
      tests/ImageSharp.Benchmarks/Config.cs
  6. 2
      tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs

12
src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs

@ -31,24 +31,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
this.columnOffsetMap = map.GetColumnOffsetSpan(); this.columnOffsetMap = map.GetColumnOffsetSpan();
} }
public ReadOnlyKernel KernelY public readonly ReadOnlyKernel KernelY
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get; get;
} }
public ReadOnlyKernel KernelX public readonly ReadOnlyKernel KernelX
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get; get;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetRowSampleOffset(int row, int kernelRow) public readonly ref int GetSampleOffsetRow(int row)
=> Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), (row * this.kernelHeight) + kernelRow); => ref Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), row * this.kernelHeight);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetColumnSampleOffset(int column, int kernelColumn) public readonly ref int GetSampleOffsetColumn(int column)
=> Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), (column * this.kernelWidth) + kernelColumn); => ref Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), column * this.kernelWidth);
} }
} }

10
src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs

@ -28,18 +28,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
this.columnOffsetMap = map.GetColumnOffsetSpan(); this.columnOffsetMap = map.GetColumnOffsetSpan();
} }
public ReadOnlyKernel Kernel public readonly ReadOnlyKernel Kernel
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get; get;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetRowSampleOffset(int row, int kernelRow) public readonly ref int GetSampleOffsetRow(int row)
=> Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), (row * this.kernelHeight) + kernelRow); => ref Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), row * this.kernelHeight);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetColumnSampleOffset(int column, int kernelColumn) public readonly ref int GetSampleOffsetColumn(int column)
=> Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), (column * this.kernelWidth) + kernelColumn); => ref Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), column * this.kernelWidth);
} }
} }

12
src/ImageSharp/Processing/Processors/Convolution/Convolver.cs

@ -100,14 +100,16 @@ namespace SixLabors.ImageSharp
Vector4 vectorY = default; Vector4 vectorY = default;
Vector4 vectorX = default; Vector4 vectorX = default;
ref int sampleOffsetRowBase = ref state.GetSampleOffsetRow(row);
for (int y = 0; y < kernelHeight; y++) 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 TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourcePixels.GetRowSpan(offsetY));
ref int sampleOffsetColumnBase = ref state.GetSampleOffsetColumn(column);
for (int x = 0; x < kernelWidth; x++) 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(); var sample = Unsafe.Add(ref sourceRowBase, offsetX).ToVector4();
Numerics.Premultiply(ref sample); Numerics.Premultiply(ref sample);
vectorX += kernelX[y, x] * sample; vectorX += kernelX[y, x] * sample;
@ -199,14 +201,16 @@ namespace SixLabors.ImageSharp
int kernelHeight = kernel.Rows; int kernelHeight = kernel.Rows;
int kernelWidth = kernel.Columns; int kernelWidth = kernel.Columns;
ref int sampleOffsetRowBase = ref state.GetSampleOffsetRow(row);
for (int y = 0; y < kernelHeight; y++) 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 TPixel sourceRowBase = ref MemoryMarshal.GetReference(sourcePixels.GetRowSpan(offsetY));
ref int sampleOffsetColumnBase = ref state.GetSampleOffsetColumn(column);
for (int x = 0; x < kernelWidth; x++) 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(); var sample = Unsafe.Add(ref sourceRowBase, offsetX).ToVector4();
Numerics.Premultiply(ref sample); Numerics.Premultiply(ref sample);
targetVector += kernel[y, x] * sample; targetVector += kernel[y, x] * sample;

6
src/ImageSharp/Processing/Processors/Convolution/KernelSamplingMap.cs

@ -52,9 +52,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref int ySpanBase = ref MemoryMarshal.GetReference(ySpan); ref int ySpanBase = ref MemoryMarshal.GetReference(ySpan);
for (int row = 0; row < bounds.Height; row++) for (int row = 0; row < bounds.Height; row++)
{ {
int rowBase = row * kernelHeight;
for (int y = 0; y < kernelHeight; y++) 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); ref int xSpanBase = ref MemoryMarshal.GetReference(xSpan);
for (int column = 0; column < bounds.Width; column++) for (int column = 0; column < bounds.Width; column++)
{ {
int columnBase = column * kernelWidth;
for (int x = 0; x < kernelWidth; x++) 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;
} }
} }

8
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 class ShortClr : Config
{ {
public ShortClr() => this.AddJob( public ShortClr() => this.AddJob(

2
tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Samplers namespace SixLabors.ImageSharp.Benchmarks.Samplers
{ {
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.MultiFramework))]
public class GaussianBlur public class GaussianBlur
{ {
[Benchmark] [Benchmark]

Loading…
Cancel
Save