Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable & optimized memory management #475

Merged
merged 76 commits into from
Feb 27, 2018
Merged
Show file tree
Hide file tree
Changes from 67 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
72772ff
- Make Buffer2D wrap Buffer
rytmis Jan 11, 2018
607e452
- Allocate Buffers from memory manager
rytmis Jan 11, 2018
c5eb2cf
- Allocate Buffer2Ds from memory manager
rytmis Jan 11, 2018
a73283f
- Add a minimum size threshold for array pool usage
rytmis Jan 11, 2018
9e4e5ab
- Removed a test that doesn't actually test anything any more
rytmis Jan 11, 2018
b1a5c71
- Removed PixelDataPool
rytmis Jan 11, 2018
333ce3b
- Oops. Note to self: don't make changes to unsafe
rytmis Jan 12, 2018
f675f5c
- Explicitly pass MemoryManager to the places that
rytmis Jan 12, 2018
f1412d3
- Use Configuration.Default.MemoryManager in tests
rytmis Jan 12, 2018
2451168
- Code style fixes
rytmis Jan 12, 2018
58330a1
- Removing more usages of ArrayPool
rytmis Jan 12, 2018
58ab4e6
- Remove ArrayPool from Huffman tree
rytmis Jan 12, 2018
9290536
- Use fixed buffers in Huffman table
rytmis Jan 12, 2018
2615556
- Use memory manager in Bytes
rytmis Jan 13, 2018
4e4cdd5
- Removed ArrayPool from WuQuantizer
rytmis Jan 13, 2018
cf13ebf
- Optional param -> second method
rytmis Jan 13, 2018
76dc5c2
- Whitespace fix
rytmis Jan 13, 2018
54313e8
- Reduced the threshold for ArrayPoolMemoryManager to 512 bytes
rytmis Jan 13, 2018
b23b137
- Oops, neglected to fix this test
rytmis Jan 13, 2018
750af5a
- Removed Configuration.Default.MemoryManager from PixelAccessor
rytmis Jan 13, 2018
7e3cb28
dropping minSizeBytes + fixing tests
antonfirsov Jan 14, 2018
22206f1
maxPoolSizeInBytes parameter + safer indexer for Buffer<T>
antonfirsov Jan 14, 2018
80e5fe3
Merge branch 'master' into feature/memory-manager
antonfirsov Feb 17, 2018
af23153
fix build after merge
antonfirsov Feb 17, 2018
7a076de
moving common MemoryManager logic into extension methods
antonfirsov Feb 17, 2018
967098b
Merge remote-tracking branch 'origin/antonfirsov/cover-all-codecs' in…
antonfirsov Feb 19, 2018
3819c75
dropping MemoryManager ctr. argument:
antonfirsov Feb 19, 2018
2ea9e08
introducing FakeBuffer<T> workaround
antonfirsov Feb 19, 2018
29483b3
IManagedByteBuffer
antonfirsov Feb 19, 2018
cf96e61
hide Buffer<T>.Array, use IManagedByteBuffer when necessary
antonfirsov Feb 19, 2018
e666609
fix regression in GifDecoderCore
antonfirsov Feb 19, 2018
739cec3
clean up Buffer<T> API
antonfirsov Feb 19, 2018
7db4cdc
Hide Buffer<T> indexer + !! WuQuantizer review in comments !!
antonfirsov Feb 20, 2018
58d187f
2 drawing regression test cases for safety
antonfirsov Feb 20, 2018
77e524d
MemoryManager returns IBuffer<T> now
antonfirsov Feb 20, 2018
4e515a8
MemoryManager-s should provide their own IBuffer<T> implementations
antonfirsov Feb 20, 2018
f390569
goodbye top-level Buffer<T>!
antonfirsov Feb 20, 2018
d6c196b
Buffer2DTests using a mock MemoryManager
antonfirsov Feb 20, 2018
f23e849
ArrayPoolMemoryManagerTests
antonfirsov Feb 20, 2018
ae52170
Covering ArrayPoolMemoryManager and it's buffer. Took hours, but wort…
antonfirsov Feb 20, 2018
fa0ae3c
ArrayPoolMemoryManager uses a different ArrayPool for large buffers +…
antonfirsov Feb 20, 2018
76633c9
allowing bucket sizes to be passed to ArrayPoolMemoryManager
antonfirsov Feb 20, 2018
2fa0994
ArrayPoolMemoryManager factory methods
antonfirsov Feb 20, 2018
a85cc51
passing MemoryManager to pixel blenders
antonfirsov Feb 21, 2018
7210a89
Merge remote-tracking branch 'origin/master' into feature/memory-manager
antonfirsov Feb 21, 2018
d29ef1a
Super-optimized GenericBlock8x8<T> to replace PixelArea<T> in JpegEnc…
antonfirsov Feb 22, 2018
6e1736d
YCbCrForwardConverter<TPixel> WIP
antonfirsov Feb 22, 2018
6a40926
Merge remote-tracking branch 'origin/antonfirsov/cover-all-codecs' in…
antonfirsov Feb 22, 2018
52c482e
build fix: MakeOpaque()
antonfirsov Feb 22, 2018
be325d8
YCbCrForwardConverter<TPixel>
antonfirsov Feb 22, 2018
bcd33b6
Encode444 using YCbCrForwardConverter<TPixel>
antonfirsov Feb 22, 2018
62f8ba2
All PixelArea<T> usages in JpegEncoder replaced by GenericBlock8x8<TP…
antonfirsov Feb 22, 2018
e64f1d5
fixing StyleCop errors
antonfirsov Feb 22, 2018
2be566b
cleanup
antonfirsov Feb 22, 2018
ba5e80f
replaced some of the PixelArea usages in bmp decoder
antonfirsov Feb 22, 2018
d1872c5
removed PixelArea<T>!
antonfirsov Feb 22, 2018
65918d1
replaced PixelAccessor<T> with Buffer2D<T> in several processors
antonfirsov Feb 23, 2018
45cca93
PixelAccessor<T> is now a meaningless thin wrapper around Buffer2D<T>
antonfirsov Feb 23, 2018
7b62fbc
do not use Configuration.Default.MemoryManager in AddFrame()
antonfirsov Feb 23, 2018
8d351f3
code analyzers fighting each other
antonfirsov Feb 23, 2018
0684c93
using WeakReference in ArrayPoolMemoryManager.Buffer
antonfirsov Feb 25, 2018
eeaa270
tuning ArrayPoolMemoryManager configuration based on benchmark results
antonfirsov Feb 25, 2018
e2694d3
tuning ArrayPoolMemoryManager configuration based on benchmark results
antonfirsov Feb 25, 2018
9368d3e
Merge branch 'master' of https://github.com/SixLabors/ImageSharp into…
antonfirsov Feb 25, 2018
110e3c7
build fix after merge
antonfirsov Feb 25, 2018
88be834
removing duplicate reference to SixLabors.Core
antonfirsov Feb 25, 2018
48a3189
SimpleManagedMemoryManager -> SimpleGcMemoryManager
antonfirsov Feb 26, 2018
c07cbea
review cleanup
antonfirsov Feb 26, 2018
4d915b6
added comments for the WeakReference stuff
antonfirsov Feb 26, 2018
de67364
optimize ResizeProcessor parallel behavior and Span<T> usage
antonfirsov Feb 26, 2018
d721138
introducing ParallelFor.WithTemporalBuffer(): common utility for the …
antonfirsov Feb 26, 2018
1b0a2b4
removed Span bottleneck from Block8x8F.CopyTo() + removed unnecessary…
antonfirsov Feb 27, 2018
7d5cea1
Removing all the buffer magic from the Bytes struct. It only made thi…
antonfirsov Feb 27, 2018
c314db6
Remove unneeded parameter
JimBobSquarePants Feb 27, 2018
5b9b27c
Temporary Vortex
antonfirsov Feb 27, 2018
55d2184
Merge branch 'feature/memory-manager' of https://github.com/SixLabors…
antonfirsov Feb 27, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,24 +122,27 @@ public override void Dispose()
internal override void Apply(Span<float> scanline, int x, int y)
{
// Create a span for colors
using (var amountBuffer = new Buffer<float>(scanline.Length))
using (var overlay = new Buffer<TPixel>(scanline.Length))
using (IBuffer<float> amountBuffer = this.Target.MemoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = this.Target.MemoryManager.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;

int sourceY = (y - this.offsetY) % this.yLength;
int offsetX = x - this.offsetX;
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(sourceY);

for (int i = 0; i < scanline.Length; i++)
{
amountBuffer[i] = scanline[i] * this.Options.BlendPercentage;
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;

int sourceX = (i + offsetX) % this.xLength;
TPixel pixel = sourceRow[sourceX];
overlay[i] = pixel;
overlaySpan[i] = pixel;
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
this.Blender.Blend(this.source.MemoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}
Expand Down
15 changes: 10 additions & 5 deletions src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,19 +152,24 @@ public override void Dispose()
internal override void Apply(Span<float> scanline, int x, int y)
{
int patternY = y % this.pattern.Height;
using (var amountBuffer = new Buffer<float>(scanline.Length))
using (var overlay = new Buffer<TPixel>(scanline.Length))
MemoryManager memoryManager = this.Target.MemoryManager;

using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;

for (int i = 0; i < scanline.Length; i++)
{
amountBuffer[i] = (scanline[i] * this.Options.BlendPercentage).Clamp(0, 1);
amountSpan[i] = (scanline[i] * this.Options.BlendPercentage).Clamp(0, 1);

int patternX = (x + i) % this.pattern.Width;
overlay[i] = this.pattern[patternY, patternX];
overlaySpan[i] = this.pattern[patternY, patternX];
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}
Expand Down
15 changes: 10 additions & 5 deletions src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,26 @@ internal BrushApplicator(ImageFrame<TPixel> target, GraphicsOptions options)
/// <remarks>scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.</remarks>
internal virtual void Apply(Span<float> scanline, int x, int y)
{
using (var amountBuffer = new Buffer<float>(scanline.Length))
using (var overlay = new Buffer<TPixel>(scanline.Length))
MemoryManager memoryManager = this.Target.MemoryManager;

using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;

for (int i = 0; i < scanline.Length; i++)
{
if (this.Options.BlendPercentage < 1)
{
amountBuffer[i] = scanline[i] * this.Options.BlendPercentage;
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}

overlay[i] = this[x + i, y];
overlaySpan[i] = this[x + i, y];
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}
Expand Down
15 changes: 10 additions & 5 deletions src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,22 +144,27 @@ public override void Dispose()
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
using (var amountBuffer = new Buffer<float>(scanline.Length))
using (var overlay = new Buffer<TPixel>(scanline.Length))
MemoryManager memoryManager = this.Target.MemoryManager;

using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;
Span<TPixel> overlaySpan = overlay.Span;

for (int i = 0; i < scanline.Length; i++)
{
amountBuffer[i] = scanline[i] * this.Options.BlendPercentage;
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;

int offsetX = x + i;

// no doubt this one can be optermised further but I can't imagine its
// actually being used and can probably be removed/interalised for now
overlay[i] = this[offsetX, y];
overlaySpan[i] = this[offsetX, y];
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}
Expand Down
22 changes: 12 additions & 10 deletions src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,14 @@ private class SolidBrushApplicator : BrushApplicator<TPixel>
public SolidBrushApplicator(ImageFrame<TPixel> source, TPixel color, GraphicsOptions options)
: base(source, options)
{
this.Colors = new Buffer<TPixel>(source.Width);
for (int i = 0; i < this.Colors.Length; i++)
{
this.Colors[i] = color;
}
this.Colors = source.MemoryManager.Allocate<TPixel>(source.Width);
this.Colors.Span.Fill(color);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't know Span had a Fill method. Neat!

}

/// <summary>
/// Gets the colors.
/// </summary>
protected Buffer<TPixel> Colors { get; }
protected IBuffer<TPixel> Colors { get; }

/// <summary>
/// Gets the color for a single pixel.
Expand All @@ -81,7 +78,7 @@ public SolidBrushApplicator(ImageFrame<TPixel> source, TPixel color, GraphicsOpt
/// <returns>
/// The color
/// </returns>
internal override TPixel this[int x, int y] => this.Colors[x];
internal override TPixel this[int x, int y] => this.Colors.Span[x];

/// <inheritdoc />
public override void Dispose()
Expand All @@ -96,18 +93,23 @@ internal override void Apply(Span<float> scanline, int x, int y)
{
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);

using (var amountBuffer = new Buffer<float>(scanline.Length))
MemoryManager memoryManager = this.Target.MemoryManager;

using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.Span;

for (int i = 0; i < scanline.Length; i++)
{
amountBuffer[i] = scanline[i] * this.Options.BlendPercentage;
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}

this.Blender.Blend(destinationRow, destinationRow, this.Colors, amountBuffer);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, amountSpan);
}
}
catch (Exception)
{
// TODO: Why are we catching exceptions here silently ???
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was probably a hangover from the old try..catch..finally pattern from when we were directly using ArrayPool

throw;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/ImageSharp.Drawing/Paths/ShapePath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System;
using System.Buffers;
using System.Numerics;

using SixLabors.ImageSharp.Memory;
using SixLabors.Shapes;

namespace SixLabors.ImageSharp.Drawing
Expand Down
17 changes: 8 additions & 9 deletions src/ImageSharp.Drawing/Paths/ShapeRegion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,17 @@ public override int Scan(float y, float[] buffer, int offset)
{
var start = new PointF(this.Bounds.Left - 1, y);
var end = new PointF(this.Bounds.Right + 1, y);
using (var innerBuffer = new Buffer<PointF>(buffer.Length))
{
PointF[] array = innerBuffer.Array;
int count = this.Shape.FindIntersections(start, end, array, 0);

for (int i = 0; i < count; i++)
{
buffer[i + offset] = array[i].X;
}
// TODO: This is a temporal workaround because of the lack of Span<T> API-s on IPath. We should use MemoryManager.Allocate() here!
PointF[] innerBuffer = new PointF[buffer.Length];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's get a PR in place against Shapes to add those API's.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we do it now, or in a follow up PR pair?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do a follow up once we've done Shapes.

int count = this.Shape.FindIntersections(start, end, innerBuffer, 0);

return count;
for (int i = 0; i < count; i++)
{
buffer[i + offset] = innerBuffer[i].X;
}

return count;
}
}
}
12 changes: 6 additions & 6 deletions src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRecta
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom);

int width = maxX - minX;
using (var amount = new Buffer<float>(width))

MemoryManager memoryManager = this.Image.GetConfiguration().MemoryManager;

using (IBuffer<float> amount = memoryManager.Allocate<float>(width))
{
for (int i = 0; i < width; i++)
{
amount[i] = this.Opacity;
}
amount.Span.Fill(this.Opacity);

Parallel.For(
minY,
Expand All @@ -88,7 +88,7 @@ protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRecta
{
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend(background, background, foreground, amount);
blender.Blend(memoryManager, background, background, foreground, amount.Span);
});
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/ImageSharp.Drawing/Processors/FillProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,25 @@ protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRecta

int width = maxX - minX;

using (var amount = new Buffer<float>(width))
using (BrushApplicator<TPixel> applicator = this.brush.CreateApplicator(source, sourceRectangle, this.options))
using (IBuffer<float> amount = source.MemoryManager.Allocate<float>(width))
using (BrushApplicator<TPixel> applicator = this.brush.CreateApplicator(
source,
sourceRectangle,
this.options))
{
for (int i = 0; i < width; i++)
{
amount[i] = this.options.BlendPercentage;
}
amount.Span.Fill(this.options.BlendPercentage);

Parallel.For(
Parallel.For(
minY,
maxY,
configuration.ParallelOptions,
y =>
{
int offsetY = y - startY;
int offsetX = minX - startX;
{
int offsetY = y - startY;
int offsetX = minX - startX;

applicator.Apply(amount, offsetX, offsetY);
});
applicator.Apply(amount.Span, offsetX, offsetY);
});
}
}
}
Expand Down
Loading