Source browser
examples/evt3_support.hpp
Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.
File fingerprint
1/** @file evt3_support.hpp
2 * @brief Reusable host wiring for a compact, streaming EVT3 example.
3 * Native shaders parse packed words, resolve block state, scan output lengths,
4 * and emit into disjoint intervals. Host readback is required only by a consumer.
5 */
6#ifndef SHDR_EXAMPLES_EVT3_SUPPORT_HPP // Open this include guard or optional feature branch.
7#define SHDR_EXAMPLES_EVT3_SUPPORT_HPP // Define SHDR_EXAMPLES_EVT3_SUPPORT_HPP for the declarations that follow.
8#include "shdr.h" // Include shdr.h declarations.
9#include <algorithm> // Include algorithm declarations.
10#include <cstdint> // Include cstdint declarations.
11#include <random> // Include random declarations.
12#include <vector> // Include vector declarations.
13
14namespace shdr_examples { // Group these helpers within their namespace.
15
16/** @brief Stateful four-stage decoder. reset_pipeline() adds a GPU/CPU reset stage.
17 * Each uvec4 event stores X, packed Y/polarity/camera, and low/high uint32 timestamp.
18 * Triggers use channel ID as X and set bit31 of the second component, with edge in bit0.
19 * Output ordering follows input ordering. Metadata extensions are skipped. Use
20 * separate decoder objects for independently queued streams or concurrent workers.
21 */
22class evt3_decoder { // Declare evt3 decoder.
23 unsigned capacity_, block_size_, count_, blocks_; // Declare capacity for the following calculation.
24 std::unique_ptr<shdr::kernel> summary_, seed_, prefix_, emit_, reset_; // Declare summary for the following calculation.
25 shdr::buffer<unsigned> packed_, sizes_; // Declare packed for the following calculation.
26 shdr::buffer<shdr::glsl::uvec4> summaries_, seeds_; // Declare summaries for the following calculation.
27 shdr::pipeline stream_, independent_; // Declare stream for the following calculation.
28 static unsigned capacity(unsigned n) { // Implement capacity for the operations below.
29 if (!n || n > 0xffffffffu / 12u) // Check this condition before entering the following branch.
30 throw shdr::error( // Report this failed operation.
31 "EVT3 word capacity must be positive and fit worst-case output offsets"); // Provide this text argument for the operation above.
32 return n; // Return n.
33 } // End this block.
34 static unsigned block(unsigned n) { // Implement block for the operations below.
35 if (!n || n > 4096u) // Check this condition before entering the following branch.
36 throw shdr::error("EVT3 block size must be between 1 and 4096 words"); // Report EVT3 block size must be between 1 and 4096 words.
37 return n; // Return n.
38 } // End this block.
39
40 public: // Set public access for the following class members.
41 shdr::buffer<shdr::glsl::uvec4> events; // Declare events for the following calculation.
42 shdr::buffer<unsigned> offsets; // Declare offsets for the following calculation.
43 shdr::buffer<shdr::glsl::uvec4> state; // Declare state for the following calculation.
44
45 /** @brief Allocate reusable storage, including worst-case twelve events per word. */
46 explicit evt3_decoder(unsigned max_words, unsigned block_size = 128) // Set block size from this expression.
47 : capacity_(capacity(max_words)), block_size_(block(block_size)), count_(0), blocks_(0), // Declare capacity with the parameters continued below.
48 summary_(shdr::make_kernel("evt3_summary_kernel")), // Create the linked evt3 summary kernel instance.
49 seed_(shdr::make_kernel("evt3_seed_kernel")), // Create the linked evt3 seed kernel instance.
50 prefix_(shdr::make_kernel("rle_offsets_kernel")), // Create the linked rle offsets kernel instance.
51 emit_(shdr::make_kernel("evt3_emit_kernel")), // Create the linked evt3 emit kernel instance.
52 reset_(shdr::make_kernel("evt3_reset_kernel")), packed_((capacity_ + 1u) / 2u), // Create the linked evt3 reset kernel instance.
53 sizes_((capacity_ + block_size_ - 1u) / block_size_), summaries_(sizes_.size() * 3u), // Apply sizes to these arguments.
54 seeds_(sizes_.size() * 2u), events(capacity_ * 12u), offsets(sizes_.size() + 1u), // Apply seeds to these arguments.
55 state(2) { // Apply state to these arguments.
56 summary_->bind("packed_words", packed_) // Connect this shader port to its application resource.
57 .bind("summaries", summaries_) // Connect this shader port to its application resource.
58 .set("block_size", block_size_); // Apply set to these arguments.
59 seed_->bind("summaries", summaries_) // Connect this shader port to its application resource.
60 .bind("seeds", seeds_) // Connect this shader port to its application resource.
61 .bind("sizes", sizes_) // Connect this shader port to its application resource.
62 .bind("stream_state", state); // Connect this shader port to its application resource.
63 prefix_->bind("sizes", sizes_).bind("offsets", offsets); // Connect this shader port to its application resource.
64 emit_->bind("packed_words", packed_) // Connect this shader port to its application resource.
65 .bind("seeds", seeds_) // Connect this shader port to its application resource.
66 .bind("offsets", offsets) // Connect this shader port to its application resource.
67 .bind("events", events) // Connect this shader port to its application resource.
68 .set("block_size", block_size_); // Apply set to these arguments.
69 reset_->bind("stream_state", state); // Connect this shader port to its application resource.
70 load(std::vector<std::uint16_t>()); // Apply load to these arguments.
71 } // End this block.
72 /** @brief Copy words into packed storage and adjust dispatches while preserving decoder state. */
73 void load(const std::vector<std::uint16_t>& words) { // Implement load for the operations below.
74 if (words.size() > capacity_) // Check this condition before entering the following branch.
75 throw shdr::error("EVT3 batch exceeds allocated capacity"); // Report EVT3 batch exceeds allocated capacity.
76 count_ = static_cast<unsigned>(words.size()); // Set count from this expression.
77 blocks_ = (count_ + block_size_ - 1u) / block_size_; // Set blocks from this expression.
78 unsigned* data = packed_.data(); // Set data from this expression.
79 for (unsigned i = 0; i < (count_ + 1u) / 2u; ++i) { // Iterate over i for this calculation.
80 data[i] = words[2u * i]; // Set data[i] from this expression.
81 if (2u * i + 1u < count_) // Check this condition before entering the following branch.
82 data[i] |= unsigned(words[2u * i + 1u]) << 16u; // Update data[i] with this contribution.
83 } // End this block.
84 summary_->set("word_count", count_); // Apply set to these arguments.
85 emit_->set("word_count", count_); // Apply set to these arguments.
86 seed_->set("blocks", blocks_); // Apply set to these arguments.
87 prefix_->set("blocks", blocks_); // Apply set to these arguments.
88 const shdr::extent groups(std::max(1u, (blocks_ + 63u) / 64u)); // Construct groups with these initial values.
89 stream_ = shdr::dispatch(*summary_, groups) >> shdr::dispatch(*seed_, shdr::extent(1)) >> // Add a shader dispatch with the required workgroup counts.
90 shdr::dispatch(*prefix_, shdr::extent(1)) >> shdr::dispatch(*emit_, groups); // Add a shader dispatch with the required workgroup counts.
91 independent_ = shdr::dispatch(*reset_, shdr::extent(1)) >> // Add a shader dispatch with the required workgroup counts.
92 shdr::dispatch(*summary_, groups) >> // Add a shader dispatch with the required workgroup counts.
93 shdr::dispatch(*seed_, shdr::extent(1)) >> // Add a shader dispatch with the required workgroup counts.
94 shdr::dispatch(*prefix_, shdr::extent(1)) >> shdr::dispatch(*emit_, groups); // Add a shader dispatch with the required workgroup counts.
95 } // End this block.
96 /** @brief Execute this for consecutive batches from the same stream. */
97 const shdr::pipeline& stream_pipeline() const { // Implement stream pipeline for the operations below.
98 return stream_; // Return stream.
99 } // End this block.
100 /** @brief Execute this for independent batches, with deterministic initial state. */
101 const shdr::pipeline& reset_pipeline() const { // Implement reset pipeline for the operations below.
102 return independent_; // Return independent.
103 } // End this block.
104 /** @brief Return the encoded word count in the current batch. */
105 unsigned word_count() const { // Implement word count for the operations below.
106 return count_; // Return count.
107 } // End this block.
108 /** @brief Return the number of active block summaries and output intervals. */
109 unsigned blocks() const { // Implement blocks for the operations below.
110 return blocks_; // Return blocks.
111 } // End this block.
112 /** @brief Read compact output length, synchronizing this buffer after GPU work. */
113 unsigned event_count() const { // Implement event count for the operations below.
114 return offsets.data()[blocks_]; // Return offsets.data()[blocks ].
115 } // End this block.
116}; // Finish this declaration.
117
118/** @brief Pack decoded CD events into X11/Y10/polarity1/time42 uint64 records.
119 * This CPU consumer downloads completed GPU results and packs CD pixel events.
120 * The lossless layout accepts X11, Y10 and time42 values, with range errors
121 * reported as exceptions. The original uvec4 records support larger geometry.
122 */
123inline std::vector<std::uint64_t> // Declare std for the following calculation.
124evt3_compact_cd_to64(const shdr::buffer<shdr::glsl::uvec4>& decoded, unsigned count) { // Apply evt3 compact cd to64 to these arguments.
125 if (count > decoded.size()) // Check this condition before entering the following branch.
126 throw shdr::error("EVT3 compact count exceeds decoded storage"); // Report EVT3 compact count exceeds decoded storage.
127 const shdr::glsl::uvec4* events = decoded.data(); // Set events from this expression.
128 std::vector<std::uint64_t> packed; // Declare packed for the following calculation.
129 packed.reserve(count); // Apply reserve to these arguments.
130 for (unsigned i = 0; i < count; ++i) { // Iterate over i for this calculation.
131 const shdr::glsl::uvec4& event = events[i]; // Set event from this expression.
132 if (event.y & 0x80000000u) // Check this condition before entering the following branch.
133 continue; // Skip the remaining work for this loop iteration.
134 const unsigned y = event.y & 2047u; // Set y from this expression.
135 if (event.x >= 2048u || y >= 1024u) // Check this condition before entering the following branch.
136 throw shdr::error("64-bit EVT3 CD packing requires X<2048 and Y<1024"); // Report 64-bit EVT3 CD packing requires X<2048 and Y<1024.
137 if (event.w >= 1024u) // Check this condition before entering the following branch.
138 throw shdr::error("64-bit EVT3 CD packing requires timestamps below 2^42 microseconds"); // Report 64-bit EVT3 CD packing requires timestamps below 2^42 microseconds.
139 const std::uint64_t timestamp = (std::uint64_t(event.w) << 32u) | event.z; // Set timestamp from this expression.
140 const unsigned polarity = (event.y >> 11u) & 1u; // Set polarity from this expression.
141 packed.push_back(std::uint64_t(event.x) | (std::uint64_t(y) << 11u) | // Apply push back to these arguments.
142 (std::uint64_t(polarity) << 21u) | (timestamp << 22u)); // Apply uint64 t to these arguments.
143 } // End this block.
144 return packed; // Return packed.
145} // End this block.
146
147/** @brief Generate reproducible vector-heavy input, crossing blocks and timestamp wraps. */
148inline std::vector<std::uint16_t> evt3_random_words(unsigned count, unsigned seed = 12345) { // Set seed from this expression.
149 std::mt19937 random(seed); // Construct random with these initial values.
150 std::vector<std::uint16_t> words; // Declare words for the following calculation.
151 words.reserve(count); // Apply reserve to these arguments.
152 unsigned high = 4093u; // Set high from this expression.
153 for (unsigned row = 0; words.size() < count; ++row) { // Iterate over row for this calculation.
154 const unsigned header[] = {0x8000u | (high & 4095u), // Declare header for the following calculation.
155 0x6000u | (unsigned(random()) & 4095u), // Apply unsigned to these arguments.
156 unsigned(random()) & 4095u, // Apply unsigned to these arguments.
157 0x3000u | (unsigned(random()) % 1000u) | // Apply unsigned to these arguments.
158 ((unsigned(random()) & 1u) << 11u)}; // Apply unsigned to these arguments.
159 for (unsigned value : header) // Visit each value required by this loop.
160 if (words.size() < count) // Check this condition before entering the following branch.
161 words.push_back(static_cast<std::uint16_t>(value)); // Apply push back to these arguments.
162 for (unsigned j = 0; j < 13 && words.size() < count; ++j) { // Iterate over j for this calculation.
163 unsigned value; // Declare value for the following calculation.
164 if (j == 4) // Check this condition before entering the following branch.
165 value = 0xa000u | ((random() & 15u) << 8u) | (random() & 1u); // Set value from this expression.
166 else if (j == 9) // Insert a scalar CD event between vector masks.
167 value = 0x2000u | (random() & 4095u); // Set value from this expression.
168 else // Alternate twelve-bit and eight-bit vector-mask words.
169 value = (j & 1u ? 0x5000u : 0x4000u) | (random() & (j & 1u ? 255u : 4095u)); // Set value from this expression.
170 words.push_back(static_cast<std::uint16_t>(value)); // Apply push back to these arguments.
171 } // End this block.
172 high = (high + 1u) & 4095u; // Set high from this expression.
173 } // End this block.
174 return words; // Return words.
175} // End this block.
176} // namespace shdr_examples
177#endif // Finish this conditional compilation branch.