109#include <type_traits>
110#include <unordered_map>
116class GolombRiceStage :
public Stage {
117 static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
118 "GolombRiceStage requires a signed integer type");
120 GolombRiceStage() =
default;
121 ~GolombRiceStage()
override;
124 void setInverse(
bool inv)
override { is_inverse_ = inv; }
125 bool isInverse()
const override {
return is_inverse_; }
130 bool isGraphCompatible()
const override {
return !is_inverse_; }
132 void setChunkSize(
size_t bytes) { chunk_size_ =
static_cast<uint32_t
>(bytes); }
133 size_t getChunkSize()
const {
return chunk_size_; }
134 size_t getRequiredInputAlignment()
const override {
return chunk_size_; }
135 uint32_t getCachedOrigBytes()
const {
return cached_orig_bytes_; }
144 FusionSpec getFusionSpec()
const override {
145 if (is_inverse_ || chunk_size_ != 16384u || !std::is_same<T, int32_t>::value)
147 return FusionSpec{FusionAccess::SegmentCodec, chunk_size_};
151 FusedOpDecl getFusedOp()
const override {
152 if (!getFusionSpec().fusable())
return {};
153 return FusedOpDecl{FusionStrategy::ChunkCooperative,
"GolombRiceCoder",
154 "fused/chunk_fusion/chunk_fusion.cuh", {}};
157 void setFusedArchiveResult(
size_t archive_bytes,
size_t orig_bytes)
override {
158 setFusedResult(archive_bytes, orig_bytes);
165 void setFusedResult(
size_t archive_bytes,
size_t orig_bytes) {
166 actual_output_size_ = archive_bytes;
167 cached_orig_bytes_ =
static_cast<uint32_t
>(orig_bytes);
168 tail_readback_pending_ =
false;
175 const std::vector<void*>& inputs,
176 const std::vector<void*>& outputs,
177 const std::vector<size_t>& sizes
179 void postStreamSync(fz::stream_t stream)
override;
182 std::string getName()
const override {
return "GolombRice"; }
183 size_t getNumInputs()
const override {
return 1; }
184 size_t getNumOutputs()
const override {
return 1; }
186 std::vector<size_t> estimateOutputSizes(
187 const std::vector<size_t>& input_sizes
190 if (cached_orig_bytes_ > 0)
191 return {
static_cast<size_t>(cached_orig_bytes_)};
192 return {input_sizes.empty() ? 0 : input_sizes[0]};
197 const size_t n_bytes = input_sizes.empty() ? 0 : input_sizes[0];
198 const size_t n_chunks = (n_bytes + chunk_size_ - 1) / chunk_size_;
199 const size_t hdr = 4 + 4 + 4 * n_chunks;
200 const size_t worst = n_bytes + hdr + kTailPad;
201 return {(worst + 3) & ~
size_t(3)};
204 std::unordered_map<std::string, size_t>
205 getActualOutputSizesByName()
const override {
206 return {{
"output", actual_output_size_}};
208 size_t getActualOutputSize(
int index)
const override {
209 return index == 0 ? actual_output_size_ : 0;
223 size_t estimateScratchBytes(
224 const std::vector<size_t>& input_sizes
226 if (is_inverse_ || input_sizes.empty())
return 0;
227 const size_t in_bytes = input_sizes[0];
228 const size_t n_chunks = (in_bytes + chunk_size_ - 1) / chunk_size_;
229 return n_chunks * (chunkScratchStride() + 3 *
sizeof(uint32_t));
232 uint16_t getStageTypeId()
const override {
236 uint8_t getOutputDataType(
size_t)
const override {
237 return static_cast<uint8_t
>(DataType::UINT8);
241 static DataType getElementDataType() {
return fused::dataTypeOf<T>(); }
243 size_t serializeHeader(
size_t, uint8_t* buf,
size_t max_size)
const override {
244 if (max_size < 5)
return 0;
245 std::memcpy(buf, &chunk_size_,
sizeof(uint32_t));
246 buf[4] =
static_cast<uint8_t
>(getElementDataType());
249 void deserializeHeader(
const uint8_t* buf,
size_t size)
override {
250 if (size >= 4) std::memcpy(&chunk_size_, buf,
sizeof(uint32_t));
252 size_t getMaxHeaderSize(
size_t)
const override {
return 5; }
254 void saveState()
override { saved_chunk_size_ = chunk_size_; }
255 void restoreState()
override { chunk_size_ = saved_chunk_size_; }
258 uint32_t elemsPerChunk()
const {
return chunk_size_ /
static_cast<uint32_t
>(
sizeof(T)); }
263 static constexpr uint32_t kEscapeQ = 24;
264 static constexpr uint32_t bitWidth() {
return 8u *
sizeof(T); }
266 static constexpr uint32_t kMaxCandidate() {
return bitWidth() > 24 ? 24u : bitWidth() - 1; }
286 static constexpr uint32_t kIntervalsPerChunk = 16;
298 size_t chunkScratchStride()
const {
299 const size_t worst_bits =
static_cast<size_t>(elemsPerChunk()) * (kEscapeQ + bitWidth());
300 const size_t worst_bytes = (4 + 4 * kIntervalsPerChunk)
302 + (worst_bits + 7) / 8;
303 return ((worst_bytes + 3) & ~size_t(3)) + kTailPad;
305 static constexpr size_t kTailPad = 16;
308 bool is_inverse_ =
false;
309 uint32_t chunk_size_ = 16384;
310 uint32_t saved_chunk_size_ = 0;
311 size_t actual_output_size_ = 0;
312 uint32_t cached_orig_bytes_ = 0;
313 uint32_t saved_cached_orig_bytes_ = 0;
316 uint8_t* d_scratch_ =
nullptr;
317 uint32_t* d_sizes_dev_ =
nullptr;
318 uint32_t* d_dst_off_dev_ =
nullptr;
319 mutable bool tail_readback_pending_ =
false;
320 mutable uint32_t tail_last_index_ = 0;
321 mutable uint32_t tail_header_size_ = 0;
322 mutable uint8_t* tail_output_ptr_ =
nullptr;
323 size_t scratch_capacity_ = 0;
324 MemoryPool* scratch_pool_owner_ =
nullptr;
325 bool scratch_from_pool_ =
false;
326 std::weak_ptr<const void> scratch_alive_;
Compile-time C++ type -> DataType enum mapping, shared by the fused stages that dispatch on multiple ...
@ GOLOMB_RICE
Chunk-local Golomb-Rice entropy coder (exact per-chunk k, escape-bounded)
DataType
Element data type identifiers used in buffer and stage descriptors.
Definition fzm_format.h:142
Base class interface for all compression stages.
Backend-neutral GPU type aliases.