<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.17 (Ruby 3.0.2) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-uralsky-gdeflate-00" category="info" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.22.0 -->
  <front>
    <title>GDEFLATE bitstream specification</title>
    <seriesInfo name="Internet-Draft" value="draft-uralsky-gdeflate-00"/>
    <author fullname="Yury Uralsky">
      <organization>NVIDIA Corporation</organization>
      <address>
        <email>yuralsky@nvidia.com</email>
      </address>
    </author>
    <date year="2024" month="July" day="07"/>
    <workgroup>Internet Engineering Task Force</workgroup>
    <keyword>deflate</keyword>
    <keyword>GPU decompression</keyword>
    <abstract>
      <?line 24?>

<t>This specification defines a lossless data compression algorithm
optimized for high-throughput decompression on many-core data-parallel
architectures. It is based on the original DEFLATE algorithm,
modifying its bit stream layout to facilitate efficient SIMD
decoding of the bitstream.</t>
    </abstract>
  </front>
  <middle>
    <?line 33?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>GDeflate is a lossless data compression algorithm optimized for
high-throughput decompression on many-core data-parallel architectures,
such as GPUs. It is based on the original DEFLATE algorithm, modifying
its bit stream layout to facilitate efficient SIMD decoding of the
bitstream. Modulo the bit stream formatting, GDeflate largely reuses the
compression scheme defined by RFC 1951, applying minimal changes. This
enables reuse of existing algorithms and other IP for compression and
decompression, only requiring changes to the addressing of the
bitstream.</t>
      <t>Throughout this document, familiarity with the original DEFLATE
algorithm and encoding principles is assumed. For full details on the
DEFLATE algorithm please refer to RFC 1951. Following sections will
focus on GDeflate-specific changes to the DEFLATE encoding and its
modified bit stream layout.</t>
    </section>
    <section anchor="deviations-from-the-original-deflate-encoding">
      <name>Deviations from the original DEFLATE encoding</name>
      <section anchor="deflate64-extensions">
        <name>DEFLATE64 extensions</name>
        <t>GDeflate directly integrates DEFLATE64 extensions (which were not
originally included in RFC 1951), allowing longer copies with distance
references spanning a range of up to 64KB. These extensions comprise the
following modifications: first, length code 285 is re-purposed to
represent an LZ copy of length in the range between 3 and 65538 bytes.
16 extra bits of unencoded length value follow this code. Second, two
previously unused distance codes 30 and 31 are now used to represent
look back distances of up to 65536 bytes. They are followed with 14
extra bits of unencoded distance value, specifying distances in the
range of 32769 to 49152 and 49153 to 65536 bytes, respectively.</t>
        <t>For completeness, modified tables of length and distance codes are
included below. Changes relative to the original tables (refer to
section 3.2.5 in RFC 1951) are highlighted:</t>
        <t>Length codes:</t>
        <table>
          <thead>
            <tr>
              <th align="center">Code</th>
              <th align="center">Extra Bits</th>
              <th align="center">Length(s)</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="center">257</td>
              <td align="center">0</td>
              <td align="center">3</td>
            </tr>
            <tr>
              <td align="center">258</td>
              <td align="center">0</td>
              <td align="center">4</td>
            </tr>
            <tr>
              <td align="center">259</td>
              <td align="center">0</td>
              <td align="center">5</td>
            </tr>
            <tr>
              <td align="center">260</td>
              <td align="center">0</td>
              <td align="center">6</td>
            </tr>
            <tr>
              <td align="center">261</td>
              <td align="center">0</td>
              <td align="center">7</td>
            </tr>
            <tr>
              <td align="center">262</td>
              <td align="center">0</td>
              <td align="center">8</td>
            </tr>
            <tr>
              <td align="center">263</td>
              <td align="center">0</td>
              <td align="center">9</td>
            </tr>
            <tr>
              <td align="center">264</td>
              <td align="center">0</td>
              <td align="center">10</td>
            </tr>
            <tr>
              <td align="center">265</td>
              <td align="center">1</td>
              <td align="center">11,12</td>
            </tr>
            <tr>
              <td align="center">266</td>
              <td align="center">1</td>
              <td align="center">13,14</td>
            </tr>
            <tr>
              <td align="center">267</td>
              <td align="center">1</td>
              <td align="center">15,16</td>
            </tr>
            <tr>
              <td align="center">268</td>
              <td align="center">1</td>
              <td align="center">17,18</td>
            </tr>
            <tr>
              <td align="center">269</td>
              <td align="center">2</td>
              <td align="center">19-22</td>
            </tr>
            <tr>
              <td align="center">270</td>
              <td align="center">2</td>
              <td align="center">23-26</td>
            </tr>
            <tr>
              <td align="center">271</td>
              <td align="center">2</td>
              <td align="center">27-30</td>
            </tr>
            <tr>
              <td align="center">272</td>
              <td align="center">2</td>
              <td align="center">31-34</td>
            </tr>
            <tr>
              <td align="center">273</td>
              <td align="center">3</td>
              <td align="center">35-42</td>
            </tr>
            <tr>
              <td align="center">274</td>
              <td align="center">3</td>
              <td align="center">43-50</td>
            </tr>
            <tr>
              <td align="center">275</td>
              <td align="center">3</td>
              <td align="center">51-58</td>
            </tr>
            <tr>
              <td align="center">276</td>
              <td align="center">3</td>
              <td align="center">59-66</td>
            </tr>
            <tr>
              <td align="center">277</td>
              <td align="center">4</td>
              <td align="center">67-82</td>
            </tr>
            <tr>
              <td align="center">278</td>
              <td align="center">4</td>
              <td align="center">83-98</td>
            </tr>
            <tr>
              <td align="center">279</td>
              <td align="center">4</td>
              <td align="center">99-114</td>
            </tr>
            <tr>
              <td align="center">280</td>
              <td align="center">4</td>
              <td align="center">115-130</td>
            </tr>
            <tr>
              <td align="center">281</td>
              <td align="center">5</td>
              <td align="center">131-162</td>
            </tr>
            <tr>
              <td align="center">282</td>
              <td align="center">5</td>
              <td align="center">163-194</td>
            </tr>
            <tr>
              <td align="center">283</td>
              <td align="center">5</td>
              <td align="center">195-226</td>
            </tr>
            <tr>
              <td align="center">284</td>
              <td align="center">5</td>
              <td align="center">227-257</td>
            </tr>
            <tr>
              <td align="center">
                <strong>285</strong></td>
              <td align="center">
                <strong>16</strong></td>
              <td align="center">
                <strong>3-65538</strong></td>
            </tr>
          </tbody>
        </table>
        <t>Distance codes:</t>
        <table>
          <thead>
            <tr>
              <th align="center">Code</th>
              <th align="center">Extra Bits</th>
              <th align="center">Distance</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="center">0</td>
              <td align="center">0</td>
              <td align="center">1</td>
            </tr>
            <tr>
              <td align="center">1</td>
              <td align="center">0</td>
              <td align="center">2</td>
            </tr>
            <tr>
              <td align="center">2</td>
              <td align="center">0</td>
              <td align="center">3</td>
            </tr>
            <tr>
              <td align="center">3</td>
              <td align="center">0</td>
              <td align="center">4</td>
            </tr>
            <tr>
              <td align="center">4</td>
              <td align="center">1</td>
              <td align="center">5,6</td>
            </tr>
            <tr>
              <td align="center">5</td>
              <td align="center">1</td>
              <td align="center">7,8</td>
            </tr>
            <tr>
              <td align="center">6</td>
              <td align="center">2</td>
              <td align="center">9-12</td>
            </tr>
            <tr>
              <td align="center">7</td>
              <td align="center">2</td>
              <td align="center">13-16</td>
            </tr>
            <tr>
              <td align="center">8</td>
              <td align="center">3</td>
              <td align="center">17-24</td>
            </tr>
            <tr>
              <td align="center">9</td>
              <td align="center">3</td>
              <td align="center">25-32</td>
            </tr>
            <tr>
              <td align="center">10</td>
              <td align="center">4</td>
              <td align="center">33-48</td>
            </tr>
            <tr>
              <td align="center">11</td>
              <td align="center">4</td>
              <td align="center">49-64</td>
            </tr>
            <tr>
              <td align="center">12</td>
              <td align="center">5</td>
              <td align="center">65-96</td>
            </tr>
            <tr>
              <td align="center">13</td>
              <td align="center">5</td>
              <td align="center">97-128</td>
            </tr>
            <tr>
              <td align="center">14</td>
              <td align="center">6</td>
              <td align="center">129-192</td>
            </tr>
            <tr>
              <td align="center">15</td>
              <td align="center">6</td>
              <td align="center">193-256</td>
            </tr>
            <tr>
              <td align="center">16</td>
              <td align="center">7</td>
              <td align="center">257-384</td>
            </tr>
            <tr>
              <td align="center">17</td>
              <td align="center">7</td>
              <td align="center">385-512</td>
            </tr>
            <tr>
              <td align="center">18</td>
              <td align="center">8</td>
              <td align="center">513-768</td>
            </tr>
            <tr>
              <td align="center">19</td>
              <td align="center">8</td>
              <td align="center">769-1024</td>
            </tr>
            <tr>
              <td align="center">20</td>
              <td align="center">9</td>
              <td align="center">1025-1536</td>
            </tr>
            <tr>
              <td align="center">21</td>
              <td align="center">9</td>
              <td align="center">1537-2048</td>
            </tr>
            <tr>
              <td align="center">22</td>
              <td align="center">10</td>
              <td align="center">2049-3072</td>
            </tr>
            <tr>
              <td align="center">23</td>
              <td align="center">10</td>
              <td align="center">3073-4096</td>
            </tr>
            <tr>
              <td align="center">24</td>
              <td align="center">11</td>
              <td align="center">4097-6144</td>
            </tr>
            <tr>
              <td align="center">25</td>
              <td align="center">11</td>
              <td align="center">6145-8192</td>
            </tr>
            <tr>
              <td align="center">26</td>
              <td align="center">12</td>
              <td align="center">8193-12288</td>
            </tr>
            <tr>
              <td align="center">27</td>
              <td align="center">12</td>
              <td align="center">12289-16384</td>
            </tr>
            <tr>
              <td align="center">28</td>
              <td align="center">13</td>
              <td align="center">16385-24576</td>
            </tr>
            <tr>
              <td align="center">29</td>
              <td align="center">13</td>
              <td align="center">24577-32768</td>
            </tr>
            <tr>
              <td align="center">
                <strong>30</strong></td>
              <td align="center">
                <strong>14</strong></td>
              <td align="center">
                <strong>32769-49152</strong></td>
            </tr>
            <tr>
              <td align="center">
                <strong>31</strong></td>
              <td align="center">
                <strong>14</strong></td>
              <td align="center">
                <strong>49153-65536</strong></td>
            </tr>
          </tbody>
        </table>
      </section>
      <section anchor="formatting-of-non-compressed-blocks">
        <name>Formatting of non-compressed blocks</name>
        <t>GDeflate also changes formatting of non-compressed blocks (BTYPE=00,
refer to section 3.2.4 in RFC 1951). In the original DEFLATE algorithm,
non-compressed blocks start with a block-specific header specifying
their length in bytes as a 16 bit value, followed by its one's
complement. The header is also specified to start on a byte-aligned
boundary. In GDeflate, the one's complement of length is dropped from
the header and the header is no longer required to be byte-aligned. As a
result, data across all blocks, compressed or non-compressed, forms one
contiguous bit stream. This streamlines SIMD decoding of the entire bit
stream, as will be explained
later.</t>
      </section>
    </section>
    <section anchor="general-assumptions-and-the-machine-model">
      <name>General assumptions and the machine model</name>
      <t>GDeflate assumes that decoding is done on a multi-threaded many-core
SIMD or SIMT machine with 32 bit registers and 32 bit memory access
grain. It is expected that per-lane operations can be predicated, and
that there is support for basic cross-lane communication and
synchronization, allowing to construct fundamental data parallel
primitives such as reductions and prefix sums.</t>
      <t>GDeflate targets SIMD width of 32, which aligns well with most common
CPU and GPU architectures today and in foreseeable future. Machines with
narrower physical SIMD width can serialize decoding, or assign multiple
SIMD threads to decode a single GDeflate bit stream. As an extreme
example, GDeflate can be decoded on a fully scalar processor without any
SIMD support. Machines with wider SIMD width can decode multiple
GDeflate bit streams using a single SIMD group, or choose to leave a
subset of SIMD lanes idle during decoding.</t>
      <t>In the discussion below, the term "SIMD group" can refer to a
cooperative thread group, a warp, or a SIMD instruction or several SIMD
instructions, depending on the implementation. The SIMD group is assumed
to comprise 32 parallel "lanes", even though the physical SIMD width of
the underlying implementation may be wider or narrower.</t>
    </section>
    <section anchor="high-level-blocking-of-gdeflate-stream">
      <name>High-level blocking of GDeflate stream</name>
      <t>At high-level, GDeflate splits the data to be compressed into pages of
64KB in size. The pages are completely independent, enabling compression
and decompression to operate on multiple pages in parallel. The
expectation is that each page will be processed by a physical thread, or
a separate core.</t>
      <t>64KB page blocking enables random access to compressed data at page
granularity and allows GDeflate bit streams to be used directly with
applications utilizing sparse/tiled resource infrastructure available in
modern graphics APIs.</t>
      <t>Any higher-level enveloping of the bitstream is not discussed in this
specification. It is assumed that the application will use a separate
data structure (such as an array of pointers) in order to address pages
comprising their overall compressed data set.</t>
    </section>
    <section anchor="bit-stream-rearrangement-for-simd-parallelism">
      <name>Bit stream rearrangement for SIMD parallelism</name>
      <t>The key change that GDeflate makes to the original DEFLATE bit stream
layout is rearranging the way its variable-length codes (representing
literals, copies, or other auxiliary meta-data) are ordered in the bit
stream.</t>
      <t>In the original DEFLATE algorithm, these variable-length codes are
ordered linearly, assuming the decoder consumes these codes one at a
time as it traverses the bit stream serially. While simple to
understand, this serial ordering makes it difficult to efficiently
utilize SIMD processing on a data-parallel machine, due to serial
dependencies between the codes: decoding of the immediately following
code cannot start until the bit length of the current code is determined
and it is fully consumed.</t>
      <section anchor="sub-streams-and-ordering-of-symbols">
        <name>Sub-streams and ordering of symbols</name>
        <t>To enable parallel parsing of the bit stream, GDeflate splits the
original sequence of variable-length codes into 32 independent
sub-streams. Each sub-stream is assigned to a fixed SIMD lane, so all
lanes in the SIMD group can collectively parse all 32 sub-streams in
parallel. Each iteration of the parsing process is referred to as "SIMD
round". At each SIMD round, 32 codes from 32 sub-streams are decoded
into symbols, with one code processed in each lane (with some exceptions
detailed in the following sections).</t>
        <t>Within a SIMD round, decoded symbols follow the SIMD lane order. For
example, symbols corresponding to entropy-coded data within compressed
blocks (literal bytes and LZ copies) which are processed within the same
round always map to a contiguous range of memory addresses in the output
buffer: this allows all decoded symbols to be written as a dense SIMD
memory write (assuming each SIMD lane computes its output pointer
accordingly). Once a SIMD round is complete, the SIMD group proceeds to
the next round, decoding the next group of 32 symbols from 32
sub-streams, advancing its input and output pointers. Thus, across SIMD
rounds, corresponding groups of 32 symbols follow sequentially.</t>
      </section>
      <section anchor="packing-of-variable-length-codes-within-sub-streams">
        <name>Packing of variable-length codes within sub-streams</name>
        <t>To enable concurrent processing of sub-streams, GDeflate packs the
variable-length codes, comprising individual sub-streams into a set of
naturally aligned 32 bit words, which can be directly addressed by the
SIMD group. As a result, the bit stream is always accessed at word
granularity: at each SIMD round, at most a single aligned 32 bit word is
read from each sub-stream (therefore, at most 32 memory reads can be
performed during a round across all lanes). These reads are done on
as-needed basis: each lane keeps track of the number of bits it is yet
to decode from the previous SIMD round, and when that number drops below
a threshold, a memory read on the current SIMD round is scheduled. The
bits returned by the new memory read are appended to the bits remaining
to be decoded in that lane, so that the lane can proceed to decoding a
symbol. Once a symbol is decoded, its corresponding code is consumed,
reducing the number of bits available for decoding on the next round,
which will eventually trigger another memory read in one of the
subsequent rounds.</t>
        <t>In GDeflate, the longest possible code contains 31 bits: 15 bits of the
worst-case Huffman code (per DEFLATE spec) plus maximum of 16 extra bits
(this could happen for the length symbol of a long LZ copy).
Consequently, the memory read threshold in GDeflate is set to 32 bits
(rounding up). This ensures that at any time during parsing, at least 32
bits of the sub-stream data are immediately available for decoding in
each lane, and hence at least one symbol per lane can be fully decoded
on each SIMD round.</t>
        <t>Note that as a result of this packing, variable-length codes may be
split across words. However, no variable-length code (including any
extra bits it may require) can span more than 2 words, so reading a
single word always adds enough data to guarantee that at least 1 symbol
can be decoded per lane.</t>
        <t>It is expected that implementations will maintain this per lane state in
a pair of 32 bit registers and a counter variable tracking how many bits
are currently valid. When the number of valid bits in the state variable
drops below 32, a new 32 bit word is read from memory and appended to
the state variable. Corresponding memory addresses for these reads can
be computed by cooperative data-parallel operations across the SIMD
group, such as prefix sums. Bits consumed during decoding can be removed
from the state variable by shifting the register pair down.</t>
        <t>The following pseudocode illustrates the process of reading the
bitstream:</t>
        <artwork><![CDATA[
// For each SIMD lane in parallel ...

uint64_t bitBuffer; // State variable
uint     bitCount;  // Number of valid bits in the state variable

bool isRefillRequired = bitCount < 32;  // Generate refill predicate
                                        // for this lane

uint32_t refillMask = vote(isRefillRequired);   // Collect refill
    // predicates across all lanes into a mask

// Compute this lane's offset as a prefix sum over refill mask
uint localOffset = countbits(refillMask & ((1 << lane) - 1));

if (isRefillRequired) { // On a refill ...
    // ... Append new bits to the state variable
    bitBuffer |= (uint64_t)input[localOffset] << bitCount;
    bitCount += 32; // ... Track the number of valid bits available
}

// Lane 0 advances shared input pointer
if (lane == 0) input += countbits(refillMask);

// Proceed to decoding variable-length codes contained in
// LSBs of bitBuffer
]]></artwork>
      </section>
      <section anchor="initial-decoder-state-and-formatting-of-the-final-bit-stream">
        <name>Initial decoder state and formatting of the final bit stream</name>
        <t>At the start of decoding, state variables in all SIMD lanes are
initialized to contain 0 bits. Therefore, the first SIMD round of
decoding always loads 32 consecutive words from the input stream,
effectively initializing state variables of all 32 sub-streams. As a
result, any valid GDeflate bit stream cannot be smaller than 4 * 32 =
128 bytes. Subsequent rounds will load variable number of words from the
input, depending on the rate at which each SIMD lane consumes codes from
the sub-stream it is responsible for.</t>
        <t>The final bit stream comprises words from the 32 sub-stream interleaved
in the order in which they are read during decoding. Note that this
reordering/interleaving applies end-to-end across all blocks in the bit
stream, disregarding block boundaries. Effectively, GDeflate treats the
entire bit stream as a contiguous sequence of variable-length codes,
permuted and packed into sub-streams as described above. Words residing
at the very end of the bit stream may not be fully packed with
variable-length codes, which means leaving some available bits unused.
This tail effect represents certain small overhead introduced by the
SIMD-oriented rearrangement of data in the bit stream.</t>
      </section>
      <section anchor="parsing-example">
        <name>Parsing example</name>
        <t>To illustrate the parsing process, consider the following bit stream
layout. The numbers indicate byte addresses of corresponding 32 bit
words in the bit stream. Letters represent variable-length codes packed
within their respective words. Note that some codes are split across two
words - this is indicated with a dot to the left or to the right of the
corresponding letter. The sets of 32b words loaded on each SIMD round
are shown underneath the boxes.</t>
        <artwork><![CDATA[
0       4       8       12     124     128
+-------+-------+-------+-     -+-------+
|A,B,C. | D,E.  |F,G,H,I|  ...  | J,K.  |
+-------+-------+-------+-     -+-------+
|<----------- SIMD round 0 ------------>|


128     132     136     252     256     K      K+4     K+8
+-------+-------+-     -+-------+-    -+-------+-------+-------+
|  .C,L |.E,M,N |  ...  | .K,O  |  ... | X,Y.  |   Z.  |  .W   |
+-------+-------+-     -+-------+-    -+-------+-------+-------+
|<------- SIMD round 1 -------->|      |<--- SIMD round N ---->|
]]></artwork>
        <t>On the very first SIMD round, the decoder loads the initial set of 32
words from the input stream, at contiguous memory addresses spanning the
first 128 bytes. This initializes per-lane state variables in each SIMD
lane with 32 bits of input data, which contain packed variable-length
codes. On this first round, the SIMD group processes codes A,D,F...J (in
that order) which all come from 32 separate sub-streams. Processed codes
are removed from their respective per-lane state variables. At that
point, the number of valid bits available for decoding in each lane
drops below 32, and hence on the second round each lane loads another
4-byte word of input, which reside at addresses 128 through 252 in the
input stream, appending loaded bits to the valid bits remaining from the
first round. On the second round, codes B,E,G...K from the 32
sub-streams are processed by the SIMD group. Note that code E was split
across two words, residing at byte addresses 4 and 132. On the second
round, all bits of E become available in the lane #1's state variable,
hence it can be fully decoded on that round. The same situation applies
to code K, split across words at addresses 124 and 252. At the end of
the second round, the codes were processed in the following order:
A,D,F...J,B,E,G...K.</t>
        <t>The decoding process continues, however on subsequent rounds the SIMD
group will likely be loading fewer than 32 words of input. In our
example, on round N the SIMD group loads only 3 additional words, at
byte addresses K through K+8. Which lanes perform these loads is a
function of the number of valid bits remaining in per-lane state from
previous rounds, which is in turn a function of how many variable-length
codes were packed in the corresponding sub-stream processed by that lane
so far. In essence, each sub-stream is represented by a chain of 32b
words scattered in the input stream. All lanes in the SIMD group
collectively traverse 32 such sub-streams, cooperatively computing
memory addresses for each lane from round to round.</t>
      </section>
    </section>
    <section anchor="block-headers">
      <name>Block headers</name>
      <t>Like in standard DEFLATE, each GDeflate block starts with a generic 3
bit header. The first bit indicates whether this block is the last block
in the stream, and the following two bits encode the block type (see
section 3.2.3 in the DEFLATE RFC for details).</t>
      <t>Additionally, non-compressed blocks and blocks compressed with dynamic
huffman codes (BTYPE=00 and BTYPE=10, respectively) also include their
own block-specific headers: headers for non-compressed blocks are 16
bits long (see section 2.2), and headers for dynamic huffman blocks are
14 bits long.</t>
      <t>In GDeflate, all block headers are always assigned to sub-stream 0 and
require one dedicated SIMD round of processing per header, where only 1
SIMD lane is active. The other 31 lanes do not modify their state
variables during the header decode round.</t>
      <t>This implies that non-compressed blocks and blocks encoded with dynamic
huffman codes process their headers in 2 SIMD rounds (1 round for the
generic header and 1 additional round for the block-specific header).
During both rounds, only 1 SIMD lane is active. Header data is then
broadcast to all SIMD lanes.</t>
      <t>Blocks encoded with fixed huffman trees do not have block-specific
headers, and therefore it takes only 1 SIMD round to decode their
generic header.</t>
    </section>
    <section anchor="non-compressed-blocks">
      <name>Non-compressed blocks</name>
      <t>The data in the body of non-compressed blocks is distributed across 32
sub-streams and goes through the same reordering described in section 5.
"Codes" in each sub-stream within non-compressed blocks are assumed to
be fixed-size 8 bit atoms, so on every SIMD round each lane writes a
byte to the output buffer and removes exactly 8 bits from its state
variable. Thus, when processing non-compressed blocks each SIMD round
loads eight 32 bit words from the input stream in steady state. The
number of full SIMD rounds required to process a non-compressed block is
determined by floor(block_size_in_bytes / 32). On the last SIMD round,
only (block_size_in_bytes % 32) SIMD lanes are active, remaining lanes
stay idle and do not change their state variables.</t>
    </section>
    <section anchor="blocks-compressed-with-dynamic-huffman-codes">
      <name>Blocks compressed with dynamic huffman codes</name>
      <section anchor="code-lengths-for-the-huffman-trees-alphabet">
        <name>Code lengths for the huffman trees alphabet</name>
        <t>In blocks compressed with dynamic huffman codes, the header is followed
by an array of up to 19 three bit values, specifying code lengths for
the code length alphabet used to describe the huffman trees. Each code
length value gets assigned to a separate sub-stream, and hence SIMD
lane, therefore all code length values are processed within a single
SIMD round. At least 32 - 19 = 13 SIMD lanes remain inactive in this
round and do not modify their state variables. The actual number of
sub-streams used (and hence the number of SIMD lanes that participate in
this round) is specified in the header (value of field HCLEN + 4). Each
active lane decodes a fixed-length 3 bit code on this round before the
SIMD groups proceeds to the next section.</t>
      </section>
      <section anchor="huffman-trees-meta-data">
        <name>Huffman trees meta-data</name>
        <t>Block-specific huffman trees represented in the form of compressed
arrays of code length values for literal/length and distance tables are
encoded next in the bitstream. There can be up to 318 symbols in this
section (up to 286 literal/length symbols plus up to 32 distance
symbols), encoded with variable-length codes. These codes are evenly
distributed across 32 sub-streams and require up to 10 (corresponding to
the maximum of 318 symbols) SIMD rounds to process. The ordering of
symbols in this section follows the rules described in section 5: each
SIMD round processes a group of 32 consecutive symbols, with groups
ordered sequentially as they are processed.</t>
      </section>
    </section>
    <section anchor="blocks-compressed-with-static-huffman-codes">
      <name>Blocks compressed with static huffman codes</name>
      <t>Blocks compressed with static huffman codes have no block-specific
headers, and use pre-defined huffman tables as per RFC 1951. The
entropy-coded data within such blocks is ordered analogously to dynamic
huffman blocks (i.e. distributed across all 32 sub-streams).</t>
    </section>
    <section anchor="processing-of-the-end-of-block-symbol">
      <name>Processing of the end-of-block symbol</name>
      <t>Blocks compressed using either dynamic or static huffman codes utilize a
special end-of-block symbol (code 256) to indicate the end of compressed
data for that block. The decoder is expected to monitor whether such
code is detected on one of the SIMD rounds. If that is the case, that
SIMD round is considered to be the last round for that block, and all
SIMD lanes following the lane that has decoded the end-of-block symbol
should not attempt to perform symbol decode and consume any bits from
their state variables, leaving them unmodified instead: those bits
belong to the immediately following block, and will get used shortly
after it starts getting decoded.</t>
    </section>
    <section anchor="lz-copy-scheduling">
      <name>LZ copy scheduling</name>
      <t>GDeflate is designed to process (up to) 32 symbols per SIMD round, with
each lane decoding a single symbol from a separate sub-stream. Since LZ
copies are specified using two symbols (a length symbol followed by a
distance symbol), copy processing is always split across two SIMD
rounds. On the first SIMD round, the length symbol is decoded and the
corresponding amount of space is reserved in the output buffer. On the
immediately following SIMD round, the distance symbol is decoded and the
copy is performed, filling the previously reserved space. The two
symbols are always assigned to the same sub-stream so that they get
processed by the same SIMD lane during two back-to-back SIMD rounds -
this ensures that the state necessary to perform the copy doesn't have
to migrate across SIMD lanes and the copy scheduling can be implemented
with a simple per-lane state machine.</t>
    </section>
    <section anchor="normative-references">
      <name>Normative References</name>
      <ul spacing="normal">
        <li>
          <t><eref target="https://www.ietf.org/rfc/rfc1951.txt">Original DEFLATE specification, RFC 1951</eref></t>
        </li>
        <li>
          <t><eref target="https://github.com/microsoft/DirectStorage/blob/main/GDeflate/shaders/GDeflate.hlsl">Reference implementation of GDeflate decompressor as a compute shader</eref></t>
        </li>
      </ul>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>Any data compression method involves the reduction of redundancy in
the data.  Consequently, any corruption of the data is likely to have
severe effects and be difficult to correct. Uncompressed text, on
the other hand, will probably still be readable despite the presence
of some corrupted bytes. It is recommended that systems using this
data format provide some means of validating the integrity of the
compressed data.</t>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
    <section anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>Trademarks cited in this document are the property of their
respective owners.</t>
      <t>Yury Uralsky, Ilya Terentyev, Vikram Kushwaha, Akshay Subramaniam and
Nikolay Sakharnykh contributed to GDeflate and this document.</t>
      <t>Phil Katz designed the deflate format. Nvidia Corporation modified its
bit stream layout to facilitate efficient SIMD decoding of the bitstream.</t>
    </section>
  </middle>
  <back>






  </back>
  <!-- ##markdown-source:
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

-->

</rfc>
