Browse Source

Reintroduce scanline optimizations

pull/2511/head
James Jackson-South 3 years ago
parent
commit
5ed6f24943
  1. 20
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  2. 2
      src/ImageSharp/Formats/Png/PngFrameMetadata.cs
  3. 65
      src/ImageSharp/Formats/Png/PngScanlineProcessor.cs

20
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -567,7 +567,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
if (frameControl is { } control)
{
PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngFrameMetadata();
frameMetadata.FromChunk(control);
frameMetadata.FromChunk(in control);
}
this.bytesPerPixel = this.CalculateBytesPerPixel();
@ -837,7 +837,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
}
Span<TPixel> rowSpan = imageBuffer.DangerousGetRowSpan(currentRow);
this.ProcessInterlacedDefilteredScanline(frameControl, this.scanline.GetSpan(), rowSpan, pngMetadata, pixelOffset: Adam7.FirstColumn[pass], increment: Adam7.ColumnIncrement[pass]);
this.ProcessInterlacedDefilteredScanline(
frameControl,
this.scanline.GetSpan(),
rowSpan,
pngMetadata,
pixelOffset: Adam7.FirstColumn[pass],
increment: Adam7.ColumnIncrement[pass]);
this.SwapScanlineBuffers();
@ -935,6 +941,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
case PngColorType.RgbWithAlpha:
PngScanlineProcessor.ProcessRgbaScanline(
this.configuration,
this.header.BitDepth,
in frameControl,
scanlineSpan,
@ -961,7 +968,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <param name="pngMetadata">The png metadata.</param>
/// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</param>
/// <param name="increment">The column increment. Always 1 for none interlaced images.</param>
private void ProcessInterlacedDefilteredScanline<TPixel>(in FrameControl frameControl, ReadOnlySpan<byte> defilteredScanline, Span<TPixel> rowSpan, PngMetadata pngMetadata, int pixelOffset = 0, int increment = 1)
private void ProcessInterlacedDefilteredScanline<TPixel>(
in FrameControl frameControl,
ReadOnlySpan<byte> defilteredScanline,
Span<TPixel> rowSpan,
PngMetadata pngMetadata,
int pixelOffset = 0,
int increment = 1)
where TPixel : unmanaged, IPixel<TPixel>
{
// Trim the first marker byte from the buffer
@ -1034,6 +1047,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
case PngColorType.RgbWithAlpha:
PngScanlineProcessor.ProcessInterlacedRgbaScanline(
this.configuration,
this.header.BitDepth,
in frameControl,
scanlineSpan,

2
src/ImageSharp/Formats/Png/PngFrameMetadata.cs

@ -53,7 +53,7 @@ public class PngFrameMetadata : IDeepCloneable
/// Initializes a new instance of the <see cref="PngFrameMetadata"/> class.
/// </summary>
/// <param name="frameControl">The chunk to create an instance from.</param>
internal void FromChunk(FrameControl frameControl)
internal void FromChunk(in FrameControl frameControl)
{
this.DelayNumerator = frameControl.DelayNumerator;
this.DelayDenominator = frameControl.DelayDenominator;

65
src/ImageSharp/Formats/Png/PngScanlineProcessor.cs

@ -216,18 +216,18 @@ internal static class PngScanlineProcessor
int bytesPerPixel,
int bytesPerSample,
Color? transparentColor)
where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedRgbScanline(
configuration,
bitDepth,
frameControl,
scanlineSpan,
rowSpan,
0,
1,
bytesPerPixel,
bytesPerSample,
transparentColor);
where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedRgbScanline(
configuration,
bitDepth,
frameControl,
scanlineSpan,
rowSpan,
0,
1,
bytesPerPixel,
bytesPerSample,
transparentColor);
public static void ProcessInterlacedRgbScanline<TPixel>(
Configuration configuration,
@ -264,9 +264,16 @@ internal static class PngScanlineProcessor
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
else if (pixelOffset == 0 && increment == 1)
{
PixelOperations<TPixel>.Instance.FromRgb24Bytes(
configuration,
scanlineSpan[..(int)(frameControl.Width * bytesPerPixel)],
rowSpan.Slice((int)frameControl.XOffset, (int)frameControl.Width),
(int)frameControl.Width);
}
else
{
// TODO: Investigate reintroducing bulk operations optimization here.
Rgb24 rgb = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
@ -323,24 +330,27 @@ internal static class PngScanlineProcessor
}
public static void ProcessRgbaScanline<TPixel>(
Configuration configuration,
int bitDepth,
in FrameControl frameControl,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
int bytesPerPixel,
int bytesPerSample)
where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedRgbaScanline(
bitDepth,
frameControl,
scanlineSpan,
rowSpan,
0,
1,
bytesPerPixel,
bytesPerSample);
where TPixel : unmanaged, IPixel<TPixel> =>
ProcessInterlacedRgbaScanline(
configuration,
bitDepth,
frameControl,
scanlineSpan,
rowSpan,
0,
1,
bytesPerPixel,
bytesPerSample);
public static void ProcessInterlacedRgbaScanline<TPixel>(
Configuration configuration,
int bitDepth,
in FrameControl frameControl,
ReadOnlySpan<byte> scanlineSpan,
@ -370,9 +380,16 @@ internal static class PngScanlineProcessor
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
else if (pixelOffset == 0 && increment == 1)
{
PixelOperations<TPixel>.Instance.FromRgba32Bytes(
configuration,
scanlineSpan[..(int)(frameControl.Width * bytesPerPixel)],
rowSpan.Slice((int)frameControl.XOffset, (int)frameControl.Width),
(int)frameControl.Width);
}
else
{
// TODO: Investigate reintroducing bulk operations optimization here.
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
Rgba32 rgba = default;
int o = 0;

Loading…
Cancel
Save