From 15521be1c3dd52233c8bad6ae8dc61688f553abb Mon Sep 17 00:00:00 2001 From: Lauri Kotilainen Date: Fri, 12 Jan 2018 21:02:37 +0200 Subject: [PATCH] - Use fixed buffers in Huffman table --- .../Components/Decoder/InputProcessor.cs | 4 +- .../Components/Decoder/OrigHuffmanTree.cs | 154 ++++++++++-------- 2 files changed, 85 insertions(+), 73 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs index a7a5fcd986..5aa0fa3097 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs @@ -220,7 +220,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder if (this.LastErrorCode == OrigDecoderErrorCode.NoError) { int lutIndex = (this.Bits.Accumulator >> (this.Bits.UnreadBits - OrigHuffmanTree.LutSizeLog2)) & 0xFF; - int v = huffmanTree.Lut[lutIndex]; + int v = huffmanTree.ReadLut(lutIndex); if (v != 0) { @@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder this.Bits.UnreadBits--; this.Bits.Mask >>= 1; - if (code <= huffmanTree.MaxCodes[i]) + if (code <= huffmanTree.GetMaxCode(i)) { result = huffmanTree.GetValue(code, i); return this.LastErrorCode = OrigDecoderErrorCode.NoError; diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigHuffmanTree.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigHuffmanTree.cs index e96421a2d6..f773a12dfa 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigHuffmanTree.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigHuffmanTree.cs @@ -3,13 +3,14 @@ using System; using System.Buffers; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder { /// /// Represents a Huffman tree /// - internal struct OrigHuffmanTree + internal unsafe struct OrigHuffmanTree { /// /// The index of the AC table row @@ -67,29 +68,29 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// are 1 plus the code length, or 0 if the value is too large to fit in /// lutSize bits. /// - public int[] Lut; + public fixed int Lut[MaxNCodes]; /// /// Gets the the decoded values, sorted by their encoding. /// - public int[] Values; + public fixed int Values[MaxNCodes]; /// /// Gets the array of minimum codes. /// MinCodes[i] is the minimum code of length i, or -1 if there are no codes of that length. /// - public int[] MinCodes; + public fixed int MinCodes[MaxCodeLength]; /// /// Gets the array of maximum codes. /// MaxCodes[i] is the maximum code of length i, or -1 if there are no codes of that length. /// - public int[] MaxCodes; + public fixed int MaxCodes[MaxCodeLength]; /// /// Gets the array of indices. Indices[i] is the index into Values of MinCodes[i]. /// - public int[] Indices; + public fixed int Indices[MaxCodeLength]; /// /// Creates and initializes an array of instances of size @@ -97,16 +98,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// An array of instances representing the Huffman tables public static OrigHuffmanTree[] CreateHuffmanTrees() { - OrigHuffmanTree[] result = new OrigHuffmanTree[NumberOfTrees]; - for (int i = 0; i < MaxTc + 1; i++) - { - for (int j = 0; j < MaxTh + 1; j++) - { - result[(i * ThRowSize) + j].Init(); - } - } - - return result; + return new OrigHuffmanTree[NumberOfTrees]; } /// @@ -151,64 +143,73 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder byte[] values = new byte[MaxNCodes]; inputProcessor.ReadFull(values, 0, this.Length); - for (int i = 0; i < values.Length; i++) + fixed (int* valuesPtr = this.Values) + fixed (int* lutPtr = this.Lut) { - this.Values[i] = values[i]; - } - - // Derive the look-up table. - for (int i = 0; i < this.Lut.Length; i++) - { - this.Lut[i] = 0; - } + for (int i = 0; i < values.Length; i++) + { + valuesPtr[i] = values[i]; + } - int x = 0, code = 0; + // Derive the look-up table. + for (int i = 0; i < MaxNCodes; i++) + { + lutPtr[i] = 0; + } - for (int i = 0; i < LutSizeLog2; i++) - { - code <<= 1; + int x = 0, code = 0; - for (int j = 0; j < ncodes[i]; j++) + for (int i = 0; i < LutSizeLog2; i++) { - // The codeLength is 1+i, so shift code by 8-(1+i) to - // calculate the high bits for every 8-bit sequence - // whose codeLength's high bits matches code. - // The high 8 bits of lutValue are the encoded value. - // The low 8 bits are 1 plus the codeLength. - int base2 = code << (7 - i); - int lutValue = (this.Values[x] << 8) | (2 + i); - - for (int k = 0; k < 1 << (7 - i); k++) + code <<= 1; + + for (int j = 0; j < ncodes[i]; j++) { - this.Lut[base2 | k] = lutValue; + // The codeLength is 1+i, so shift code by 8-(1+i) to + // calculate the high bits for every 8-bit sequence + // whose codeLength's high bits matches code. + // The high 8 bits of lutValue are the encoded value. + // The low 8 bits are 1 plus the codeLength. + int base2 = code << (7 - i); + int lutValue = (valuesPtr[x] << 8) | (2 + i); + + for (int k = 0; k < 1 << (7 - i); k++) + { + lutPtr[base2 | k] = lutValue; + } + + code++; + x++; } - - code++; - x++; } } - // Derive minCodes, maxCodes, and indices. - int c = 0, index = 0; - for (int i = 0; i < ncodes.Length; i++) + fixed (int* minCodesPtr = this.MinCodes) + fixed (int* maxCodesPtr = this.MaxCodes) + fixed (int* indicesPtr = this.Indices) { - int nc = ncodes[i]; - if (nc == 0) - { - this.MinCodes[i] = -1; - this.MaxCodes[i] = -1; - this.Indices[i] = -1; - } - else + // Derive minCodes, maxCodes, and indices. + int c = 0, index = 0; + for (int i = 0; i < ncodes.Length; i++) { - this.MinCodes[i] = c; - this.MaxCodes[i] = c + nc - 1; - this.Indices[i] = index; - c += nc; - index += nc; - } + int nc = ncodes[i]; + if (nc == 0) + { + minCodesPtr[i] = -1; + maxCodesPtr[i] = -1; + indicesPtr[i] = -1; + } + else + { + minCodesPtr[i] = c; + maxCodesPtr[i] = c + nc - 1; + indicesPtr[i] = index; + c += nc; + index += nc; + } - c <<= 1; + c <<= 1; + } } } @@ -220,19 +221,30 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// The value public int GetValue(int code, int codeLength) { - return this.Values[this.Indices[codeLength] + code - this.MinCodes[codeLength]]; + fixed (int* valuesPtr = this.Values) + fixed (int* minCodesPtr = this.MinCodes) + fixed (int* indicesPtr = this.Indices) + { + return valuesPtr[indicesPtr[codeLength] + code - minCodesPtr[codeLength]]; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadLut(int index) + { + fixed (int* lutPtr = this.Lut) + { + return lutPtr[index]; + } } - /// - /// Initializes the Huffman tree - /// - private void Init() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int GetMaxCode(int index) { - this.Lut = new int[MaxNCodes]; - this.Values = new int[MaxNCodes]; - this.MinCodes = new int[MaxCodeLength]; - this.MaxCodes = new int[MaxCodeLength]; - this.Indices = new int[MaxCodeLength]; + fixed (int* maxCodesPtr = this.MaxCodes) + { + return maxCodesPtr[index]; + } } } } \ No newline at end of file