|
|
@ -68,21 +68,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|
|
this.Configuration, |
|
|
this.Configuration, |
|
|
(rows) => |
|
|
(rows) => |
|
|
{ |
|
|
{ |
|
|
// Allocate the reusable source row buffer, to enable vectorized bulk conversions
|
|
|
/* Allocate the two temporary Vector4 buffers, one for the source row and one for the target row. |
|
|
using IMemoryOwner<Vector4> sourceRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(rowWidth); |
|
|
* The ParallelHelper.IterateRowsWithTempBuffers overload is not used in this case because |
|
|
|
|
|
* the two allocated buffers have a length equal to the width of the source image, |
|
|
|
|
|
* and not just equal to the width of the target rectangle to process. |
|
|
|
|
|
* Furthermore, there are two buffers being allocated in this case, so using that overload would |
|
|
|
|
|
* have still required the explicit allocation of the secondary buffer. |
|
|
|
|
|
* Similarly, one temporary float buffer is also allocated from the pool, and that is used |
|
|
|
|
|
* to create the target bins for all the color channels being processed. |
|
|
|
|
|
* This buffer is only rented once outside of the main processing loop, and its contents |
|
|
|
|
|
* are cleared for each loop iteration, to avoid the repeated allocation for each processed pixel. */ |
|
|
|
|
|
using (IMemoryOwner<Vector4> sourceRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(rowWidth)) |
|
|
|
|
|
using (IMemoryOwner<Vector4> targetRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(rowWidth)) |
|
|
|
|
|
using (IMemoryOwner<float> bins = configuration.MemoryAllocator.Allocate<float>(levels * 4)) |
|
|
|
|
|
{ |
|
|
Span<Vector4> sourceRowVector4Span = sourceRowBuffer.Memory.Span; |
|
|
Span<Vector4> sourceRowVector4Span = sourceRowBuffer.Memory.Span; |
|
|
Span<Vector4> sourceRowAreaVector4Span = sourceRowVector4Span.Slice(startX, rectangleWidth); |
|
|
Span<Vector4> sourceRowAreaVector4Span = sourceRowVector4Span.Slice(startX, rectangleWidth); |
|
|
|
|
|
|
|
|
// Allocate the reusable target row buffer
|
|
|
|
|
|
using IMemoryOwner<Vector4> targetRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(rowWidth); |
|
|
|
|
|
|
|
|
|
|
|
Span<Vector4> targetRowVector4Span = targetRowBuffer.Memory.Span; |
|
|
Span<Vector4> targetRowVector4Span = targetRowBuffer.Memory.Span; |
|
|
Span<Vector4> targetRowAreaVector4Span = targetRowVector4Span.Slice(startX, rectangleWidth); |
|
|
Span<Vector4> targetRowAreaVector4Span = targetRowVector4Span.Slice(startX, rectangleWidth); |
|
|
|
|
|
|
|
|
// Rent the shared buffer only once per parallel item.
|
|
|
|
|
|
using IMemoryOwner<float> bins = configuration.MemoryAllocator.Allocate<float>(levels * 4); |
|
|
|
|
|
|
|
|
|
|
|
ref float binsRef = ref bins.GetReference(); |
|
|
ref float binsRef = ref bins.GetReference(); |
|
|
ref int intensityBinRef = ref Unsafe.As<float, int>(ref binsRef); |
|
|
ref int intensityBinRef = ref Unsafe.As<float, int>(ref binsRef); |
|
|
ref float redBinRef = ref Unsafe.Add(ref binsRef, levels); |
|
|
ref float redBinRef = ref Unsafe.Add(ref binsRef, levels); |
|
|
@ -152,6 +157,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|
|
|
|
|
|
|
|
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, targetRowAreaVector4Span, targetRowAreaPixelSpan); |
|
|
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, targetRowAreaVector4Span, targetRowAreaPixelSpan); |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); |
|
|
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); |
|
|
|