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();
}
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);
}
}

10
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);
}
}

12
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;

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);
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;
}
}

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 ShortClr() => this.AddJob(

2
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]

Loading…
Cancel
Save