Browse Source

refactor

- ResizeWindow -> ResizeWorker
- Most logic moved to ResizeWorker
af/merge-core
Anton Firszov 7 years ago
parent
commit
ec1971435b
  1. 42
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs
  2. 72
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

42
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs

@ -237,11 +237,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
BufferArea<TPixel> sourceArea = source.PixelBuffer.GetArea(sourceRectangle); BufferArea<TPixel> sourceArea = source.PixelBuffer.GetArea(sourceRectangle);
// Interpolate the image using the calculated weights. // If we want to reintroduce processing:
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm // it's possible to launch multiple workers for different regions of the image
// First process the columns. Since we are not using multiple threads startY and endY using (var worker = new ResizeWorker<TPixel>(
// are the upper and lower bounds of the source rectangle.
using (var resizeWindow = new ResizeWindow<TPixel>(
configuration, configuration,
sourceArea, sourceArea,
conversionModifiers, conversionModifiers,
@ -250,39 +248,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
width, width,
destWorkingRect, destWorkingRect,
startX)) startX))
using (IMemoryOwner<Vector4> tempBuffer = source.MemoryAllocator.Allocate<Vector4>(width))
{ {
resizeWindow.Initialize(); worker.Initialize();
worker.FillDestinationPixels(destWorkingRect.Top, destWorkingRect.Bottom, startY, destination.PixelBuffer);
// Now process the rows.
Span<Vector4> tempColSpan = tempBuffer.GetSpan();
for (int y = destWorkingRect.Top; y < destWorkingRect.Bottom; y++)
{
// Ensure offsets are normalized for cropping and padding.
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY);
while (kernel.StartIndex + kernel.Length > resizeWindow.Bottom)
{
resizeWindow.Slide();
}
ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan);
int top = kernel.StartIndex - resizeWindow.Top;
for (int x = 0; x < width; x++)
{
Span<Vector4> firstPassColumn = resizeWindow.GetColumnSpan(x).Slice(top);
// Destination color components
Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(firstPassColumn);
}
Span<TPixel> targetRowSpan = destination.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, tempColSpan, targetRowSpan, conversionModifiers);
}
} }
} }

72
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs → src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -5,6 +5,7 @@ using System;
using System.Buffers; using System.Buffers;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -13,7 +14,7 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{ {
internal class ResizeWindow<TPixel> : IDisposable internal class ResizeWorker<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private readonly Buffer2D<Vector4> buffer; private readonly Buffer2D<Vector4> buffer;
@ -32,15 +33,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly IMemoryOwner<Vector4> tempRowBuffer; private readonly IMemoryOwner<Vector4> tempRowBuffer;
private readonly IMemoryOwner<Vector4> tempColumnBuffer;
private readonly ResizeKernelMap verticalKernelMap; private readonly ResizeKernelMap verticalKernelMap;
private readonly int destWidth;
private readonly Rectangle destWorkingRect; private readonly Rectangle destWorkingRect;
private readonly int diameter; private readonly int diameter;
private readonly int windowHeight; private readonly int windowHeight;
public ResizeWindow( public ResizeWorker(
Configuration configuration, Configuration configuration,
BufferArea<TPixel> source, BufferArea<TPixel> source,
PixelConversionModifiers conversionModifiers, PixelConversionModifiers conversionModifiers,
@ -56,6 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.conversionModifiers = conversionModifiers; this.conversionModifiers = conversionModifiers;
this.horizontalKernelMap = horizontalKernelMap; this.horizontalKernelMap = horizontalKernelMap;
this.verticalKernelMap = verticalKernelMap; this.verticalKernelMap = verticalKernelMap;
this.destWidth = destWidth;
this.destWorkingRect = destWorkingRect; this.destWorkingRect = destWorkingRect;
this.startX = startX; this.startX = startX;
@ -67,22 +73,29 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.windowHeight, this.windowHeight,
destWidth, destWidth,
AllocationOptions.Clean); AllocationOptions.Clean);
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width); this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width);
this.tempColumnBuffer = configuration.MemoryAllocator.Allocate<Vector4>(destWidth);
this.CurrentMinY = 0;
this.CurrentMaxY = this.windowHeight;
} }
public int Bottom { get; private set; } public int CurrentMaxY { get; private set; }
public int Top { get; private set; } public int CurrentMinY { get; private set; }
public void Dispose() public void Dispose()
{ {
this.buffer.Dispose(); this.buffer.Dispose();
this.tempRowBuffer.Dispose();
this.tempColumnBuffer.Dispose();
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> GetColumnSpan(int x, int startY) public Span<Vector4> GetColumnSpan(int x, int startY)
{ {
return this.buffer.GetRowSpan(x).Slice(startY - this.Top); return this.buffer.GetRowSpan(x).Slice(startY - this.CurrentMinY);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -93,23 +106,52 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public void Initialize() public void Initialize()
{ {
this.Initialize(0, this.windowHeight); this.CalculateFirstPassValues(0, this.windowHeight);
} }
public void Slide() public void FillDestinationPixels(int minY, int maxY, int startY, Buffer2D<TPixel> destination)
{ {
int top = this.Top + this.diameter; Span<Vector4> tempColSpan = this.tempColumnBuffer.GetSpan();
int bottom = Math.Min(this.Bottom + this.diameter, this.sourceRectangle.Height);
this.Initialize(top, bottom); for (int y = minY; y < maxY; y++)
{
// Ensure offsets are normalized for cropping and padding.
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY);
while (kernel.StartIndex + kernel.Length > this.CurrentMaxY)
{
this.Slide();
}
ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan);
int top = kernel.StartIndex - this.CurrentMinY;
for (int x = 0; x < this.destWidth; x++)
{
Span<Vector4> firstPassColumn = this.GetColumnSpan(x).Slice(top);
// Destination color components
Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(firstPassColumn);
}
Span<TPixel> targetRowSpan = destination.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, tempColSpan, targetRowSpan, conversionModifiers);
}
} }
private void Initialize(int top, int bottom) public void Slide()
{ {
this.Top = top; this.CurrentMinY = this.CurrentMinY + this.diameter;
this.Bottom = bottom; this.CurrentMaxY = Math.Min(this.CurrentMaxY + this.diameter, this.sourceRectangle.Height);
this.CalculateFirstPassValues(this.CurrentMinY, this.CurrentMaxY);
}
private void CalculateFirstPassValues(int minY, int maxY)
{
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan(); Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
for (int y = top; y < bottom; y++) for (int y = minY; y < maxY; y++)
{ {
Span<TPixel> sourceRow = this.source.GetRowSpan(y); Span<TPixel> sourceRow = this.source.GetRowSpan(y);
@ -120,7 +162,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.conversionModifiers); this.conversionModifiers);
//ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top]; //ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top];
Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - top); Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - minY);
for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++) for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++)
{ {
Loading…
Cancel
Save