From b3c075a2e43fc2e8bc1c1715edca7be47f45d865 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 10 Nov 2016 03:20:51 +0100 Subject: [PATCH] ArrayPool --- .../Formats/Jpg/Components/Block.cs | 43 ++++++++++++++++++- .../Formats/Jpg/Components/IDCT.cs | 4 +- src/ImageSharp46/Formats/Jpg/JpegDecoder.cs | 6 ++- .../Formats/Jpg/JpegDecoderCore.cs | 35 ++++++++++----- .../Formats/Jpg/JpegEncoderCore.cs | 37 ++++++++-------- tests/ImageSharp.Tests46/JpegSandbox.cs | 3 ++ 6 files changed, 91 insertions(+), 37 deletions(-) diff --git a/src/ImageSharp46/Formats/Jpg/Components/Block.cs b/src/ImageSharp46/Formats/Jpg/Components/Block.cs index 168413292..e0be19206 100644 --- a/src/ImageSharp46/Formats/Jpg/Components/Block.cs +++ b/src/ImageSharp46/Formats/Jpg/Components/Block.cs @@ -3,6 +3,7 @@ // Licensed under the Apache License, Version 2.0. // +using System; using System.Buffers; namespace ImageSharp.Formats @@ -10,8 +11,10 @@ namespace ImageSharp.Formats /// /// Represents an 8x8 block of coefficients to transform and encode. /// - internal struct Block + internal struct Block : IDisposable { + private static ArrayPool IntArrayPool => ArrayPool.Shared; /*= ArrayPool.Create(BlockSize, 50);*/ + /// /// Gets the size of the block. /// @@ -32,7 +35,25 @@ namespace ImageSharp.Formats public void Init() { - this.Data = new int[BlockSize]; + //this.Data = new int[BlockSize]; + this.Data = IntArrayPool.Rent(BlockSize); + } + + public static Block Create() + { + var block = new Block(); + block.Init(); + return block; + } + + public static Block[] CreateArray(int size) + { + Block[] result = new Block[size]; + for (int i = 0; i < result.Length; i++) + { + result[i].Init(); + } + return result; } public bool IsInitialized => this.Data != null; @@ -49,5 +70,23 @@ namespace ImageSharp.Formats get { return this.Data[index]; } set { this.Data[index] = value; } } + + // TODO: Refactor Block.Dispose() callers to always use 'using' or 'finally' statement! + public void Dispose() + { + if (Data != null) + { + IntArrayPool.Return(Data, true); + Data = null; + } + } + + public static void DisposeAll(Block[] blocks) + { + for (int i = 0; i < blocks.Length; i++) + { + blocks[i].Dispose(); + } + } } } diff --git a/src/ImageSharp46/Formats/Jpg/Components/IDCT.cs b/src/ImageSharp46/Formats/Jpg/Components/IDCT.cs index 8bbbae357..4ca4ba903 100644 --- a/src/ImageSharp46/Formats/Jpg/Components/IDCT.cs +++ b/src/ImageSharp46/Formats/Jpg/Components/IDCT.cs @@ -41,10 +41,8 @@ namespace ImageSharp.Formats /// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984. /// /// The source block of coefficients - public static void Transform(ref Block block) + public static void Transform(ref Block src) { - - var src = block.Data; // Horizontal 1-D IDCT. for (int y = 0; y < 8; y++) { diff --git a/src/ImageSharp46/Formats/Jpg/JpegDecoder.cs b/src/ImageSharp46/Formats/Jpg/JpegDecoder.cs index 666f1b35a..d3c64a9c0 100644 --- a/src/ImageSharp46/Formats/Jpg/JpegDecoder.cs +++ b/src/ImageSharp46/Formats/Jpg/JpegDecoder.cs @@ -83,8 +83,10 @@ namespace ImageSharp.Formats Guard.NotNull(image, "image"); Guard.NotNull(stream, "stream"); - JpegDecoderCore decoder = new JpegDecoderCore(); - decoder.Decode(image, stream, false); + using (JpegDecoderCore decoder = new JpegDecoderCore()) + { + decoder.Decode(image, stream, false); + } } /// diff --git a/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs index d64803eb4..181211f4d 100644 --- a/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs +++ b/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Formats /// /// Performs the jpeg decoding operation. /// - internal class JpegDecoderCore + internal class JpegDecoderCore : IDisposable { /// /// The maximum (inclusive) number of bits in a Huffman code. @@ -201,7 +201,7 @@ namespace ImageSharp.Formats //this.huffmanTrees = new Huffman[MaxTc + 1, MaxTh + 1]; this.huffmanTrees = new Huffman[(MaxTc + 1)*(MaxTh + 1)]; - this.quantizationTables = new Block[MaxTq + 1]; + this.quantizationTables = Block.CreateArray(MaxTq + 1); this.temp = new byte[2 * Block.BlockSize]; this.componentArray = new Component[MaxComponents]; this.progCoeffs = new Block[MaxComponents][]; @@ -219,11 +219,11 @@ namespace ImageSharp.Formats } } - for (int i = 0; i < this.quantizationTables.Length; i++) - { - //this.quantizationTables[i] = new Block(); - this.quantizationTables[i].Init(); - } + //for (int i = 0; i < this.quantizationTables.Length; i++) + //{ + // //this.quantizationTables[i] = new Block(); + // this.quantizationTables[i].Init(); + //} //for (int i = 0; i < this.componentArray.Length; i++) //{ @@ -1576,7 +1576,7 @@ namespace ImageSharp.Formats int compIndex = scan[i].Index; if (this.progCoeffs[compIndex] == null) { - this.progCoeffs[compIndex] = new Block[mxx * myy * this.componentArray[compIndex].HorizontalFactor * this.componentArray[compIndex].VerticalFactor]; + this.progCoeffs[compIndex] = Block.CreateArray(mxx * myy * this.componentArray[compIndex].HorizontalFactor * this.componentArray[compIndex].VerticalFactor); for (int j = 0; j < this.progCoeffs[compIndex].Length; j++) { @@ -1668,11 +1668,13 @@ namespace ImageSharp.Formats } else { - var b = new Block(); - b.Init(); + var b = Block.Create(); + ProcessBlockImpl(ah, ref b, scan, i, zigStart, zigEnd, al, dc, compIndex, @by, mxx, hi, bx, ref this.quantizationTables[qtIndex] ); + + b.Dispose(); } } @@ -2252,5 +2254,18 @@ namespace ImageSharp.Formats private class EOFException : Exception { } + + public void Dispose() + { + Block.DisposeAll(this.quantizationTables); + + foreach (Block[] blocks in progCoeffs) + { + if (blocks != null) + { + Block.DisposeAll(blocks); + } + } + } } } diff --git a/src/ImageSharp46/Formats/Jpg/JpegEncoderCore.cs b/src/ImageSharp46/Formats/Jpg/JpegEncoderCore.cs index 9a282a72b..75e00bc76 100644 --- a/src/ImageSharp46/Formats/Jpg/JpegEncoderCore.cs +++ b/src/ImageSharp46/Formats/Jpg/JpegEncoderCore.cs @@ -579,7 +579,7 @@ namespace ImageSharp.Formats /// /// The destination block array /// The source block array. - private void Scale16X16To8X8(Block destination, Block[] source) + private void Scale16X16To8X8(ref Block destination, Block[] source) { for (int i = 0; i < 4; i++) { @@ -849,9 +849,9 @@ namespace ImageSharp.Formats where TColor : struct, IPackedPixel where TPacked : struct { - Block b = new Block(); - Block cb = new Block(); - Block cr = new Block(); + Block b = Block.Create(); + Block cb = Block.Create(); + Block cr = Block.Create(); // ReSharper disable once InconsistentNaming int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; @@ -865,6 +865,9 @@ namespace ImageSharp.Formats prevDCCr = this.WriteBlock(ref cr, QuantIndex.Chrominance, prevDCCr); } } + b.Dispose(); + cb.Dispose(); + cr.Dispose(); } /// @@ -878,22 +881,12 @@ namespace ImageSharp.Formats where TColor : struct, IPackedPixel where TPacked : struct { - Block b = new Block(); - Block[] cb = new Block[4]; - Block[] cr = new Block[4]; + Block b = Block.Create(); + Block[] cb = Block.CreateArray(4); + Block[] cr = Block.CreateArray(4); // ReSharper disable once InconsistentNaming int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; - - for (int i = 0; i < 4; i++) - { - cb[i] = new Block(); - } - - for (int i = 0; i < 4; i++) - { - cr[i] = new Block(); - } - + for (int y = 0; y < pixels.Height; y += 16) { for (int x = 0; x < pixels.Width; x += 16) @@ -907,12 +900,16 @@ namespace ImageSharp.Formats prevDCY = this.WriteBlock(ref b, QuantIndex.Luminance, prevDCY); } - this.Scale16X16To8X8(b, cb); + this.Scale16X16To8X8(ref b, cb); prevDCCb = this.WriteBlock(ref b, QuantIndex.Chrominance, prevDCCb); - this.Scale16X16To8X8(b, cr); + this.Scale16X16To8X8(ref b, cr); prevDCCr = this.WriteBlock(ref b, QuantIndex.Chrominance, prevDCCr); } } + + b.Dispose(); + Block.DisposeAll(cb); + Block.DisposeAll(cr); } /// diff --git a/tests/ImageSharp.Tests46/JpegSandbox.cs b/tests/ImageSharp.Tests46/JpegSandbox.cs index 2e9cdb894..d6e5bff4b 100644 --- a/tests/ImageSharp.Tests46/JpegSandbox.cs +++ b/tests/ImageSharp.Tests46/JpegSandbox.cs @@ -68,6 +68,9 @@ namespace ImageSharp.Tests { Vector hej = new Vector(); + + + Output.WriteLine(Vector.Count.ToString()); } }