FZGPUModules 2.0
GPU-accelerated modular compression pipelines
Loading...
Searching...
No Matches
speck2d_stage.h
Go to the documentation of this file.
1#pragma once
2
35#include "stage/stage.h"
36#include "fzm_format.h"
37#include "backend/types.h"
38#include <array>
39#include <cstdint>
40#include <cstring>
41#include <stdexcept>
42#include <string>
43#include <unordered_map>
44#include <vector>
45
46namespace fz {
47
50 uint32_t dim_x;
51 uint32_t dim_y;
52 int32_t B;
53 uint64_t nbits_a;
54
55 Speck2DConfig() : dim_x(0), dim_y(0), B(-1), nbits_a(0) {}
56};
57static_assert(sizeof(Speck2DConfig) <= FZM_STAGE_CONFIG_SIZE,
58 "Speck2DConfig must fit in FZM_STAGE_CONFIG_SIZE");
59
60class Speck2DStage : public Stage {
61public:
62 Speck2DStage() = default;
63 ~Speck2DStage() override;
64
65 // ── Stage control ─────────────────────────────────────────────────────────
66 void setInverse(bool inv) override { is_inverse_ = inv; }
67 bool isInverse() const override { return is_inverse_; }
68
69 void setDims(const std::array<size_t, 3>& dims) override { dims_ = dims; }
70 void setDims(size_t x, size_t y) { dims_ = {x, y, 1}; }
71
72 // ── Execution ─────────────────────────────────────────────────────────────
73 void execute(cudaStream_t stream, MemoryPool* pool,
74 const std::vector<void*>& inputs,
75 const std::vector<void*>& outputs,
76 const std::vector<size_t>& sizes) override;
77
81 void postStreamSync(cudaStream_t stream) override;
82
85 bool isGraphCompatible() const override { return false; }
86
87 // ── Metadata ──────────────────────────────────────────────────────────────
88 std::string getName() const override { return "SPECK2D"; }
89 size_t getNumInputs() const override { return 1; }
90 size_t getNumOutputs() const override { return 1; }
91
92 std::vector<size_t> estimateOutputSizes(
93 const std::vector<size_t>& input_sizes) const override {
94 if (input_sizes.empty()) return {0};
95 if (is_inverse_) {
96 // Exact: n int32 codes, from dims_ (nx*ny) -- NOT from input_sizes,
97 // which for the inverse direction is the COMPRESSED payload size and
98 // has no fixed relationship to the element count. dims_ is reliable
99 // in both cases that matter: a cold object reconstructed via
100 // deserializeHeader() (dims come from the header), and the SAME
101 // object reused in-memory across a compress-then-decompress cycle
102 // (dims_ was already set by setDims() at pipeline-build time and is
103 // never cleared). Falls back to input_sizes only if dims_ somehow
104 // isn't set yet, which estimateOutputSizes() can be called before
105 // execute() validates -- not reachable in normal pipeline use.
106 size_t n = (dims_[0] && dims_[1]) ? dims_[0] * dims_[1]
107 : input_sizes[0] / sizeof(int32_t);
108 return { n * sizeof(int32_t) };
109 }
110 // Worst case: nn (tree node count) <= 2n-1 (every internal node has
111 // >=2 children, a general property of this quadtree's partition -- see
112 // speck2d_kernels.cuh), nl == n exactly (every pixel is a leaf), and
113 // every present node/leaf costs at most 1 word (32 bits) -- see the
114 // words_ub comment in speck2d_stage.cu. So (2n + n) words is a safe
115 // upper bound; +margin for rounding.
116 size_t n = input_sizes[0] / sizeof(int32_t);
117 size_t words_ub = 3 * n + 8;
118 return { words_ub * sizeof(uint32_t) };
119 }
120
121 std::unordered_map<std::string, size_t>
122 getActualOutputSizesByName() const override {
123 return {{"output", actual_output_size_}};
124 }
125 size_t getActualOutputSize(int index) const override {
126 return index == 0 ? actual_output_size_ : 0;
127 }
128
129 // ── Type system ───────────────────────────────────────────────────────────
130 uint16_t getStageTypeId() const override {
131 return static_cast<uint16_t>(StageType::SPECK2D);
132 }
133 uint8_t getOutputDataType(size_t /*output_index*/) const override {
134 // Compressed payload is opaque bytes; decompressed output is INT32.
135 return is_inverse_ ? static_cast<uint8_t>(DataType::INT32)
136 : static_cast<uint8_t>(DataType::UNKNOWN);
137 }
138 uint8_t getInputDataType(size_t /*input_index*/) const override {
139 return is_inverse_ ? static_cast<uint8_t>(DataType::UNKNOWN)
140 : static_cast<uint8_t>(DataType::INT32);
141 }
142
143 // ── Serialization ─────────────────────────────────────────────────────────
144 size_t serializeHeader(size_t /*output_index*/, uint8_t* buf, size_t max_size) const override {
145 if (max_size < sizeof(Speck2DConfig))
146 throw std::runtime_error("Speck2DStage: header buffer too small");
147 Speck2DConfig cfg;
148 cfg.dim_x = static_cast<uint32_t>(dims_[0]);
149 cfg.dim_y = static_cast<uint32_t>(dims_[1]);
150 cfg.B = last_B_;
151 cfg.nbits_a = last_nbitsA_;
152 std::memcpy(buf, &cfg, sizeof(cfg));
153 return sizeof(cfg);
154 }
155 void deserializeHeader(const uint8_t* buf, size_t size) override {
156 if (size < sizeof(Speck2DConfig))
157 throw std::runtime_error("Speck2DStage: header too small");
158 Speck2DConfig cfg;
159 std::memcpy(&cfg, buf, sizeof(cfg));
160 dims_[0] = cfg.dim_x; dims_[1] = cfg.dim_y; dims_[2] = 1;
161 last_B_ = cfg.B;
162 last_nbitsA_ = cfg.nbits_a;
163 }
164 size_t getMaxHeaderSize(size_t /*output_index*/) const override {
165 return sizeof(Speck2DConfig);
166 }
167
168 void saveState() override { saved_dims_ = dims_; }
169 void restoreState() override { dims_ = saved_dims_; }
170
171private:
172 bool is_inverse_ = false;
173 size_t actual_output_size_ = 0;
174 std::array<size_t, 3> dims_ = {0, 0, 1};
175 std::array<size_t, 3> saved_dims_ = {0, 0, 1};
176 int32_t last_B_ = -1;
177 uint64_t last_nbitsA_ = 0;
178 uint64_t last_nbitsB_ = 0;
179
180 // Per-shape resident state (tree geometry + device buffers); opaque here,
181 // defined in speck2d_stage.cu to keep CUDA types out of this public header.
182 struct Impl;
183 Impl* impl_ = nullptr;
184
185 // Pending async scalar reads from the most recent forward execute(); valid
186 // only after postStreamSync() completes them.
187 bool pending_ = false;
188};
189
190} // namespace fz
FZM binary file format definitions — structs, enums, and helpers.
Definition dag.h:24
constexpr size_t FZM_STAGE_CONFIG_SIZE
Per-stage serialized config slot (bytes)
Definition fzm_format.h:65
@ SPECK2D
GPU-parallel "wavefront" SPECK-like coder (2-D), decode-parallel format.
DataType
Element data type identifiers used in buffer and stage descriptors.
Definition fzm_format.h:139
@ UNKNOWN
Byte-transparent stages: skip type checking at finalize()
Base class interface for all compression stages.
Serialized Speck2DStage config (FZMBufferEntry.stage_config). 24 bytes.
Definition speck2d_stage.h:49
uint32_t dim_y
Y dimension.
Definition speck2d_stage.h:51
uint32_t dim_x
X (fast) dimension.
Definition speck2d_stage.h:50
int32_t B
Root onset (max msb over the whole field); -1 = all-zero.
Definition speck2d_stage.h:52
uint64_t nbits_a
Section A bit length (locates Section B in the payload).
Definition speck2d_stage.h:53
Backend-neutral GPU type aliases.