Browse Source

More performance improvements to 2 pass convolution

js/color-alpha-handling
Sergio Pedri 5 years ago
parent
commit
ff86b651d2
  1. 116
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs

116
src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs

@ -161,24 +161,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer); ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetStart = ref MemoryMarshal.GetReference(targetBuffer);
ref Vector4 targetEnd = ref Unsafe.Add(ref targetStart, sourceBuffer.Length);
ref float kernelBase = ref this.kernel[0]; ref float kernelBase = ref this.kernel[0];
ref float kernelEnd = ref Unsafe.Add(ref kernelBase, kernelSize);
ref int sampleColumnBase = ref MemoryMarshal.GetReference(this.map.GetColumnOffsetSpan()); ref int sampleColumnBase = ref MemoryMarshal.GetReference(this.map.GetColumnOffsetSpan());
for (int x = 0; x < sourceBuffer.Length; x++) while (Unsafe.IsAddressLessThan(ref targetStart, ref targetEnd))
{ {
ref Vector4 target = ref Unsafe.Add(ref targetBase, x); ref float kernelStart = ref kernelBase;
ref int sampleColumnStart = ref sampleColumnBase;
for (int kX = 0; kX < kernelSize; kX++) while (Unsafe.IsAddressLessThan(ref kernelStart, ref kernelEnd))
{ {
int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; Vector4 sample = Unsafe.Add(ref sourceBase, sampleColumnStart - boundsX);
Vector4 sample = Unsafe.Add(ref sourceBase, sampleX);
float factor = Unsafe.Add(ref kernelBase, kX); targetStart += kernelStart * sample;
target += factor * sample; kernelStart = ref Unsafe.Add(ref kernelStart, 1);
sampleColumnStart = ref Unsafe.Add(ref sampleColumnStart, 1);
} }
// Shift the base column sampling reference by one row targetStart = ref Unsafe.Add(ref targetStart, 1);
sampleColumnBase = ref Unsafe.Add(ref sampleColumnBase, kernelSize); sampleColumnBase = ref Unsafe.Add(ref sampleColumnBase, kernelSize);
} }
@ -186,10 +190,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
sourceRow = this.sourcePixels.GetRowSpan(y).Slice(boundsX, boundsWidth); sourceRow = this.sourcePixels.GetRowSpan(y).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
for (int x = 0; x < sourceRow.Length; x++) targetStart = ref MemoryMarshal.GetReference(targetBuffer);
while (Unsafe.IsAddressLessThan(ref targetStart, ref targetEnd))
{ {
ref Vector4 target = ref Unsafe.Add(ref targetBase, x); targetStart.W = sourceBase.W;
target.W = Unsafe.Add(ref MemoryMarshal.GetReference(sourceBuffer), x).W;
targetStart = ref Unsafe.Add(ref targetStart, 1);
sourceBase = ref Unsafe.Add(ref sourceBase, 1);
} }
Span<TPixel> targetRow = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth); Span<TPixel> targetRow = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth);
@ -217,23 +225,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
Numerics.Premultiply(sourceBuffer); Numerics.Premultiply(sourceBuffer);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer); ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetStart = ref MemoryMarshal.GetReference(targetBuffer);
ref Vector4 targetEnd = ref Unsafe.Add(ref targetStart, sourceBuffer.Length);
ref float kernelBase = ref this.kernel[0]; ref float kernelBase = ref this.kernel[0];
ref float kernelEnd = ref Unsafe.Add(ref kernelBase, kernelSize);
ref int sampleColumnBase = ref MemoryMarshal.GetReference(this.map.GetColumnOffsetSpan()); ref int sampleColumnBase = ref MemoryMarshal.GetReference(this.map.GetColumnOffsetSpan());
for (int x = 0; x < sourceBuffer.Length; x++) while (Unsafe.IsAddressLessThan(ref targetStart, ref targetEnd))
{ {
ref Vector4 target = ref Unsafe.Add(ref targetBase, x); ref float kernelStart = ref kernelBase;
ref int sampleColumnStart = ref sampleColumnBase;
for (int kX = 0; kX < kernelSize; kX++) while (Unsafe.IsAddressLessThan(ref kernelStart, ref kernelEnd))
{ {
int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX; Vector4 sample = Unsafe.Add(ref sourceBase, sampleColumnStart - boundsX);
Vector4 sample = Unsafe.Add(ref sourceBase, sampleX);
float factor = Unsafe.Add(ref kernelBase, kX);
target += factor * sample; targetStart += kernelStart * sample;
kernelStart = ref Unsafe.Add(ref kernelStart, 1);
sampleColumnStart = ref Unsafe.Add(ref sampleColumnStart, 1);
} }
targetStart = ref Unsafe.Add(ref targetStart, 1);
sampleColumnBase = ref Unsafe.Add(ref sampleColumnBase, kernelSize); sampleColumnBase = ref Unsafe.Add(ref sampleColumnBase, kernelSize);
} }
@ -307,37 +320,48 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
targetBuffer.Clear(); targetBuffer.Clear();
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
ref float kernelBase = ref this.kernel[0]; ref float kernelStart = ref this.kernel[0];
ref float kernelEnd = ref Unsafe.Add(ref kernelStart, kernelSize);
Span<TPixel> sourceRow; Span<TPixel> sourceRow;
for (int kY = 0; kY < kernelSize; kY++) while (Unsafe.IsAddressLessThan(ref kernelStart, ref kernelEnd))
{ {
// 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.
int sampleY = Unsafe.Add(ref sampleRowBase, kY); sourceRow = this.sourcePixels.GetRowSpan(sampleRowBase).Slice(boundsX, boundsWidth);
sourceRow = this.sourcePixels.GetRowSpan(sampleY).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer); ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
float factor = Unsafe.Add(ref kernelBase, kY); ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceBase, sourceBuffer.Length);
ref Vector4 targetStart = ref targetBase;
float factor = kernelStart;
for (int x = 0; x < sourceBuffer.Length; x++) while (Unsafe.IsAddressLessThan(ref sourceBase, ref sourceEnd))
{ {
ref Vector4 target = ref Unsafe.Add(ref targetBase, x); targetStart += factor * sourceBase;
Vector4 sample = Unsafe.Add(ref sourceBase, x);
target += factor * sample; sourceBase = ref Unsafe.Add(ref sourceBase, 1);
targetStart = ref Unsafe.Add(ref targetStart, 1);
} }
kernelStart = ref Unsafe.Add(ref kernelStart, 1);
sampleRowBase = ref Unsafe.Add(ref sampleRowBase, 1);
} }
// Now we need to copy the original alpha values from the source row. // Now we need to copy the original alpha values from the source row.
sourceRow = this.sourcePixels.GetRowSpan(y).Slice(boundsX, boundsWidth); sourceRow = this.sourcePixels.GetRowSpan(y).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
for (int x = 0; x < sourceRow.Length; x++)
{ {
ref Vector4 target = ref Unsafe.Add(ref targetBase, x); ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
target.W = Unsafe.Add(ref MemoryMarshal.GetReference(sourceBuffer), x).W; ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceBase, sourceBuffer.Length);
while (Unsafe.IsAddressLessThan(ref sourceBase, ref sourceEnd))
{
targetBase.W = sourceBase.W;
targetBase = ref Unsafe.Add(ref targetBase, 1);
sourceBase = ref Unsafe.Add(ref sourceBase, 1);
}
} }
Span<TPixel> targetRow = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth); Span<TPixel> targetRow = this.targetPixels.GetRowSpan(y).Slice(boundsX, boundsWidth);
@ -361,28 +385,32 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
targetBuffer.Clear(); targetBuffer.Clear();
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
ref float kernelBase = ref this.kernel[0]; ref float kernelStart = ref this.kernel[0];
ref float kernelEnd = ref Unsafe.Add(ref kernelStart, kernelSize);
for (int kY = 0; kY < kernelSize; kY++) Span<TPixel> sourceRow;
while (Unsafe.IsAddressLessThan(ref kernelStart, ref kernelEnd))
{ {
// 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.
int sampleY = Unsafe.Add(ref sampleRowBase, kY); sourceRow = this.sourcePixels.GetRowSpan(sampleRowBase).Slice(boundsX, boundsWidth);
Span<TPixel> sourceRow = this.sourcePixels.GetRowSpan(sampleY).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
Numerics.Premultiply(sourceBuffer);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer); ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
float factor = Unsafe.Add(ref kernelBase, kY); ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceBase, sourceBuffer.Length);
ref Vector4 targetStart = ref targetBase;
float factor = kernelStart;
for (int x = 0; x < sourceBuffer.Length; x++) while (Unsafe.IsAddressLessThan(ref sourceBase, ref sourceEnd))
{ {
ref Vector4 target = ref Unsafe.Add(ref targetBase, x); targetStart += factor * sourceBase;
Vector4 sample = Unsafe.Add(ref sourceBase, x);
target += factor * sample; sourceBase = ref Unsafe.Add(ref sourceBase, 1);
targetStart = ref Unsafe.Add(ref targetStart, 1);
} }
kernelStart = ref Unsafe.Add(ref kernelStart, 1);
sampleRowBase = ref Unsafe.Add(ref sampleRowBase, 1);
} }
Numerics.UnPremultiply(targetBuffer); Numerics.UnPremultiply(targetBuffer);

Loading…
Cancel
Save