Source browser
examples/evt3_flow_checks.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_flow_checks.hpp
2 * @brief Synthetic event-plane fixtures and an independent optical-flow oracle.
3 * A plane t=100*x+50*y microseconds has normal velocity (8000,4000) pixels/second.
4 * Chain decoding and flow estimation through the same event buffers.
5 */
6#ifndef SHDR_EXAMPLES_EVT3_FLOW_CHECKS_HPP // Open this include guard or optional feature branch.
7#define SHDR_EXAMPLES_EVT3_FLOW_CHECKS_HPP // Define SHDR_EXAMPLES_EVT3_FLOW_CHECKS_HPP for the declarations that follow.
8#include "runner.hpp" // Include runner.hpp declarations.
9#include "evt3_support.hpp" // Include evt3_support.hpp declarations.
10#include <algorithm> // Include algorithm declarations.
11#include <cmath> // Include cmath declarations.
12#include <cstdint> // Include cstdint declarations.
13#include <vector> // Include vector declarations.
14
15namespace shdr_examples { // Group these helpers within their namespace.
16
17/** @brief Build time-ordered direct EVT3 events for a translating temporal plane.
18 * crossing_32 selects a time origin just before the low timestamp word wraps.
19 * Synchronization-only words establish the preceding 24-bit wraps, so the same
20 * fixture exercises the decoder and exact timestamp subtraction in the flow stage.
21 */
22inline std::vector<std::uint16_t> // Declare std for the following calculation.
23evt3_planar_words(unsigned width = 32, unsigned height = 24, bool crossing_32 = false) { // Set width from this expression.
24 if (!width || !height || width > 2048u || height > 2048u) // Check this condition before entering the following branch.
25 throw shdr::error("event-plane dimensions must be between 1 and 2048"); // Report event-plane dimensions must be between 1 and 2048.
26 struct pixel { // Declare pixel.
27 unsigned x, y, time; // Declare x for the following calculation.
28 }; // Finish this declaration.
29 std::vector<pixel> pixels; // Declare pixels for the following calculation.
30 for (unsigned y = 0; y < height; ++y) // Iterate over y for this calculation.
31 for (unsigned x = 0; x < width; ++x) // Iterate over x for this calculation.
32 pixels.push_back(pixel{x, y, 100u * x + 50u * y}); // Apply push back to these arguments.
33 std::stable_sort(pixels.begin(), pixels.end(), [](const pixel& a, const pixel& b) { // Apply stable sort to these arguments.
34 return a.time < b.time; // Return a.time < b.time.
35 }); // Finish this declaration.
36 std::vector<std::uint16_t> words; // Declare words for the following calculation.
37 if (crossing_32) // Check this condition before entering the following branch.
38 for (unsigned wrap = 0; wrap < 255u; ++wrap) { // Iterate over wrap for this calculation.
39 words.push_back(0x8fffu); // Apply push back to these arguments.
40 words.push_back(0x8000u); // Apply push back to these arguments.
41 } // End this block.
42 const std::uint64_t origin = crossing_32 ? (std::uint64_t(1) << 32) - 2000u : 0u; // Set origin from this expression.
43 for (const pixel& p : pixels) { // Visit each p required by this loop.
44 const std::uint64_t timestamp = origin + p.time; // Set timestamp from this expression.
45 words.push_back(static_cast<std::uint16_t>(0x8000u | ((timestamp >> 12u) & 4095u))); // Apply push back to these arguments.
46 words.push_back(static_cast<std::uint16_t>(0x6000u | (timestamp & 4095u))); // Apply push back to these arguments.
47 words.push_back(static_cast<std::uint16_t>(p.y)); // Apply push back to these arguments.
48 words.push_back(static_cast<std::uint16_t>(0x2000u | p.x)); // Apply push back to these arguments.
49 } // End this block.
50 return words; // Return words.
51} // End this block.
52
53/** @brief Attach a bounded local-plane flow stage to decoded event storage.
54 * The decoder offsets provide the compact event count on the GPU. A dispatch
55 * covering allocated capacity uses that device-resident count to bound its work.
56 */
57inline std::unique_ptr<shdr::kernel> evt3_flow_kernel(evt3_decoder& decoder, // Declare evt3 flow kernel with the parameters continued below.
58 shdr::buffer<shdr::glsl::vec4>& output, // Declare output for the following calculation.
59 unsigned history = 128u) { // Set history from this expression.
60 auto shader = shdr::make_kernel("evt3_flow_kernel"); // Create the linked evt3 flow kernel instance.
61 shader->bind("events", decoder.events) // Connect this shader port to its application resource.
62 .bind("offsets", decoder.offsets) // Connect this shader port to its application resource.
63 .bind("flow", output) // Connect this shader port to its application resource.
64 .set<unsigned>("blocks", decoder.blocks()) // Supply this shader uniform with its typed application value.
65 .set<float>("radius", 3.0f) // Supply this shader uniform with its typed application value.
66 .set<unsigned>("history", history) // Supply this shader uniform with its typed application value.
67 .set<unsigned>("time_window", 10000u); // Supply this shader uniform with its typed application value.
68 return shader; // Return shader.
69} // End this block.
70
71namespace detail { // Group these helpers within their namespace.
72
73// Solve the full three-parameter normal equations in double precision as an
74// independent reference for the timestamp-plane slopes and intercept.
75inline shdr::glsl::vec4 evt3_reference_flow(const std::vector<shdr::glsl::uvec4>& events, // Declare evt3 reference flow with the parameters continued below.
76 unsigned index, // Declare index for the following calculation.
77 float radius, // Declare radius for the following calculation.
78 unsigned history, // Declare history for the following calculation.
79 unsigned time_window) { // Declare time window for the following calculation.
80 const shdr::glsl::uvec4 center = events[index]; // Set center from this expression.
81 if (center.y & 0x80000000u) // Check this condition before entering the following branch.
82 return shdr::glsl::vec4(0.0f); // Return shdr::glsl::vec4(0.0f).
83 double normal[3][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 1, 0}}; // Use this floating-point value or resource in the following calculation.
84 const std::uint64_t current = (std::uint64_t(center.w) << 32) | center.z; // Set current from this expression.
85 unsigned neighbors = 0; // Set neighbors from this expression.
86 for (unsigned distance = 1; distance <= std::min(128u, history) && distance <= index; // Iterate over distance for this calculation.
87 ++distance) { // Continue the expression using distance.
88 const shdr::glsl::uvec4 previous = events[index - distance]; // Set previous from this expression.
89 if ((previous.y & 0x80000000u) || (previous.y & 0x1800u) != (center.y & 0x1800u)) // Check this condition before entering the following branch.
90 continue; // Skip the remaining work for this loop iteration.
91 const std::uint64_t timestamp = (std::uint64_t(previous.w) << 32) | previous.z; // Set timestamp from this expression.
92 if (timestamp > current || current - timestamp > time_window) // Check this condition before entering the following branch.
93 continue; // Skip the remaining work for this loop iteration.
94 const double dx = double(previous.x) - center.x, // Set dx from this expression.
95 dy = double(previous.y & 2047u) - double(center.y & 2047u); // Set dy from this expression.
96 if (dx * dx + dy * dy > double(radius) * radius) // Check this condition before entering the following branch.
97 continue; // Skip the remaining work for this loop iteration.
98 const double row[3] = {dx, dy, 1.0}, dt = -double(current - timestamp); // Set row[3] from this expression.
99 for (unsigned r = 0; r < 3; ++r) { // Iterate over r for this calculation.
100 for (unsigned c = 0; c < 3; ++c) // Iterate over c for this calculation.
101 normal[r][c] += row[r] * row[c]; // Update normal[r][c] with this contribution.
102 normal[r][3] += row[r] * dt; // Update normal[r][3] with this contribution.
103 } // End this block.
104 ++neighbors; // Continue the expression using neighbors.
105 } // End this block.
106 if (neighbors < 6u) // Check this condition before entering the following branch.
107 return shdr::glsl::vec4(0.0f); // Return shdr::glsl::vec4(0.0f).
108 for (unsigned c = 0; c < 3; ++c) { // Iterate over c for this calculation.
109 unsigned pivot = c; // Set pivot from this expression.
110 for (unsigned r = c + 1; r < 3; ++r) // Iterate over r for this calculation.
111 if (std::fabs(normal[r][c]) > std::fabs(normal[pivot][c])) // Check this condition before entering the following branch.
112 pivot = r; // Set pivot from this expression.
113 if (std::fabs(normal[pivot][c]) < 1e-9) // Check this condition before entering the following branch.
114 return shdr::glsl::vec4(0.0f); // Return shdr::glsl::vec4(0.0f).
115 for (unsigned j = c; j < 4; ++j) // Iterate over j for this calculation.
116 std::swap(normal[pivot][j], normal[c][j]); // Apply swap to these arguments.
117 const double divisor = normal[c][c]; // Set divisor from this expression.
118 for (unsigned j = c; j < 4; ++j) // Iterate over j for this calculation.
119 normal[c][j] /= divisor; // Update normal[c][j] with this contribution.
120 for (unsigned r = 0; r < 3; ++r) // Iterate over r for this calculation.
121 if (r != c) { // Check this condition before entering the following branch.
122 const double multiplier = normal[r][c]; // Set multiplier from this expression.
123 for (unsigned j = c; j < 4; ++j) // Iterate over j for this calculation.
124 normal[r][j] -= multiplier * normal[c][j]; // Update normal[r][j] with this contribution.
125 } // End this block.
126 } // End this block.
127 const double a = normal[0][3], b = normal[1][3], gradient = a * a + b * b; // Set a from this expression.
128 if (gradient <= 0.000001) // Check this condition before entering the following branch.
129 return shdr::glsl::vec4(0.0f); // Return shdr::glsl::vec4(0.0f).
130 return shdr::glsl::vec4( // Return shdr::glsl::vec4(.
131 float(a * 1000000.0 / gradient), float(b * 1000000.0 / gradient), float(neighbors), 1.0f); // Apply float to these arguments.
132} // End this block.
133
134inline shdr::glsl::uvec4 evt3_flow_record(unsigned x, unsigned packed_y, std::uint64_t time) { // Implement evt3 flow record for the operations below.
135 return shdr::glsl::uvec4( // Return shdr::glsl::uvec4(.
136 x, packed_y, static_cast<unsigned>(time), static_cast<unsigned>(time >> 32)); // Continue the expression using x, packed y, static cast.
137} // End this block.
138
139// Interleaved camera/polarity records, triggers, a stale high timestamp word and
140// an out-of-order timestamp make every neighborhood rejection observable.
141inline void evt3_mixed_flow_check(runner& run) { // Implement evt3 mixed flow check for the operations below.
142 const std::uint64_t origin = (std::uint64_t(1) << 32) - 200u; // Set origin from this expression.
143 std::vector<shdr::glsl::uvec4> records; // Declare records for the following calculation.
144 records.push_back(evt3_flow_record(2u, 2u, 0u)); // Apply push back to these arguments.
145 for (unsigned y = 0; y < 5; ++y) // Iterate over y for this calculation.
146 for (unsigned x = 0; x < 5; ++x) { // Iterate over x for this calculation.
147 const unsigned relative = 100u * x + 50u * y; // Set relative from this expression.
148 if (relative > 300u || (x == 2u && y == 2u)) // Check this condition before entering the following branch.
149 continue; // Skip the remaining work for this loop iteration.
150 const std::uint64_t time = origin + relative; // Set time from this expression.
151 records.push_back(evt3_flow_record(x, y, time)); // Apply push back to these arguments.
152 records.push_back(evt3_flow_record(x, y | 2048u, time - 17u)); // Apply push back to these arguments.
153 records.push_back(evt3_flow_record(x, y | 4096u, time - 31u)); // Apply push back to these arguments.
154 records.push_back(evt3_flow_record(1u, 0x80000001u, time)); // Apply push back to these arguments.
155 } // End this block.
156 std::stable_sort( // Apply stable sort to these arguments.
157 records.begin(), records.end(), [](const shdr::glsl::uvec4& a, const shdr::glsl::uvec4& b) { // Apply begin to these arguments.
158 return a.w < b.w || (a.w == b.w && a.z < b.z); // Return a.w < b.w || (a.w == b.w && a.z < b.z).
159 }); // Finish this declaration.
160 records.push_back( // Apply push back to these arguments.
161 evt3_flow_record(2u, 1u, origin + 400u)); // Future data must be ignored by the final fit.
162 records.push_back(evt3_flow_record(2u, 2u, origin + 300u)); // Apply push back to these arguments.
163 shdr::buffer<shdr::glsl::uvec4> events(records.size()); // Construct events with these initial values.
164 std::copy(records.begin(), records.end(), events.data()); // Apply copy to these arguments.
165 shdr::buffer<unsigned> offsets{static_cast<unsigned>(records.size())}; // Declare offsets for the following calculation.
166 shdr::buffer<shdr::glsl::vec4> output(records.size()); // Construct output with these initial values.
167 auto shader = shdr::make_kernel("evt3_flow_kernel"); // Create the linked evt3 flow kernel instance.
168 shader->bind("events", events) // Connect this shader port to its application resource.
169 .bind("offsets", offsets) // Connect this shader port to its application resource.
170 .bind("flow", output) // Connect this shader port to its application resource.
171 .set<unsigned>("blocks", 0u) // Supply this shader uniform with its typed application value.
172 .set<float>("radius", 3.0f) // Supply this shader uniform with its typed application value.
173 .set<unsigned>("history", 128u) // Supply this shader uniform with its typed application value.
174 .set<unsigned>("time_window", 250u); // Supply this shader uniform with its typed application value.
175 run.run(shdr::pipeline(shdr::dispatch( // Execute the configured pipeline on the requested backend.
176 *shader, shdr::extent((static_cast<unsigned>(records.size()) + 63u) / 64u)))); // Apply extent to these arguments.
177 const shdr::glsl::vec4* actual = // Set actual from this expression.
178 static_cast<const shdr::buffer<shdr::glsl::vec4>&>(output).data(); // Apply data to these arguments.
179 for (unsigned index = 0; index < records.size(); ++index) { // Iterate over index for this calculation.
180 const shdr::glsl::vec4 expected = evt3_reference_flow(records, index, 3.0f, 128u, 250u); // Set expected from this expression.
181 require_close(actual[index].x, expected.x, "mixed-event flow X", 1.5f); // Check the computed value against the independent reference.
182 require_close(actual[index].y, expected.y, "mixed-event flow Y", 1.5f); // Check the computed value against the independent reference.
183 require_close(actual[index].z, expected.z, "mixed-event neighbor count", 0.0f); // Check the computed value against the independent reference.
184 require_close(actual[index].w, expected.w, "mixed-event fit validity", 0.0f); // Check the computed value against the independent reference.
185 } // End this block.
186 require_close(actual[records.size() - 1u].x, 8000.0f, "filtered temporal-plane X", 1.5f); // Check the computed value against the independent reference.
187 require_close(actual[records.size() - 1u].y, 4000.0f, "filtered temporal-plane Y", 1.5f); // Check the computed value against the independent reference.
188 // Require two independent spatial directions for a two-dimensional plane fit.
189 for (unsigned index = 0; index < records.size(); ++index) // Iterate over index for this calculation.
190 records[index] = evt3_flow_record(index % 3u, 2u, origin + 50u * index); // Set records[index] from this expression.
191 std::copy(records.begin(), records.end(), events.data()); // Apply copy to these arguments.
192 shader->set<unsigned>("time_window", 10000u); // Supply this shader uniform with its typed application value.
193 run.run(shdr::pipeline(shdr::dispatch( // Execute the configured pipeline on the requested backend.
194 *shader, shdr::extent((static_cast<unsigned>(records.size()) + 63u) / 64u)))); // Apply extent to these arguments.
195 actual = static_cast<const shdr::buffer<shdr::glsl::vec4>&>(output).data(); // Use a constant buffer view so GPU writes synchronize before host reads.
196 for (unsigned index = 0; index < records.size(); ++index) // Iterate over index for this calculation.
197 if (actual[index] != shdr::glsl::vec4(0.0f)) // Check this condition before entering the following branch.
198 throw shdr::error("collinear events produced a valid plane fit"); // Report collinear events produced a valid plane fit.
199 // This six-neighbor geometry has an exactly zero horizontal timestamp slope.
200 // Early covariance division can invent a tiny slope and amplify it into false velocity.
201 // The fitted vertical slope is one fifth of a microsecond per pixel.
202 const std::uint64_t axis_time = (std::uint64_t(1) << 32) + 100u; // Keep exact timestamp subtraction near a low-word boundary.
203 records = { // Reproduce the integer geometry of a difficult recorded-event neighborhood.
204 evt3_flow_record(394u, 573u, axis_time - 1u), // Include the first event one microsecond before the center.
205 evt3_flow_record(393u, 573u, axis_time - 1u), // Include the second older event on the same pixel row.
206 evt3_flow_record(394u, 574u, axis_time), // Include a same-time neighbor four pixels to the right.
207 evt3_flow_record(393u, 574u, axis_time), // Include a same-time neighbor three pixels to the right.
208 evt3_flow_record(392u, 574u, axis_time), // Include a same-time neighbor two pixels to the right.
209 evt3_flow_record(394u, 572u, axis_time), // Supply spatial variation that makes the plane fit nondegenerate.
210 evt3_flow_record(390u, 575u, axis_time)}; // Place the evaluated center after all six preceding neighbors.
211 std::copy(records.begin(), records.end(), events.data()); // Replace the input prefix with the zero-axis regression fixture.
212 offsets.data()[0] = static_cast<unsigned>(records.size()); // Restrict shader output to the seven supplied records.
213 shader->set<float>("radius", 5.0f); // Include the diagonal neighbor exactly five pixels from the center.
214 run.run(shdr::pipeline(shdr::dispatch(*shader, shdr::extent(1u)))); // Fit the same regression neighborhood on the selected backend.
215 actual = static_cast<const shdr::buffer<shdr::glsl::vec4>&>(output).data(); // Read completed flow through a constant buffer view.
216 const unsigned center = static_cast<unsigned>(records.size() - 1u); // Select the event with all six regression neighbors.
217 const shdr::glsl::vec4 expected = evt3_reference_flow(records, center, 5.0f, 128u, 10000u); // Solve the independent double-precision normal equations.
218 require_close(expected.x, 0.0f, "zero-axis oracle horizontal velocity", 0.00001f); // Verify zero horizontal velocity in the independent fit.
219 require_close(expected.y, 5000000.0f, "zero-axis oracle vertical velocity", 1.0f); // Verify the fixture's known normal velocity in pixels per second.
220 require_close(actual[center].x, expected.x, "zero-axis flow X", 0.00001f); // Detect any false velocity caused by rounding a mathematically zero slope.
221 require_close(actual[center].y, expected.y, "zero-axis flow Y", 1.0f); // Bound the vertical error relative to the large known velocity.
222 require_close(actual[center].z, 6.0f, "zero-axis neighbor count", 0.0f); // Require all six intended neighbors to participate.
223 require_close(actual[center].w, 1.0f, "zero-axis fit validity", 0.0f); // Require the noncollinear regression geometry to produce a valid fit.
224} // End this block.
225
226// Fused arithmetic can produce a positive rounded determinant for large collinear integer covariances.
227// Exact pixel-direction tests must reject these neighborhoods before solving any timestamp slope.
228inline void evt3_collinear_history_check(runner& run) { // Check long singular neighborhoods on the selected CPU or GPU backend.
229 for (unsigned count : {64u, 65u, 128u, 129u}) { // Exercise both workgroup boundaries and the maximum neighbor history.
230 const std::uint64_t origin = (std::uint64_t(1) << 32) + 1000u; // Keep all preceding timestamps within a short exact window.
231 std::vector<shdr::glsl::uvec4> records; // Build a timestamp-ordered line of repeated pixel locations.
232 for (int age = int(count) - 1; age > 0; --age) { // Emit the oldest event first and approach the evaluated center.
233 const int position = age == 1 ? 1 : (age % 2 ? -2 : 2); // Break covariance power-of-two factors while staying on one line.
234 const unsigned x = unsigned(100 + 2 * position), y = unsigned(100 + position); // Keep all pixels on the exact integer line X minus 100 equals twice Y minus 100.
235 records.push_back(evt3_flow_record(x, y, origin - unsigned(age))); // Give every candidate a valid earlier timestamp.
236 } // Finish the long collinear neighbor sequence.
237 records.push_back(evt3_flow_record(100u, 100u, origin)); // Include the evaluated center on the same spatial line.
238 shdr::buffer<shdr::glsl::uvec4> input(records.size()); // Allocate the complete singular neighborhood.
239 std::copy(records.begin(), records.end(), input.data()); // Load exactly the generated pixel and timestamp records.
240 shdr::buffer<unsigned> offsets{count}; // Provide the event count directly for this isolated flow-kernel fixture.
241 shdr::buffer<shdr::glsl::vec4> output(count); // Receive one invalid zero flow record for every input event.
242 auto shader = shdr::make_kernel("evt3_flow_kernel"); // Create the same native flow module used by decoded-event pipelines.
243 shader->bind("events", input).bind("offsets", offsets).bind("flow", output); // Connect the direct regression input and its result resource.
244 shader->set<unsigned>("blocks", 0u).set<unsigned>("history", 128u); // Read the single total offset and allow the maximum supported history.
245 shader->set<float>("radius", 5.0f).set<unsigned>("time_window", 10000u); // Set a radius that includes every candidate while retaining the standard fit thresholds.
246 const shdr::pipeline pipeline(shdr::dispatch(*shader, shdr::extent((count + 63u) / 64u))); // Cover all records and ignore padded invocations normally.
247 for (unsigned duplicates = 0u; duplicates < 2u; ++duplicates) { // Check both a true spatial line and repeated center positions.
248 if (duplicates != 0u) { // Replace the line with a neighborhood of identical pixel coordinates.
249 for (unsigned index = 0u; index < count; ++index) { // Keep all timestamps ordered while removing spatial variation.
250 records[index] = evt3_flow_record(100u, 100u, origin - (count - 1u - index)); // Make every record a duplicate of the center's pixel.
251 } // Finish the rank-zero neighborhood.
252 std::copy(records.begin(), records.end(), input.data()); // Upload the changed positions for the second regression run.
253 } // Retain the original line geometry during the first run.
254 run.run(pipeline); // Execute the complete singular neighborhood on the selected backend.
255 const shdr::glsl::vec4* actual = static_cast<const shdr::buffer<shdr::glsl::vec4>&>(output).data(); // Read synchronized results through the constant buffer interface.
256 for (unsigned index = 0u; index < count; ++index) { // Check every prefix and the longest available neighborhood.
257 const shdr::glsl::vec4 expected = evt3_reference_flow(records, index, 5.0f, 128u, 10000u); // Confirm singularity with the independent double-precision solver.
258 if (expected != shdr::glsl::vec4(0.0f)) { // Require the regression fixture to remain mathematically degenerate.
259 throw shdr::error("collinear-history oracle unexpectedly accepted a plane"); // Report an invalid fixture or independent solver regression.
260 } // The independent oracle rejects this spatial geometry.
261 if (actual[index] != expected) { // Reject a fabricated valid flow or any nonzero invalid output component.
262 throw shdr::error("long collinear history produced a valid plane fit"); // Catch determinant residues caused by fused floating-point products.
263 } // Both backends must publish the same exact invalid result.
264 } // Finish all prefix checks for this singular geometry.
265 } // Finish line and repeated-center regressions.
266 } // Finish every bounded history size.
267} // Finish exact spatial rank validation.
268} // namespace detail
269
270/** @brief Verify decoded planes and GPU/CPU flow against a scalar double oracle.
271 * Both a small timestamp origin and a uint32-boundary crossing use one linked
272 * decode-and-flow pipeline. Invalid fits publish zero and valid fits publish a
273 * count with normal velocity. The oracle checks every compact output event.
274 */
275inline void check_evt3_flow(runner& run) { // Implement check evt3 flow for the operations below.
276 for (unsigned crossing = 0; crossing < 2; ++crossing) { // Iterate over crossing for this calculation.
277 const std::vector<std::uint16_t> words = evt3_planar_words(32, 24, crossing != 0); // Set words from this expression.
278 evt3_decoder decoder(static_cast<unsigned>(words.size()), 127); // Construct decoder with these initial values.
279 decoder.load(words); // Apply load to these arguments.
280 shdr::buffer<shdr::glsl::vec4> output(decoder.events.size()); // Construct output with these initial values.
281 auto shader = evt3_flow_kernel(decoder, output); // Set shader from this expression.
282 shdr::pipeline pipeline = decoder.reset_pipeline(); // Set pipeline from this expression.
283 pipeline += shdr::dispatch( // Add a shader dispatch with the required workgroup counts.
284 *shader, shdr::extent((static_cast<unsigned>(output.size()) + 63u) / 64u)); // Apply extent to these arguments.
285 run.run(pipeline); // Execute the configured pipeline on the requested backend.
286 const unsigned count = decoder.event_count(); // Set count from this expression.
287 if (count != 32u * 24u) // Check this condition before entering the following branch.
288 throw shdr::error("temporal-plane event count mismatch"); // Report temporal-plane event count mismatch.
289 const shdr::glsl::uvec4* decoded = // Set decoded from this expression.
290 static_cast<const shdr::buffer<shdr::glsl::uvec4>&>(decoder.events).data(); // Apply data to these arguments.
291 const std::vector<shdr::glsl::uvec4> events(decoded, decoded + count); // Construct events with these initial values.
292 const shdr::glsl::vec4* actual = // Set actual from this expression.
293 static_cast<const shdr::buffer<shdr::glsl::vec4>&>(output).data(); // Apply data to these arguments.
294 unsigned valid = 0; // Set valid from this expression.
295 for (unsigned index = 0; index < count; ++index) { // Iterate over index for this calculation.
296 const shdr::glsl::vec4 expected = // Set expected from this expression.
297 detail::evt3_reference_flow(events, index, 3.0f, 128u, 10000u); // Apply evt3 reference flow to these arguments.
298 require_close(actual[index].x, expected.x, "event-plane flow X", 1.5f); // Check the computed value against the independent reference.
299 require_close(actual[index].y, expected.y, "event-plane flow Y", 1.5f); // Check the computed value against the independent reference.
300 require_close(actual[index].z, expected.z, "event-plane neighbor count", 0.0f); // Check the computed value against the independent reference.
301 require_close(actual[index].w, expected.w, "event-plane fit validity", 0.0f); // Check the computed value against the independent reference.
302 if (expected.w != 0.0f) { // Check this condition before entering the following branch.
303 ++valid; // Continue the expression using valid.
304 require_close( // Check the computed value against the independent reference.
305 actual[index].x, 8000.0f, "translating-plane normal velocity X", 1.5f); // Continue the expression using actual, index, x.
306 require_close( // Check the computed value against the independent reference.
307 actual[index].y, 4000.0f, "translating-plane normal velocity Y", 1.5f); // Continue the expression using actual, index, y.
308 } // End this block.
309 } // End this block.
310 if (valid < count / 2u) // Check this condition before entering the following branch.
311 throw shdr::error("temporal plane produced too few valid flow fits"); // Report temporal plane produced too few valid flow fits.
312 std::cout << "EVT3 normal flow: " << valid << '/' << count // Write this part of the example result or diagnostic.
313 << " valid events, velocity (8000,4000) pixels/s" // Write this part of the example result or diagnostic.
314 << (crossing ? " across a 32-bit timestamp boundary" : "") << '\n'; // Write this part of the example result or diagnostic.
315 } // End this block.
316 detail::evt3_mixed_flow_check(run); // Apply evt3 mixed flow check to these arguments.
317 detail::evt3_collinear_history_check(run); // Reject long collinear and repeated-pixel neighborhoods independently of floating-point contraction.
318} // End this block.
319} // namespace shdr_examples
320#endif // Finish this conditional compilation branch.