Browse Source

Removed using statements, added detailed comment

af/octree-no-pixelmap
Sergio Pedri 6 years ago
parent
commit
b048dacaa7
  1. 130
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs

130
src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs

@ -68,89 +68,95 @@ 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,
Span<Vector4> sourceRowVector4Span = sourceRowBuffer.Memory.Span; * and not just equal to the width of the target rectangle to process.
Span<Vector4> sourceRowAreaVector4Span = sourceRowVector4Span.Slice(startX, rectangleWidth); * 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.
// Allocate the reusable target row buffer * Similarly, one temporary float buffer is also allocated from the pool, and that is used
using IMemoryOwner<Vector4> targetRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(rowWidth); * 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
Span<Vector4> targetRowVector4Span = targetRowBuffer.Memory.Span; * are cleared for each loop iteration, to avoid the repeated allocation for each processed pixel. */
Span<Vector4> targetRowAreaVector4Span = targetRowVector4Span.Slice(startX, rectangleWidth); using (IMemoryOwner<Vector4> sourceRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(rowWidth))
using (IMemoryOwner<Vector4> targetRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(rowWidth))
// Rent the shared buffer only once per parallel item. using (IMemoryOwner<float> bins = configuration.MemoryAllocator.Allocate<float>(levels * 4))
using IMemoryOwner<float> bins = configuration.MemoryAllocator.Allocate<float>(levels * 4);
ref float binsRef = ref bins.GetReference();
ref int intensityBinRef = ref Unsafe.As<float, int>(ref binsRef);
ref float redBinRef = ref Unsafe.Add(ref binsRef, levels);
ref float blueBinRef = ref Unsafe.Add(ref redBinRef, levels);
ref float greenBinRef = ref Unsafe.Add(ref blueBinRef, levels);
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> sourceRowPixelSpan = source.GetPixelRowSpan(y); Span<Vector4> sourceRowVector4Span = sourceRowBuffer.Memory.Span;
Span<TPixel> sourceRowAreaPixelSpan = sourceRowPixelSpan.Slice(startX, rectangleWidth); Span<Vector4> sourceRowAreaVector4Span = sourceRowVector4Span.Slice(startX, rectangleWidth);
Span<Vector4> targetRowVector4Span = targetRowBuffer.Memory.Span;
Span<Vector4> targetRowAreaVector4Span = targetRowVector4Span.Slice(startX, rectangleWidth);
PixelOperations<TPixel>.Instance.ToVector4(configuration, sourceRowAreaPixelSpan, sourceRowAreaVector4Span); ref float binsRef = ref bins.GetReference();
ref int intensityBinRef = ref Unsafe.As<float, int>(ref binsRef);
ref float redBinRef = ref Unsafe.Add(ref binsRef, levels);
ref float blueBinRef = ref Unsafe.Add(ref redBinRef, levels);
ref float greenBinRef = ref Unsafe.Add(ref blueBinRef, levels);
for (int x = startX; x < endX; x++) for (int y = rows.Min; y < rows.Max; y++)
{ {
int maxIntensity = 0; Span<TPixel> sourceRowPixelSpan = source.GetPixelRowSpan(y);
int maxIndex = 0; Span<TPixel> sourceRowAreaPixelSpan = sourceRowPixelSpan.Slice(startX, rectangleWidth);
// Clear the current shared buffer before processing each target pixel PixelOperations<TPixel>.Instance.ToVector4(configuration, sourceRowAreaPixelSpan, sourceRowAreaVector4Span);
bins.Memory.Span.Clear();
for (int fy = 0; fy <= radius; fy++) for (int x = startX; x < endX; x++)
{ {
int fyr = fy - radius; int maxIntensity = 0;
int offsetY = y + fyr; int maxIndex = 0;
offsetY = offsetY.Clamp(0, maxY); // Clear the current shared buffer before processing each target pixel
bins.Memory.Span.Clear();
Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); for (int fy = 0; fy <= radius; fy++)
for (int fx = 0; fx <= radius; fx++)
{ {
int fxr = fx - radius; int fyr = fy - radius;
int offsetX = x + fxr; int offsetY = y + fyr;
offsetX = offsetX.Clamp(0, maxX);
var vector = sourceOffsetRow[offsetX].ToVector4(); offsetY = offsetY.Clamp(0, maxY);
float sourceRed = vector.X; Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY);
float sourceBlue = vector.Z;
float sourceGreen = vector.Y;
int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); for (int fx = 0; fx <= radius; fx++)
{
int fxr = fx - radius;
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
Unsafe.Add(ref intensityBinRef, currentIntensity)++; var vector = sourceOffsetRow[offsetX].ToVector4();
Unsafe.Add(ref redBinRef, currentIntensity) += sourceRed;
Unsafe.Add(ref blueBinRef, currentIntensity) += sourceBlue;
Unsafe.Add(ref greenBinRef, currentIntensity) += sourceGreen;
if (Unsafe.Add(ref intensityBinRef, currentIntensity) > maxIntensity) float sourceRed = vector.X;
{ float sourceBlue = vector.Z;
maxIntensity = Unsafe.Add(ref intensityBinRef, currentIntensity); float sourceGreen = vector.Y;
maxIndex = currentIntensity;
int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1));
Unsafe.Add(ref intensityBinRef, currentIntensity)++;
Unsafe.Add(ref redBinRef, currentIntensity) += sourceRed;
Unsafe.Add(ref blueBinRef, currentIntensity) += sourceBlue;
Unsafe.Add(ref greenBinRef, currentIntensity) += sourceGreen;
if (Unsafe.Add(ref intensityBinRef, currentIntensity) > maxIntensity)
{
maxIntensity = Unsafe.Add(ref intensityBinRef, currentIntensity);
maxIndex = currentIntensity;
}
} }
}
float red = MathF.Abs(Unsafe.Add(ref redBinRef, maxIndex) / maxIntensity); float red = MathF.Abs(Unsafe.Add(ref redBinRef, maxIndex) / maxIntensity);
float blue = MathF.Abs(Unsafe.Add(ref blueBinRef, maxIndex) / maxIntensity); float blue = MathF.Abs(Unsafe.Add(ref blueBinRef, maxIndex) / maxIntensity);
float green = MathF.Abs(Unsafe.Add(ref greenBinRef, maxIndex) / maxIntensity); float green = MathF.Abs(Unsafe.Add(ref greenBinRef, maxIndex) / maxIntensity);
float alpha = sourceRowVector4Span[x].W; float alpha = sourceRowVector4Span[x].W;
targetRowVector4Span[x] = new Vector4(red, green, blue, alpha); targetRowVector4Span[x] = new Vector4(red, green, blue, alpha);
}
} }
}
Span<TPixel> targetRowAreaPixelSpan = targetPixels.GetRowSpan(y).Slice(startX, rectangleWidth); Span<TPixel> targetRowAreaPixelSpan = targetPixels.GetRowSpan(y).Slice(startX, rectangleWidth);
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, targetRowAreaVector4Span, targetRowAreaPixelSpan); PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, targetRowAreaVector4Span, targetRowAreaPixelSpan);
}
} }
}); });

Loading…
Cancel
Save