Skip to content

Commit dd7bd7b

Browse files
committed
Skip some safety readonly struct copies
1 parent 6b9d344 commit dd7bd7b

File tree

8 files changed

+28
-19
lines changed

8 files changed

+28
-19
lines changed

src/ImageSharp/Advanced/IRowIntervalAction.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ public void Invoke(int i)
9595
int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY);
9696
var rows = new RowInterval(yMin, yMax);
9797

98-
this.action.Invoke(in rows);
98+
// Skip the safety copy when invoking a potentially impure method on a readonly field
99+
Unsafe.AsRef(this.action).Invoke(in rows);
99100
}
100101
}
101102
}

src/ImageSharp/Advanced/IRowIntervalAction{TBuffer}.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ public void Invoke(int i)
9292
var rows = new RowInterval(yMin, yMax);
9393

9494
using IMemoryOwner<TBuffer> buffer = this.allocator.Allocate<TBuffer>(this.info.MaxX);
95-
this.action.Invoke(in rows, buffer.Memory);
95+
96+
Unsafe.AsRef(this.action).Invoke(in rows, buffer.Memory);
9697
}
9798
}
9899
}

src/ImageSharp/Advanced/ParallelRowIterator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static void IterateRows<T>(
6060
if (numOfSteps == 1)
6161
{
6262
var rows = new RowInterval(top, bottom);
63-
body.Invoke(in rows);
63+
Unsafe.AsRef(body).Invoke(in rows);
6464
return;
6565
}
6666

@@ -121,7 +121,7 @@ internal static void IterateRows<T, TBuffer>(
121121
var rows = new RowInterval(top, bottom);
122122
using (IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(width))
123123
{
124-
body.Invoke(rows, buffer.Memory);
124+
Unsafe.AsRef(body).Invoke(rows, buffer.Memory);
125125
}
126126

127127
return;

src/ImageSharp/Formats/Png/PngEncoderCore.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -554,8 +554,14 @@ private void WritePaletteChunk<TPixel>(Stream stream, IQuantizedFrame<TPixel> qu
554554
return;
555555
}
556556

557-
// Grab the palette and write it to the stream.
558-
ReadOnlySpan<TPixel> palette = quantized.Palette.Span;
557+
/* Grab the palette and write it to the stream.
558+
* Here the palette is reinterpreted as a mutable Memory<TPixel> value,
559+
* which is possible because the two memory types have the same layout.
560+
* This is done so that the Span<TPixel> we're working on is mutable,
561+
* so that we can skip the safety copies done by the compiler when we
562+
* invoke the IPixel.ToRgba32 method below, which is not marked as readonly. */
563+
ReadOnlyMemory<TPixel> paletteMemory = quantized.Palette;
564+
Span<TPixel> palette = Unsafe.As<ReadOnlyMemory<TPixel>, Memory<TPixel>>(ref paletteMemory).Span;
559565
int paletteLength = Math.Min(palette.Length, 256);
560566
int colorTableLength = paletteLength * 3;
561567
bool anyAlpha = false;

src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public void FromVector4(Vector4 vector)
218218

219219
/// <inheritdoc />
220220
[MethodImpl(InliningOptions.ShortMethod)]
221-
public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max;
221+
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max;
222222

223223
/// <inheritdoc />
224224
[MethodImpl(InliningOptions.ShortMethod)]
@@ -343,7 +343,7 @@ public void FromRgb48(Rgb48 source)
343343
/// </summary>
344344
/// <returns>The <see cref="Rgba32"/>.</returns>
345345
[MethodImpl(InliningOptions.ShortMethod)]
346-
public Rgba32 ToRgba32()
346+
public readonly Rgba32 ToRgba32()
347347
{
348348
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
349349
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
@@ -357,7 +357,7 @@ public Rgba32 ToRgba32()
357357
/// </summary>
358358
/// <returns>The <see cref="Bgra32"/>.</returns>
359359
[MethodImpl(InliningOptions.ShortMethod)]
360-
public Bgra32 ToBgra32()
360+
public readonly Bgra32 ToBgra32()
361361
{
362362
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
363363
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
@@ -371,7 +371,7 @@ public Bgra32 ToBgra32()
371371
/// </summary>
372372
/// <returns>The <see cref="Argb32"/>.</returns>
373373
[MethodImpl(InliningOptions.ShortMethod)]
374-
public Argb32 ToArgb32()
374+
public readonly Argb32 ToArgb32()
375375
{
376376
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
377377
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
@@ -385,7 +385,7 @@ public Argb32 ToArgb32()
385385
/// </summary>
386386
/// <returns>The <see cref="Rgb24"/>.</returns>
387387
[MethodImpl(InliningOptions.ShortMethod)]
388-
public Rgb24 ToRgb24()
388+
public readonly Rgb24 ToRgb24()
389389
{
390390
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
391391
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
@@ -398,7 +398,7 @@ public Rgb24 ToRgb24()
398398
/// </summary>
399399
/// <returns>The <see cref="Bgr24"/>.</returns>
400400
[MethodImpl(InliningOptions.ShortMethod)]
401-
public Bgr24 ToBgr24()
401+
public readonly Bgr24 ToBgr24()
402402
{
403403
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
404404
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);

src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Six Labors and contributors.
1+
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
@@ -66,7 +66,8 @@ internal static void ToVector4<TPixel>(
6666
MemoryMarshal.Cast<Rgba32, byte>(lastQuarterOfDestBuffer),
6767
MemoryMarshal.Cast<Vector4, float>(destVectors.Slice(0, countWithoutLastItem)));
6868

69-
destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4();
69+
// Reinterpret as a mutable reference to skip the safety copy of the readonly value
70+
destVectors[countWithoutLastItem] = Unsafe.AsRef(sourcePixels[countWithoutLastItem]).ToVector4();
7071

7172
// TODO: Investigate optimized 1-pass approach!
7273
ApplyForwardConversionModifiers(destVectors, modifiers);
@@ -126,4 +127,4 @@ private static int CalculateVector4ConversionThreshold()
126127
}
127128
}
128129
}
129-
}
130+
}

src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void Invoke(in RowInterval rows, Memory<Vector4> memory)
9595
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, vectorSpan, this.modifiers);
9696

9797
// Run the user defined pixel shader to the current row of pixels
98-
this.rowProcessor.Invoke(vectorSpan, new Point(this.startX, y));
98+
Unsafe.AsRef(this.rowProcessor).Invoke(vectorSpan, new Point(this.startX, y));
9999

100100
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, vectorSpan, rowSpan, this.modifiers);
101101
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Six Labors and contributors.
1+
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
@@ -81,7 +81,7 @@ private ResizeKernelMap(
8181
/// </summary>
8282
public void Dispose()
8383
{
84-
this.pinHandle.Dispose();
84+
Unsafe.AsRef(this.pinHandle).Dispose();
8585
this.data.Dispose();
8686
}
8787

@@ -248,4 +248,4 @@ private unsafe ResizeKernel CreateKernel(int dataRowIndex, int left, int right)
248248
return new ResizeKernel(left, rowPtr, length);
249249
}
250250
}
251-
}
251+
}

0 commit comments

Comments
 (0)