Browse Source

block scaling bottleneck -> eliminated

pull/1574/head
Anton Firszov 6 years ago
parent
commit
572c9264f8
  1. 33
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
  2. 14
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
  3. 16
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
  4. 2
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs

33
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs

@ -16,28 +16,35 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public void CopyTo(in BufferArea<float> area, int horizontalScale, int verticalScale)
{
ref float areaOrigin = ref area.GetReferenceToOrigin();
this.CopyTo(ref areaOrigin, area.Stride, horizontalScale, verticalScale);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void CopyTo(ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale)
{
if (horizontalScale == 1 && verticalScale == 1)
{
this.Copy1x1Scale(area);
this.Copy1x1Scale(ref areaOrigin, areaStride);
return;
}
if (horizontalScale == 2 && verticalScale == 2)
{
this.Copy2x2Scale(area);
this.Copy2x2Scale(ref areaOrigin, areaStride);
return;
}
// TODO: Optimize: implement all cases with scale-specific, loopless code!
this.CopyArbitraryScale(area, horizontalScale, verticalScale);
this.CopyArbitraryScale(ref areaOrigin, areaStride, horizontalScale, verticalScale);
}
public void Copy1x1Scale(in BufferArea<float> destination)
public void Copy1x1Scale(ref float areaOrigin, int areaStride)
{
ref byte selfBase = ref Unsafe.As<Block8x8F, byte>(ref this);
ref byte destBase = ref Unsafe.As<float, byte>(ref destination.GetReferenceToOrigin());
int destStride = destination.Stride * sizeof(float);
ref byte destBase = ref Unsafe.As<float, byte>(ref areaOrigin);
int destStride = areaStride * sizeof(float);
CopyRowImpl(ref selfBase, ref destBase, destStride, 0);
CopyRowImpl(ref selfBase, ref destBase, destStride, 1);
@ -57,10 +64,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float));
}
private void Copy2x2Scale(in BufferArea<float> area)
private void Copy2x2Scale(ref float areaOrigin, int areaStride)
{
ref Vector2 destBase = ref Unsafe.As<float, Vector2>(ref area.GetReferenceToOrigin());
int destStride = area.Stride / 2;
ref Vector2 destBase = ref Unsafe.As<float, Vector2>(ref areaOrigin);
int destStride = areaStride / 2;
this.WidenCopyRowImpl2x2(ref destBase, 0, destStride);
this.WidenCopyRowImpl2x2(ref destBase, 1, destStride);
@ -110,10 +117,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
[MethodImpl(InliningOptions.ColdPath)]
private void CopyArbitraryScale(BufferArea<float> area, int horizontalScale, int verticalScale)
private void CopyArbitraryScale(ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale)
{
ref float destBase = ref area.GetReferenceToOrigin();
for (int y = 0; y < 8; y++)
{
int yy = y * verticalScale;
@ -127,12 +132,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
for (int i = 0; i < verticalScale; i++)
{
int baseIdx = ((yy + i) * area.Stride) + xx;
int baseIdx = ((yy + i) * areaStride) + xx;
for (int j = 0; j < horizontalScale; j++)
{
// area[xx + j, yy + i] = value;
Unsafe.Add(ref destBase, baseIdx + j) = value;
Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
}
}
}

14
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs

@ -68,11 +68,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// - Copy the resulting color values into 'destArea' scaling up the block by amount defined in <see cref="subSamplingDivisors"/>.
/// </summary>
/// <param name="sourceBlock">The source block.</param>
/// <param name="destArea">The destination buffer area.</param>
/// <param name="destAreaOrigin">Reference to the origin of the destination pixel area.</param>
/// <param name="destAreaStride">The width of the destination pixel buffer.</param>
/// <param name="maximumValue">The maximum value derived from the bitdepth.</param>
public void ProcessBlockColorsInto(
ref Block8x8 sourceBlock,
in BufferArea<float> destArea,
ref float destAreaOrigin,
int destAreaStride,
float maximumValue)
{
ref Block8x8F b = ref this.SourceBlock;
@ -88,7 +90,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// To be "more accurate", we need to emulate this by rounding!
this.WorkspaceBlock1.NormalizeColorsAndRoundInplace(maximumValue);
this.WorkspaceBlock1.CopyTo(destArea, this.subSamplingDivisors.Width, this.subSamplingDivisors.Height);
this.WorkspaceBlock1.CopyTo(
ref destAreaOrigin,
destAreaStride,
this.subSamplingDivisors.Width,
this.subSamplingDivisors.Height);
}
}
}
}

16
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs

@ -79,6 +79,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
var blockPp = new JpegBlockPostProcessor(this.ImagePostProcessor.RawJpeg, this.Component);
float maximumValue = MathF.Pow(2, this.ImagePostProcessor.RawJpeg.Precision) - 1;
int destAreaStride = this.ColorBuffer.Width;
for (int y = 0; y < this.BlockRowsPerStep; y++)
{
int yBlock = this.currentComponentRowInBlocks + y;
@ -90,22 +92,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int yBuffer = y * this.blockAreaSize.Height;
Span<float> colorBufferRow = this.ColorBuffer.GetRowSpan(yBuffer);
Span<Block8x8> blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock);
ref Block8x8 blockRowBase = ref MemoryMarshal.GetReference(blockRow);
for (int xBlock = 0; xBlock < this.SizeInBlocks.Width; xBlock++)
{
ref Block8x8 block = ref Unsafe.Add(ref blockRowBase, xBlock);
ref Block8x8 block = ref blockRow[xBlock];
int xBuffer = xBlock * this.blockAreaSize.Width;
ref float destAreaOrigin = ref colorBufferRow[xBuffer];
BufferArea<float> destArea = this.ColorBuffer.GetArea(
xBuffer,
yBuffer,
this.blockAreaSize.Width,
this.blockAreaSize.Height);
blockPp.ProcessBlockColorsInto(ref block, destArea, maximumValue);
blockPp.ProcessBlockColorsInto(ref block, ref destAreaOrigin, destAreaStride, maximumValue);
}
}

2
tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs

@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using (Buffer2D<float> buffer = Configuration.Default.MemoryAllocator.Allocate2D<float>(20, 20, AllocationOptions.Clean))
{
BufferArea<float> area = buffer.GetArea(5, 10, 8, 8);
block.Copy1x1Scale(area);
block.Copy1x1Scale(ref area.GetReferenceToOrigin(), area.Stride);
Assert.Equal(block[0, 0], buffer[5, 10]);
Assert.Equal(block[1, 0], buffer[6, 10]);

Loading…
Cancel
Save