Browse Source

Span<T>!!

pull/386/head
James Jackson-South 9 years ago
parent
commit
13f73a963a
  1. 2
      src/ImageSharp/Memory/Buffer{T}.cs
  2. 157
      src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs

2
src/ImageSharp/Memory/Buffer{T}.cs

@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Buffer<T> CreateClean(int count) public static Buffer<T> CreateClean(int count)
{ {
Buffer<T> buffer = new Buffer<T>(count); var buffer = new Buffer<T>(count);
buffer.Clear(); buffer.Clear();
return buffer; return buffer;
} }

157
src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs

@ -103,92 +103,95 @@ namespace SixLabors.ImageSharp.Processing.Processors
int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); int xLength = (int)MathF.Ceiling((radius.X * 2) + 2);
int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2);
Parallel.For( using (var yBuffer = new Buffer2D<float>(yLength, height))
0, using (var xBuffer = new Buffer2D<float>(xLength, height))
height, {
configuration.ParallelOptions, Parallel.For(
y => 0,
{ height,
Span<TPixel> destRow = destination.GetPixelRowSpan(y); configuration.ParallelOptions,
using (var yBuffer = new Buffer<float>(yLength)) y =>
using (var xBuffer = new Buffer<float>(xLength))
{
for (int x = 0; x < width; x++)
{ {
// Use the single precision position to calculate correct bounding pixels Span<TPixel> destRow = destination.GetPixelRowSpan(y);
// otherwise we get rogue pixels outside of the bounds. Span<float> ySpan = yBuffer.GetRowSpan(y);
var point = Vector2.Transform(new Vector2(x, y), matrix); Span<float> xSpan = xBuffer.GetRowSpan(y);
// Clamp sampling pixel radial extents to the source image edges for (int x = 0; x < width; x++)
Vector2 maxXY = point + radius; {
Vector2 minXY = point - radius; // Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds.
var point = Vector2.Transform(new Vector2(x, y), matrix);
var extents = new Vector4( // Clamp sampling pixel radial extents to the source image edges
MathF.Ceiling(maxXY.X), Vector2 maxXY = point + radius;
MathF.Ceiling(maxXY.Y), Vector2 minXY = point - radius;
MathF.Floor(minXY.X),
MathF.Floor(minXY.Y));
int right = (int)extents.X; var extents = new Vector4(
int bottom = (int)extents.Y; MathF.Ceiling(maxXY.X),
int left = (int)extents.Z; MathF.Ceiling(maxXY.Y),
int top = (int)extents.W; MathF.Floor(minXY.X),
MathF.Floor(minXY.Y));
extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); int right = (int)extents.X;
int bottom = (int)extents.Y;
int left = (int)extents.Z;
int top = (int)extents.W;
int maxX = (int)extents.X; extents = Vector4.Clamp(extents, Vector4.Zero, maxSource);
int maxY = (int)extents.Y;
int minX = (int)extents.Z;
int minY = (int)extents.W;
if (minX == maxX || minY == maxY) int maxX = (int)extents.X;
{ int maxY = (int)extents.Y;
continue; int minX = (int)extents.Z;
} int minY = (int)extents.W;
// It appears these have to be calculated on-the-fly. if (minX == maxX || minY == maxY)
// Precalulating transformed weights would require prior knowledge of every transformed pixel location {
// since they can be at sub-pixel positions. continue;
// I've optimized where I can but am always open to suggestions. }
//
// Create and normalize the y-weights
if (yScale > 1)
{
CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, yBuffer);
}
else
{
CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, yBuffer);
}
// Create and normalize the x-weights // It appears these have to be calculated on-the-fly.
if (xScale > 1) // Precalulating transformed weights would require prior knowledge of every transformed pixel location
{ // since they can be at sub-pixel positions on both axis.
CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, xBuffer); // I've optimized where I can but am always open to suggestions.
} //
else // Create and normalize the y-weights
{ if (yScale > 1)
CalculateWeightsScaleUp(minX, maxX, point.X, sampler, xBuffer); {
} CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, ySpan);
}
else
{
CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ySpan);
}
// Now multiply the results against the offsets // Create and normalize the x-weights
Vector4 sum = Vector4.Zero; if (xScale > 1)
for (int yy = 0, j = minY; j <= maxY; j++, yy++) {
{ CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, xSpan);
float yWeight = yBuffer[yy]; }
else
{
CalculateWeightsScaleUp(minX, maxX, point.X, sampler, xSpan);
}
for (int xx = 0, i = minX; i <= maxX; i++, xx++) // Now multiply the results against the offsets
Vector4 sum = Vector4.Zero;
for (int yy = 0, j = minY; j <= maxY; j++, yy++)
{ {
float xWeight = xBuffer[xx]; float yWeight = ySpan[yy];
sum += source[i, j].ToVector4() * xWeight * yWeight;
for (int xx = 0, i = minX; i <= maxX; i++, xx++)
{
float xWeight = xSpan[xx];
sum += source[i, j].ToVector4() * xWeight * yWeight;
}
} }
}
ref TPixel dest = ref destRow[x]; ref TPixel dest = ref destRow[x];
dest.PackFromVector4(sum); dest.PackFromVector4(sum);
} }
} });
}); }
} }
/// <summary> /// <summary>
@ -206,7 +209,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <summary> /// <summary>
/// Calculated the weights for the given point. This method uses more samples than the upscaled version to ensure edge pixels are correctly rendered. /// Calculated the weights for the given point.
/// This method uses more samples than the upscaled version to ensure edge pixels are correctly rendered.
/// Additionally the weights are nomalized. /// Additionally the weights are nomalized.
/// </summary> /// </summary>
/// <param name="min">The minimum sampling offset</param> /// <param name="min">The minimum sampling offset</param>
@ -218,7 +222,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// <param name="scale">The transformed image scale relative to the source</param> /// <param name="scale">The transformed image scale relative to the source</param>
/// <param name="weights">The collection of weights</param> /// <param name="weights">The collection of weights</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CalculateWeightsDown(int min, int max, int sourceMin, int sourceMax, float point, IResampler sampler, float scale, Buffer<float> weights) private static void CalculateWeightsDown(int min, int max, int sourceMin, int sourceMax, float point, IResampler sampler, float scale, Span<float> weights)
{ {
float sum = 0; float sum = 0;
ref float weightsBaseRef = ref weights[0]; ref float weightsBaseRef = ref weights[0];
@ -253,8 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <summary> /// <summary>
/// Calculated the weights for the given point. This method uses more samples than the upscaled version to ensure edge pixels are correctly rendered. /// Calculated the weights for the given point.
/// Additionally the weights are nomalized.
/// </summary> /// </summary>
/// <param name="sourceMin">The minimum source bounds</param> /// <param name="sourceMin">The minimum source bounds</param>
/// <param name="sourceMax">The maximum source bounds</param> /// <param name="sourceMax">The maximum source bounds</param>
@ -262,7 +265,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// <param name="sampler">The sampler</param> /// <param name="sampler">The sampler</param>
/// <param name="weights">The collection of weights</param> /// <param name="weights">The collection of weights</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CalculateWeightsScaleUp(int sourceMin, int sourceMax, float point, IResampler sampler, Buffer<float> weights) private static void CalculateWeightsScaleUp(int sourceMin, int sourceMax, float point, IResampler sampler, Span<float> weights)
{ {
ref float weightsBaseRef = ref weights[0]; ref float weightsBaseRef = ref weights[0];
for (int x = 0, i = sourceMin; i <= sourceMax; i++, x++) for (int x = 0, i = sourceMin; i <= sourceMax; i++, x++)

Loading…
Cancel
Save