FZGPUModules 2.0
GPU-accelerated modular compression pipelines
Loading...
Searching...
No Matches
GpuANSCodec.h
1
9#ifndef FZ_ANS_DIETGPU_ANS_GPUANSCODEC_H
10#define FZ_ANS_DIETGPU_ANS_GPUANSCODEC_H
11
12#pragma once
13
14#include <assert.h>
15#include "utils/DeviceUtils.h"
16#include "utils/StaticUtils.h"
17
18namespace fz { namespace ans {
19
20using ANSStateT = uint32_t;
21using ANSEncodedT = uint16_t;
22using ANSDecodedT = uint8_t;
23
24struct __align__(16) ANSDecodedTx16 {
25 ANSDecodedT x[16];
26};
27
28struct __align__(8) ANSDecodedTx8 {
29 ANSDecodedT x[8];
30};
31
32struct __align__(4) ANSDecodedTx4 {
33 ANSDecodedT x[4];
34};
35
36constexpr uint32_t kNumSymbols = 1 << (sizeof(ANSDecodedT) * 8);
37static_assert(kNumSymbols > 1, "");
38
39// Default block size for compression (in bytes)
40constexpr uint32_t kDefaultBlockSize = 4096;
41
42// limit state to 2^31 - 1, so as to prevent addition overflow in the integer
43// division via mul and shift by constants
44constexpr int kANSStateBits = sizeof(ANSStateT) * 8 - 1;
45constexpr int kANSEncodedBits = sizeof(ANSEncodedT) * 8; // out bits
46constexpr ANSStateT kANSEncodedMask =
47 (ANSStateT(1) << kANSEncodedBits) - ANSStateT(1);
48
49constexpr ANSStateT kANSStartState = ANSStateT(1)
50 << (kANSStateBits - kANSEncodedBits);
51constexpr ANSStateT kANSMinState = ANSStateT(1)
52 << (kANSStateBits - kANSEncodedBits);
53
54// magic number to verify archive integrity
55constexpr uint32_t kANSMagic = 0xd00d;
56
57// current DietGPU version number
58constexpr uint32_t kANSVersion = 0x0001;
59
60// Each block of compressed data (either coalesced or uncoalesced) is aligned to
61// this number of bytes and has a valid (if not all used) segment with this
62// multiple of bytes
63constexpr uint32_t kBlockAlignment = 16;
64
65struct ANSWarpState {
66 // The ANS state data for this warp
67 ANSStateT warpState[kWarpSize];
68};
69
70struct __align__(32) ANSCoalescedHeader {
71 static __host__ __device__ uint32_t getCompressedOverhead(
72 uint32_t numBlocks) {
73 constexpr int kAlignment = kBlockAlignment / sizeof(uint2) == 0
74 ? 1
75 : kBlockAlignment / sizeof(uint2);
76
77 return sizeof(ANSCoalescedHeader) +
78 // probs
79 sizeof(uint16_t) * kNumSymbols +
80 // states
81 sizeof(ANSWarpState) * numBlocks +
82 // block words
83 sizeof(uint2) * roundUp(numBlocks, kAlignment);
84 }
85
86 __host__ __device__ uint32_t getTotalCompressedSize() const {
87 return getCompressedOverhead() +
88 getTotalCompressedWords() * sizeof(ANSEncodedT);
89 }
90
91 __host__ __device__ uint32_t getCompressedOverhead() const {
92 return getCompressedOverhead(getNumBlocks());
93 }
94
95 __host__ __device__ float getCompressionRatio() const {
96 return (float)getTotalCompressedSize() /
97 (float)getTotalUncompressedWords() * sizeof(ANSDecodedT);
98 }
99
100 __host__ __device__ uint32_t getNumBlocks() const { return numBlocks; }
101 __host__ __device__ void setNumBlocks(uint32_t nb) { numBlocks = nb; }
102
103 __host__ __device__ void setMagicAndVersion() {
104 magicAndVersion = (kANSMagic << 16) | kANSVersion;
105 }
106
107 __host__ __device__ void checkMagicAndVersion() const {
108 assert((magicAndVersion >> 16) == kANSMagic);
109 assert((magicAndVersion & 0xffffU) == kANSVersion);
110 }
111
112 __host__ __device__ uint32_t getTotalUncompressedWords() const {
113 return totalUncompressedWords;
114 }
115 __host__ __device__ void setTotalUncompressedWords(uint32_t words) {
116 totalUncompressedWords = words;
117 }
118
119 __host__ __device__ uint32_t getTotalCompressedWords() const {
120 return totalCompressedWords;
121 }
122 __host__ __device__ void setTotalCompressedWords(uint32_t words) {
123 totalCompressedWords = words;
124 }
125
126 __host__ __device__ uint32_t getProbBits() const { return options & 0xf; }
127 __host__ __device__ void setProbBits(uint32_t bits) {
128 assert(bits <= 0xf);
129 options = (options & 0xfffffff0U) | bits;
130 }
131
132 __host__ __device__ bool getUseChecksum() const { return options & 0x10; }
133 __host__ __device__ void setUseChecksum(bool uc) {
134 options = (options & 0xffffffef) | (uint32_t(uc) << 4);
135 }
136
137 __host__ __device__ uint32_t getChecksum() const { return checksum; }
138 __host__ __device__ void setChecksum(uint32_t c) { checksum = c; }
139
140 __device__ uint16_t* getSymbolProbs() {
141 return (uint16_t*)(this + 1);
142 }
143 __device__ const uint16_t* getSymbolProbs() const {
144 return (const uint16_t*)(this + 1);
145 }
146
147 __device__ ANSWarpState* getWarpStates() {
148 return (ANSWarpState*)(getSymbolProbs() + kNumSymbols);
149 }
150 __device__ const ANSWarpState* getWarpStates() const {
151 return (const ANSWarpState*)(getSymbolProbs() + kNumSymbols);
152 }
153
154 __device__ uint2* getBlockWords(uint32_t numBlocks) {
155 return (uint2*)(getWarpStates() + numBlocks);
156 }
157 __device__ const uint2* getBlockWords(uint32_t numBlocks) const {
158 return (const uint2*)(getWarpStates() + numBlocks);
159 }
160
161 __device__ ANSEncodedT* getBlockDataStart(uint32_t numBlocks) {
162 constexpr int kAlignment = kBlockAlignment / sizeof(uint2) == 0
163 ? 1
164 : kBlockAlignment / sizeof(uint2);
165 return (ANSEncodedT*)(getBlockWords(numBlocks) + roundUp(numBlocks, kAlignment));
166 }
167 __device__ const ANSEncodedT* getBlockDataStart(uint32_t numBlocks) const {
168 constexpr int kAlignment = kBlockAlignment / sizeof(uint2) == 0
169 ? 1
170 : kBlockAlignment / sizeof(uint2);
171 return (const ANSEncodedT*)(getBlockWords(numBlocks) + roundUp(numBlocks, kAlignment));
172 }
173
174 // (16: magic)(16: version)
175 uint32_t magicAndVersion;
176 uint32_t numBlocks;
177 uint32_t totalUncompressedWords;
178 uint32_t totalCompressedWords;
179
180 // (27: unused)(1: use checksum)(4: probBits)
181 uint32_t options;
182 uint32_t checksum;
183 uint32_t unused0;
184 uint32_t unused1;
185};
186
187static_assert(sizeof(ANSCoalescedHeader) == 32, "");
188static_assert(isEvenDivisor(sizeof(ANSCoalescedHeader), sizeof(uint4)), "");
189
190// Required minimum alignment in bytes of all data to be compressed in the batch
191constexpr int kANSRequiredAlignment = 4;
192
193constexpr int kANSDefaultProbBits = 10;
194
195// maximum raw compressed data block size in bytes
196constexpr __host__ __device__ uint32_t
197getRawCompBlockMaxSize(uint32_t uncompressedBlockBytes) {
198 return roundUp(
199 uncompressedBlockBytes + (uncompressedBlockBytes / 4), kBlockAlignment);
200}
201
202inline uint32_t getMaxBlockSizeUnCoalesced(uint32_t uncompressedBlockBytes) {
203 return sizeof(ANSWarpState) + getRawCompBlockMaxSize(uncompressedBlockBytes);
204}
205
206inline uint32_t getMaxBlockSizeCoalesced(uint32_t uncompressedBlockBytes) {
207 return getRawCompBlockMaxSize(uncompressedBlockBytes);
208}
209
210inline uint32_t getMaxCompressedSize(uint32_t uncompressedBytes) {
211 uint32_t blocks = divUp(uncompressedBytes, kDefaultBlockSize);
212
213 size_t rawSize = ANSCoalescedHeader::getCompressedOverhead(kDefaultBlockSize);
214 rawSize += (size_t)getMaxBlockSizeCoalesced(kDefaultBlockSize) * blocks;
215 rawSize = roundUp(rawSize, sizeof(uint4));
216
217 return rawSize;
218}
219
220struct BatchWriter {
221 inline __device__ BatchWriter(void* out)
222 : out_((uint8_t*)out), outBlock_(nullptr) {}
223
224 inline __device__ void setBlock(uint32_t block) {
225 outBlock_ = out_ + block * kDefaultBlockSize;
226 }
227
228 inline __device__ void write(uint32_t offset, uint8_t sym) {
229 outBlock_[offset] = sym;
230 }
231
232 uint8_t* out_;
233 uint8_t* outBlock_;
234};
235
236}} // namespace fz::ans
237
238#endif // FZ_ANS_DIETGPU_ANS_GPUANSCODEC_H
Definition dag.h:24