Browse Source

Minor code refactoring to improve flexibility

js/color-alpha-handling
Sergio Pedri 5 years ago
parent
commit
bd6e555312
  1. 8
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs
  2. 8
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs
  3. 2
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
  4. 12
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionRowOperation{TPixel}.cs
  5. 23
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs
  6. 11
      src/ImageSharp/Processing/Processors/Convolution/KernelSamplingMap.cs
  7. 19
      src/ImageSharp/Processing/Processors/Convolution/ReadOnlyKernel{T}.cs

8
src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs

@ -80,8 +80,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref Vector4 targetBaseY = ref MemoryMarshal.GetReference(targetYBuffer); ref Vector4 targetBaseY = ref MemoryMarshal.GetReference(targetYBuffer);
ref Vector4 targetBaseX = ref MemoryMarshal.GetReference(targetXBuffer); ref Vector4 targetBaseX = ref MemoryMarshal.GetReference(targetXBuffer);
ReadOnlyKernel kernelY = state.KernelY; ReadOnlyKernel<float> kernelY = state.KernelY;
ReadOnlyKernel kernelX = state.KernelX; ReadOnlyKernel<float> kernelX = state.KernelX;
Span<TPixel> sourceRow; Span<TPixel> sourceRow;
for (int kY = 0; kY < kernelY.Rows; kY++) for (int kY = 0; kY < kernelY.Rows; kY++)
{ {
@ -146,8 +146,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref Vector4 targetBaseY = ref MemoryMarshal.GetReference(targetYBuffer); ref Vector4 targetBaseY = ref MemoryMarshal.GetReference(targetYBuffer);
ref Vector4 targetBaseX = ref MemoryMarshal.GetReference(targetXBuffer); ref Vector4 targetBaseX = ref MemoryMarshal.GetReference(targetXBuffer);
ReadOnlyKernel kernelY = state.KernelY; ReadOnlyKernel<float> kernelY = state.KernelY;
ReadOnlyKernel kernelX = state.KernelX; ReadOnlyKernel<float> kernelX = state.KernelX;
for (int kY = 0; kY < kernelY.Rows; kY++) for (int kY = 0; kY < kernelY.Rows; kY++)
{ {
// Get the precalculated source sample row for this kernel row and copy to our buffer. // Get the precalculated source sample row for this kernel row and copy to our buffer.

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

@ -23,21 +23,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
KernelSamplingMap map) KernelSamplingMap map)
{ {
// We check the kernels are the same size upstream. // We check the kernels are the same size upstream.
this.KernelY = new ReadOnlyKernel(kernelY); this.KernelY = new ReadOnlyKernel<float>(kernelY);
this.KernelX = new ReadOnlyKernel(kernelX); this.KernelX = new ReadOnlyKernel<float>(kernelX);
this.kernelHeight = kernelY.Rows; this.kernelHeight = kernelY.Rows;
this.kernelWidth = kernelY.Columns; this.kernelWidth = kernelY.Columns;
this.rowOffsetMap = map.GetRowOffsetSpan(); this.rowOffsetMap = map.GetRowOffsetSpan();
this.columnOffsetMap = map.GetColumnOffsetSpan(); this.columnOffsetMap = map.GetColumnOffsetSpan();
} }
public readonly ReadOnlyKernel KernelY public readonly ReadOnlyKernel<float> KernelY
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get; get;
} }
public readonly ReadOnlyKernel KernelX public readonly ReadOnlyKernel<float> KernelX
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get; get;

2
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs

@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref Vector4 targetRowRef = ref MemoryMarshal.GetReference(span); ref Vector4 targetRowRef = ref MemoryMarshal.GetReference(span);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth); Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth);
var state = new ConvolutionState(in this.kernel, this.map); var state = new ConvolutionState<float>(in this.kernel, this.map);
int row = y - this.bounds.Y; int row = y - this.bounds.Y;
ref int sampleRowBase = ref state.GetSampleRow(row); ref int sampleRowBase = ref state.GetSampleRow(row);

12
src/ImageSharp/Processing/Processors/Convolution/ConvolutionRowOperation{TPixel}.cs

@ -67,14 +67,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
Span<Vector4> sourceBuffer = span.Slice(0, this.bounds.Width); Span<Vector4> sourceBuffer = span.Slice(0, this.bounds.Width);
Span<Vector4> targetBuffer = span.Slice(this.bounds.Width); Span<Vector4> targetBuffer = span.Slice(this.bounds.Width);
var state = new ConvolutionState(in this.kernelMatrix, this.map); var state = new ConvolutionState<float>(in this.kernelMatrix, this.map);
ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y); ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y);
// Clear the target buffer for each row run. // Clear the target buffer for each row run.
targetBuffer.Clear(); targetBuffer.Clear();
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
ReadOnlyKernel kernel = state.Kernel; ReadOnlyKernel<float> kernel = state.Kernel;
Span<TPixel> sourceRow; Span<TPixel> sourceRow;
for (int kY = 0; kY < kernel.Rows; kY++) for (int kY = 0; kY < kernel.Rows; kY++)
{ {
@ -119,17 +119,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
// Span is 2x bounds. // Span is 2x bounds.
int boundsX = this.bounds.X; int boundsX = this.bounds.X;
int boundsWidth = this.bounds.Width; int boundsWidth = this.bounds.Width;
Span<Vector4> sourceBuffer = span.Slice(0, this.bounds.Width); Span<Vector4> sourceBuffer = span.Slice(0, boundsWidth);
Span<Vector4> targetBuffer = span.Slice(this.bounds.Width); Span<Vector4> targetBuffer = span.Slice(boundsWidth);
var state = new ConvolutionState(in this.kernelMatrix, this.map); var state = new ConvolutionState<float>(in this.kernelMatrix, this.map);
ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y); ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y);
// Clear the target buffer for each row run. // Clear the target buffer for each row run.
targetBuffer.Clear(); targetBuffer.Clear();
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
ReadOnlyKernel kernel = state.Kernel; ReadOnlyKernel<float> kernel = state.Kernel;
for (int kY = 0; kY < kernel.Rows; kY++) for (int kY = 0; kY < kernel.Rows; kY++)
{ {
// Get the precalculated source sample row for this kernel row and copy to our buffer. // Get the precalculated source sample row for this kernel row and copy to our buffer.

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

@ -10,7 +10,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A stack only struct used for reducing reference indirection during convolution operations. /// A stack only struct used for reducing reference indirection during convolution operations.
/// </summary> /// </summary>
internal readonly ref struct ConvolutionState /// <typeparam name="T">The type of values for the kernel in use.</typeparam>
internal readonly ref struct ConvolutionState<T>
where T : unmanaged, IEquatable<T>
{ {
private readonly Span<int> rowOffsetMap; private readonly Span<int> rowOffsetMap;
private readonly Span<int> columnOffsetMap; private readonly Span<int> columnOffsetMap;
@ -18,17 +20,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly int kernelWidth; private readonly int kernelWidth;
public ConvolutionState( public ConvolutionState(
in DenseMatrix<float> kernel, in DenseMatrix<T> kernel,
KernelSamplingMap map) KernelSamplingMap map)
{ {
this.Kernel = new ReadOnlyKernel(kernel); this.Kernel = new ReadOnlyKernel<T>(kernel);
this.kernelHeight = kernel.Rows; this.kernelHeight = kernel.Rows;
this.kernelWidth = kernel.Columns; this.kernelWidth = kernel.Columns;
this.rowOffsetMap = map.GetRowOffsetSpan(); this.rowOffsetMap = map.GetRowOffsetSpan();
this.columnOffsetMap = map.GetColumnOffsetSpan(); this.columnOffsetMap = map.GetColumnOffsetSpan();
} }
public readonly ReadOnlyKernel Kernel public ConvolutionState(
T[] kernel,
int height,
int width,
KernelSamplingMap map)
{
this.Kernel = new ReadOnlyKernel<T>(kernel, height, width);
this.kernelHeight = height;
this.kernelWidth = width;
this.rowOffsetMap = map.GetRowOffsetSpan();
this.columnOffsetMap = map.GetColumnOffsetSpan();
}
public readonly ReadOnlyKernel<T> Kernel
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get; get;

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

@ -31,9 +31,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <param name="kernel">The convolution kernel.</param> /// <param name="kernel">The convolution kernel.</param>
/// <param name="bounds">The source bounds.</param> /// <param name="bounds">The source bounds.</param>
public void BuildSamplingOffsetMap(DenseMatrix<float> kernel, Rectangle bounds) public void BuildSamplingOffsetMap(DenseMatrix<float> kernel, Rectangle bounds)
=> this.BuildSamplingOffsetMap(kernel.Rows, kernel.Columns, bounds);
/// <summary>
/// Builds a map of the sampling offsets for the kernel clamped by the given bounds.
/// </summary>
/// <param name="kernelHeight">The height (number of rows) of the convolution kernel to use.</param>
/// <param name="kernelWidth">The width (number of columns) of the convolution kernel to use.</param>
/// <param name="bounds">The source bounds.</param>
public void BuildSamplingOffsetMap(int kernelHeight, int kernelWidth, Rectangle bounds)
{ {
int kernelHeight = kernel.Rows;
int kernelWidth = kernel.Columns;
this.yOffsets = this.allocator.Allocate<int>(bounds.Height * kernelHeight); this.yOffsets = this.allocator.Allocate<int>(bounds.Height * kernelHeight);
this.xOffsets = this.allocator.Allocate<int>(bounds.Width * kernelWidth); this.xOffsets = this.allocator.Allocate<int>(bounds.Width * kernelWidth);

19
src/ImageSharp/Processing/Processors/Convolution/ReadOnlyKernel.cs → src/ImageSharp/Processing/Processors/Convolution/ReadOnlyKernel{T}.cs

@ -12,17 +12,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// A stack only, readonly, kernel matrix that can be indexed without /// A stack only, readonly, kernel matrix that can be indexed without
/// bounds checks when compiled in release mode. /// bounds checks when compiled in release mode.
/// </summary> /// </summary>
internal readonly ref struct ReadOnlyKernel /// <typeparam name="T">The type of items in the kernel.</typeparam>
internal readonly ref struct ReadOnlyKernel<T>
where T : unmanaged, IEquatable<T>
{ {
private readonly ReadOnlySpan<float> values; private readonly ReadOnlySpan<T> values;
public ReadOnlyKernel(DenseMatrix<float> matrix) public ReadOnlyKernel(DenseMatrix<T> matrix)
{ {
this.Columns = matrix.Columns; this.Columns = matrix.Columns;
this.Rows = matrix.Rows; this.Rows = matrix.Rows;
this.values = matrix.Span; this.values = matrix.Span;
} }
public ReadOnlyKernel(T[] kernel, int height, int width)
{
this.Columns = width;
this.Rows = height;
this.values = kernel;
}
public int Columns public int Columns
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -35,13 +44,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
get; get;
} }
public float this[int row, int column] public T this[int row, int column]
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get get
{ {
this.CheckCoordinates(row, column); this.CheckCoordinates(row, column);
ref float vBase = ref MemoryMarshal.GetReference(this.values); ref T vBase = ref MemoryMarshal.GetReference(this.values);
return Unsafe.Add(ref vBase, (row * this.Columns) + column); return Unsafe.Add(ref vBase, (row * this.Columns) + column);
} }
} }
Loading…
Cancel
Save