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) if (frameControl is { } control)
{ {
PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngFrameMetadata(); PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngFrameMetadata();
frameMetadata.FromChunk(control); frameMetadata.FromChunk(in control);
} }
this.bytesPerPixel = this.CalculateBytesPerPixel(); this.bytesPerPixel = this.CalculateBytesPerPixel();
@ -837,7 +837,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
} }
Span<TPixel> rowSpan = imageBuffer.DangerousGetRowSpan(currentRow); 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(); this.SwapScanlineBuffers();
@ -935,6 +941,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
case PngColorType.RgbWithAlpha: case PngColorType.RgbWithAlpha:
PngScanlineProcessor.ProcessRgbaScanline( PngScanlineProcessor.ProcessRgbaScanline(
this.configuration,
this.header.BitDepth, this.header.BitDepth,
in frameControl, in frameControl,
scanlineSpan, scanlineSpan,
@ -961,7 +968,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <param name="pngMetadata">The png metadata.</param> /// <param name="pngMetadata">The png metadata.</param>
/// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</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> /// <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> where TPixel : unmanaged, IPixel<TPixel>
{ {
// Trim the first marker byte from the buffer // Trim the first marker byte from the buffer
@ -1034,6 +1047,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
case PngColorType.RgbWithAlpha: case PngColorType.RgbWithAlpha:
PngScanlineProcessor.ProcessInterlacedRgbaScanline( PngScanlineProcessor.ProcessInterlacedRgbaScanline(
this.configuration,
this.header.BitDepth, this.header.BitDepth,
in frameControl, in frameControl,
scanlineSpan, 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. /// Initializes a new instance of the <see cref="PngFrameMetadata"/> class.
/// </summary> /// </summary>
/// <param name="frameControl">The chunk to create an instance from.</param> /// <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.DelayNumerator = frameControl.DelayNumerator;
this.DelayDenominator = frameControl.DelayDenominator; this.DelayDenominator = frameControl.DelayDenominator;

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

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

Loading…
Cancel
Save