Skip to content

Commit 617c77c

Browse files
Lazily derive the huffman tables. Fix #839 (#841)
* Lazily derive the huffman tables. Fix #839 * Lazy invoke fast table * Add performance tweaks to scan decoder. * Remove unneccessary classes.
1 parent 8f3658d commit 617c77c

File tree

9 files changed

+209
-189
lines changed

9 files changed

+209
-189
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) Six Labors and contributors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System.Runtime.CompilerServices;
5+
6+
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
7+
{
8+
internal unsafe struct FastACTable
9+
{
10+
/// <summary>
11+
/// Gets the lookahead array
12+
/// </summary>
13+
public fixed short Lookahead[512];
14+
15+
/// <summary>
16+
/// Derives a lookup table for fast AC entropy scan decoding.
17+
/// This can happen multiple times during progressive decoding but always outside mcu loops.
18+
/// </summary>
19+
/// <param name="huffmanTable">The AC Huffman table.</param>
20+
public void Derive(ref HuffmanTable huffmanTable)
21+
{
22+
const int FastBits = ScanDecoder.FastBits;
23+
ref short fastACRef = ref this.Lookahead[0];
24+
ref byte huffmanLookaheadRef = ref huffmanTable.Lookahead[0];
25+
ref byte huffmanValuesRef = ref huffmanTable.Values[0];
26+
ref short huffmanSizesRef = ref huffmanTable.Sizes[0];
27+
28+
int i;
29+
for (i = 0; i < (1 << FastBits); i++)
30+
{
31+
byte fast = Unsafe.Add(ref huffmanLookaheadRef, i);
32+
Unsafe.Add(ref fastACRef, i) = 0;
33+
34+
if (fast < byte.MaxValue)
35+
{
36+
int rs = Unsafe.Add(ref huffmanValuesRef, fast);
37+
int run = (rs >> 4) & 15;
38+
int magbits = rs & 15;
39+
int len = Unsafe.Add(ref huffmanSizesRef, fast);
40+
41+
if (magbits != 0 && len + magbits <= FastBits)
42+
{
43+
// Magnitude code followed by receive_extend code
44+
int k = ((i << len) & ((1 << FastBits) - 1)) >> (FastBits - magbits);
45+
int m = 1 << (magbits - 1);
46+
if (k < m)
47+
{
48+
k += (int)((~0U << magbits) + 1);
49+
}
50+
51+
// If the result is small enough, we can fit it in fastAC table
52+
if (k >= -128 && k <= 127)
53+
{
54+
Unsafe.Add(ref fastACRef, i) = (short)((k << 8) + (run << 4) + (len + magbits));
55+
}
56+
}
57+
}
58+
}
59+
}
60+
}
61+
}

src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs

Lines changed: 0 additions & 90 deletions
This file was deleted.

src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
1717
[StructLayout(LayoutKind.Sequential)]
1818
internal unsafe struct HuffmanTable
1919
{
20+
private bool isDerived;
21+
22+
private readonly MemoryAllocator memoryAllocator;
23+
24+
#pragma warning disable IDE0044 // Add readonly modifier
25+
private fixed byte codeLengths[17];
26+
#pragma warning restore IDE0044 // Add readonly modifier
27+
2028
/// <summary>
2129
/// Gets the max code array
2230
/// </summary>
@@ -50,16 +58,31 @@ internal unsafe struct HuffmanTable
5058
/// <param name="values">The huffman values</param>
5159
public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLengths, ReadOnlySpan<byte> values)
5260
{
61+
this.isDerived = false;
62+
this.memoryAllocator = memoryAllocator;
63+
Unsafe.CopyBlockUnaligned(ref this.codeLengths[0], ref MemoryMarshal.GetReference(codeLengths), (uint)codeLengths.Length);
64+
Unsafe.CopyBlockUnaligned(ref this.Values[0], ref MemoryMarshal.GetReference(values), (uint)values.Length);
65+
}
66+
67+
/// <summary>
68+
/// Expands the HuffmanTable into its derived form.
69+
/// </summary>
70+
public void Derive()
71+
{
72+
if (this.isDerived)
73+
{
74+
return;
75+
}
76+
5377
const int Length = 257;
54-
using (IMemoryOwner<short> huffcode = memoryAllocator.Allocate<short>(Length))
78+
using (IMemoryOwner<short> huffcode = this.memoryAllocator.Allocate<short>(Length))
5579
{
5680
ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan());
57-
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths);
81+
ref byte codeLengthsRef = ref this.codeLengths[0];
5882

5983
// Figure C.1: make table of Huffman code length for each symbol
6084
ref short sizesRef = ref this.Sizes[0];
6185
short x = 0;
62-
6386
for (short i = 1; i < 17; i++)
6487
{
6588
byte length = Unsafe.Add(ref codeLengthsRef, i);
@@ -119,7 +142,7 @@ public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLeng
119142
}
120143
}
121144

122-
Unsafe.CopyBlockUnaligned(ref this.Values[0], ref MemoryMarshal.GetReference(values), 256);
145+
this.isDerived = true;
123146
}
124147
}
125148
}

src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTables.cs

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)