Browse Source

refactor FillRegionProcessor, drop MemoryManager.AllocateFake

af/merge-core
Anton Firszov 8 years ago
parent
commit
259f9736f3
  1. 63
      src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs
  2. 10
      src/ImageSharp/Memory/MemoryManager.cs
  3. 18
      tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs
  4. 2
      tests/ImageSharp.Tests/TestUtilities/TestUtils.cs
  5. 2
      tests/Images/External

63
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs

@ -96,36 +96,35 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
using (BrushApplicator<TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options))
{
int scanlineWidth = maxX - minX;
using (BasicArrayBuffer<float> buffer = source.MemoryManager.AllocateFake<float>(maxIntersections))
using (BasicArrayBuffer<float> scanline = source.MemoryManager.AllocateFake<float>(scanlineWidth))
using (IBuffer<float> bBuffer = source.MemoryManager.Allocate<float>(maxIntersections))
using (IBuffer<float> bScanline = source.MemoryManager.Allocate<float>(scanlineWidth))
{
bool scanlineDirty = true;
float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount;
Span<float> buffer = bBuffer.GetSpan();
Span<float> scanline = bScanline.GetSpan();
for (int y = minY; y < maxY; y++)
{
if (scanlineDirty)
{
// clear the buffer
for (int x = 0; x < scanlineWidth; x++)
{
scanline[x] = 0;
}
scanline.Clear();
scanlineDirty = false;
}
float yPlusOne = y + 1;
for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
{
int pointsFound = region.Scan(subPixel + offset, buffer.GetSpan(), configuration);
int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
if (pointsFound == 0)
{
// nothing on this line skip
continue;
}
QuickSort(new Span<float>(buffer.Array, 0, pointsFound));
QuickSort(buffer.Slice(0, pointsFound));
for (int point = 0; point < pointsFound; point += 2)
{
@ -181,7 +180,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
}
}
applicator.Apply(scanline.GetSpan(), minX, y);
applicator.Apply(scanline, minX, y);
}
}
}
@ -189,31 +188,45 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap(Span<float> data, int left, int right)
private static void Swap(ref float left, ref float right)
{
float tmp = data[left];
data[left] = data[right];
data[right] = tmp;
float tmp = left;
left = right;
right = tmp;
}
private static void QuickSort(Span<float> data)
{
QuickSort(data, 0, data.Length - 1);
if (data.Length < 2)
{
return;
}
else if (data.Length == 2)
{
if (data[0] > data[1])
{
Swap(ref data[0], ref data[1]);
}
return;
}
QuickSort(ref data[0], 0, data.Length - 1);
}
private static void QuickSort(Span<float> data, int lo, int hi)
private static void QuickSort(ref float data0, int lo, int hi)
{
if (lo < hi)
{
int p = Partition(data, lo, hi);
QuickSort(data, lo, p);
QuickSort(data, p + 1, hi);
int p = Partition(ref data0, lo, hi);
QuickSort(ref data0, lo, p);
QuickSort(ref data0, p + 1, hi);
}
}
private static int Partition(Span<float> data, int lo, int hi)
private static int Partition(ref float data0, int lo, int hi)
{
float pivot = data[lo];
float pivot = Unsafe.Add(ref data0, lo);
int i = lo - 1;
int j = hi + 1;
while (true)
@ -222,20 +235,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
{
i = i + 1;
}
while (data[i] < pivot && i < hi);
while (Unsafe.Add(ref data0, i) < pivot && i < hi);
do
{
j = j - 1;
}
while (data[j] > pivot && j > lo);
while (Unsafe.Add(ref data0, j) > pivot && j > lo);
if (i >= j)
{
return j;
}
Swap(data, i, j);
Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j));
}
}
}

10
src/ImageSharp/Memory/MemoryManager.cs

@ -27,16 +27,6 @@ namespace SixLabors.ImageSharp.Memory
/// <returns>The <see cref="IManagedByteBuffer"/></returns>
internal abstract IManagedByteBuffer AllocateManagedByteBuffer(int length, bool clear);
/// <summary>
/// Temporal workaround. A method providing a "Buffer" based on a generic array without the 'Unsafe.As()' hackery.
/// Should be replaced with 'Allocate()' as soon as SixLabors.Shapes has Span-based API-s!
/// </summary>
internal BasicArrayBuffer<T> AllocateFake<T>(int length, bool dummy = false)
where T : struct
{
return new BasicArrayBuffer<T>(new T[length]);
}
/// <summary>
/// Releases all retained resources not being in use.
/// Eg: by resetting array pools and letting GC to free the arrays.

18
tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs

@ -12,7 +12,10 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Drawing
{
using System;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.Primitives;
[GroupOutput("Drawing")]
public class FillSolidBrushTests
@ -67,6 +70,19 @@ namespace SixLabors.ImageSharp.Tests.Drawing
}
}
[Theory]
[WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 5, 7, 3, 8)]
[WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 8, 5, 6, 4)]
public void FillRegion<TPixel>(TestImageProvider<TPixel> provider, int x0, int y0, int w, int h)
where TPixel : struct, IPixel<TPixel>
{
FormattableString testDetails = $"(x{x0},y{y0},w{w},h{h})";
var region = new RectangleF(x0, y0, w, h);
TPixel color = TestUtils.GetPixelOfNamedColor<TPixel>("Blue");
provider.RunValidatingProcessorTest(c => c.Fill(color, region), testDetails, ImageComparer.Exact);
}
public static readonly TheoryData<bool, string, float, PixelBlenderMode, float> BlendData =
new TheoryData<bool, string, float, PixelBlenderMode, float>()
{

2
tests/ImageSharp.Tests/TestUtilities/TestUtils.cs

@ -113,8 +113,6 @@ namespace SixLabors.ImageSharp.Tests
/// <returns></returns>
public static PixelTypes GetPixelType(this Type colorStructClrType) => ClrTypes2PixelTypes[colorStructClrType];
public static IEnumerable<KeyValuePair<PixelTypes, Type>> ExpandAllTypes(this PixelTypes pixelTypes)
{
if (pixelTypes == PixelTypes.Undefined)

2
tests/Images/External

@ -1 +1 @@
Subproject commit eb40b3c039dd8c8ca448cb8073a59ca178901e9f
Subproject commit b1f057df33b7bfa6cabe714cf7090ac6017ea5d8
Loading…
Cancel
Save