Skip to content

Commit 06bdf13

Browse files
Optimize memory usage for resize pad operations
1 parent baa8c7b commit 06bdf13

File tree

3 files changed

+14
-19
lines changed

3 files changed

+14
-19
lines changed

src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ protected virtual void Dispose(bool disposing)
101101
/// Returns a <see cref="ResizeKernel"/> for an index value between 0 and DestinationSize - 1.
102102
/// </summary>
103103
[MethodImpl(InliningOptions.ShortMethod)]
104-
internal ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx];
104+
internal ref ResizeKernel GetKernel(nint destIdx) => ref this.kernels[destIdx];
105105

106106
/// <summary>
107107
/// Computes the weights to apply at each pixel when resizing.

src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -209,21 +209,18 @@ private static void ApplyResizeFrameTransform(
209209

210210
// To reintroduce parallel processing, we would launch multiple workers
211211
// for different row intervals of the image.
212-
using (var worker = new ResizeWorker<TPixel>(
212+
using var worker = new ResizeWorker<TPixel>(
213213
configuration,
214214
sourceRegion,
215215
conversionModifiers,
216216
horizontalKernelMap,
217217
verticalKernelMap,
218-
destination.Width,
219218
interest,
220-
destinationRectangle.Location))
221-
{
222-
worker.Initialize();
219+
destinationRectangle.Location);
220+
worker.Initialize();
223221

224-
var workingInterval = new RowInterval(interest.Top, interest.Bottom);
225-
worker.FillDestinationPixels(workingInterval, destination.PixelBuffer);
226-
}
222+
var workingInterval = new RowInterval(interest.Top, interest.Bottom);
223+
worker.FillDestinationPixels(workingInterval, destination.PixelBuffer);
227224
}
228225

229226
private readonly struct NNRowOperation : IRowOperation

src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ internal sealed class ResizeWorker<TPixel> : IDisposable
3939

4040
private readonly ResizeKernelMap verticalKernelMap;
4141

42-
private readonly int destWidth;
43-
4442
private readonly Rectangle targetWorkingRect;
4543

4644
private readonly Point targetOrigin;
@@ -57,7 +55,6 @@ public ResizeWorker(
5755
PixelConversionModifiers conversionModifiers,
5856
ResizeKernelMap horizontalKernelMap,
5957
ResizeKernelMap verticalKernelMap,
60-
int destWidth,
6158
Rectangle targetWorkingRect,
6259
Point targetOrigin)
6360
{
@@ -67,7 +64,6 @@ public ResizeWorker(
6764
this.conversionModifiers = conversionModifiers;
6865
this.horizontalKernelMap = horizontalKernelMap;
6966
this.verticalKernelMap = verticalKernelMap;
70-
this.destWidth = destWidth;
7167
this.targetWorkingRect = targetWorkingRect;
7268
this.targetOrigin = targetOrigin;
7369

@@ -80,14 +76,14 @@ public ResizeWorker(
8076

8177
int numberOfWindowBands = ResizeHelper.CalculateResizeWorkerHeightInWindowBands(
8278
this.windowBandHeight,
83-
destWidth,
79+
targetWorkingRect.Width,
8480
workingBufferLimitHintInBytes);
8581

8682
this.workerHeight = Math.Min(this.sourceRectangle.Height, numberOfWindowBands * this.windowBandHeight);
8783

8884
this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D<Vector4>(
8985
this.workerHeight,
90-
destWidth,
86+
targetWorkingRect.Width,
9187
preferContiguosImageBuffers: true,
9288
options: AllocationOptions.Clean);
9389

@@ -137,9 +133,9 @@ public void FillDestinationPixels(RowInterval rowInterval, Buffer2D<TPixel> dest
137133

138134
ref Vector4 fpBase = ref transposedFirstPassBufferSpan[top];
139135

140-
for (int x = left; x < right; x++)
136+
for (nint x = left; x < right; x++)
141137
{
142-
ref Vector4 firstPassColumnBase = ref Unsafe.Add(ref fpBase, x * this.workerHeight);
138+
ref Vector4 firstPassColumnBase = ref Unsafe.Add(ref fpBase, (x - left) * this.workerHeight);
143139

144140
// Destination color components
145141
Unsafe.Add(ref tempRowBase, x - left) = kernel.ConvolveCore(ref firstPassColumnBase);
@@ -174,6 +170,8 @@ private void CalculateFirstPassValues(RowInterval calculationInterval)
174170
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
175171
Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.DangerousGetSingleSpan();
176172

173+
int left = this.targetWorkingRect.Left;
174+
int right = this.targetWorkingRect.Right;
177175
for (int y = calculationInterval.Min; y < calculationInterval.Max; y++)
178176
{
179177
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y);
@@ -188,13 +186,13 @@ private void CalculateFirstPassValues(RowInterval calculationInterval)
188186
// Span<Vector4> firstPassSpan = transposedFirstPassBufferSpan.Slice(y - this.currentWindow.Min);
189187
ref Vector4 firstPassBaseRef = ref transposedFirstPassBufferSpan[y - this.currentWindow.Min];
190188

191-
for (int x = this.targetWorkingRect.Left; x < this.targetWorkingRect.Right; x++)
189+
for (nint x = left; x < right; x++)
192190
{
193191
ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - this.targetOrigin.X);
194192

195193
// optimization for:
196194
// firstPassSpan[x * this.workerHeight] = kernel.Convolve(tempRowSpan);
197-
Unsafe.Add(ref firstPassBaseRef, x * this.workerHeight) = kernel.Convolve(tempRowSpan);
195+
Unsafe.Add(ref firstPassBaseRef, (x - left) * this.workerHeight) = kernel.Convolve(tempRowSpan);
198196
}
199197
}
200198
}

0 commit comments

Comments
 (0)