MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VisionGpuDispatch.hpp
Go to the documentation of this file.
1#pragma once
2
4
7
8namespace MayaFlux::Yantra {
9
10/**
11 * @file VisionGpuDispatch.hpp
12 * @brief GPU execution layer for Kinesis::Vision::VisionSequence.
13 *
14 * VisionGpuExecutor::run() mirrors VisionExecutor::run() in contract: same
15 * input types, same VisionResult output. Internally it drives a
16 * VisionGpuContexts through the sequence via swap_shader() + stage_image()
17 * + dispatch_core() per step, keeping the working image GPU-resident
18 * between steps via OutputMode::IMAGE.
19 *
20 * VisionGpuExecutor::config() is the inspectable shader config table. It
21 * returns the GpuComputeConfig for any given VisionOp. Ops that are
22 * expressible via ShaderSpec are assembled at call time (no .comp file);
23 * ops requiring neighbourhood access or structured output name a .comp
24 * file. Ops with no GPU implementation return a config with INVALID_SHADER.
25 *
26 * The caller is responsible for only passing sequences composed of ops
27 * whose config is valid. run() logs an error and returns a default
28 * VisionResult on encountering INVALID_SHADER mid-sequence.
29 */
30
31/**
32 * @brief Cross-run state of the flow context.
33 *
34 * Two atlases are bound for their whole life. Which one holds the current
35 * frame is the curr parity, passed to shaders as a push constant, so ping-pong
36 * is a bit flip and never rewrites a descriptor. Detections, retained previous
37 * points and tracks live in the flow context's shared buffers and never leave
38 * the GPU except for the final tracks readback.
39 */
40struct FlowState {
41 std::shared_ptr<Core::VKImage> atlas[2];
43
44 /**
45 * @brief Dense flow images, allocated on first use of OpticalFlowDense.
46 *
47 * flow_out holds the finest-level result at frame resolution, alternated
48 * by the same parity as the atlases so a result stays valid for one more
49 * run. The rest share the atlas layout: flow_lvl holds the coarser levels,
50 * dense_a and dense_b are the box filter scratch, and dense_tensor holds
51 * the previous frame's summed structure tensor and confidence.
52 */
53 std::shared_ptr<Core::VKImage> flow_out[2];
54 std::shared_ptr<Core::VKImage> flow_lvl;
55 std::shared_ptr<Core::VKImage> dense_a;
56 std::shared_ptr<Core::VKImage> dense_b;
57 std::shared_ptr<Core::VKImage> dense_tensor;
58 std::shared_ptr<Core::VKImage> flow_vis;
60
61 /**
62 * @brief Most recent flow image and track list produced from a frame that
63 * differed from the one before it.
64 *
65 * A repeated camera frame carries no motion, so a run on one republishes
66 * these instead of a field of zeros. Before any result exists, the fresh
67 * result is published as is.
68 */
69 std::shared_ptr<Core::VKImage> last_flow;
70 std::vector<Kinesis::Vision::TrackResult> last_tracks;
71
72 /**
73 * @brief Track count of the last distinct frame, independent of whether a
74 * host list was produced for it, and whether the submitted track
75 * sequence should read its tracks back to the host.
76 */
77 uint32_t last_track_count { 0 };
78 bool host_pending { true };
79
80 /**
81 * @brief Bookkeeping for the device resident track export.
82 *
83 * The two export buffers are shared buffers of the flow context and
84 * alternate per published frame, so a delivered buffer stays valid for one
85 * more publish. export_slot is the buffer the next publish writes,
86 * last_export the view of the most recent distinct frame, and
87 * export_pending marks a submitted track sequence whose export has not
88 * been delivered yet. export_view caches one handle per buffer, created on
89 * first delivery, so publishing allocates nothing per frame.
90 */
91 std::shared_ptr<Portal::Graphics::GpuBufferHandle> export_view[2];
92 std::shared_ptr<Portal::Graphics::GpuBufferHandle> last_export;
93 uint32_t export_slot { 0 };
94 bool export_pending { false };
95
96 uint32_t curr { 0 };
97 bool have_prev { false };
98 bool curr_ready { false };
99 bool buffers_ready { false };
101};
102
103/**
104 * @brief Fixed set of TextureExecutionContexts covering every GPU-implemented
105 * VisionOp shape.
106 *
107 * Owned exclusively by VisionGpuExecutor, which lazily constructs and holds
108 * one instance per executor via m_contexts. Never rebuilt inside run() or
109 * per-step; the bindings each member declares are fixed at construction and
110 * dictated entirely by the shaders they drive, not by caller preference.
111 *
112 * There is exactly one correct binding layout per member, so this struct
113 * carries no configuration surface.
114 */
115struct MAYAFLUX_API VisionGpuContexts {
116 TextureExecutionContext pixel; ///< Image pipeline. IMAGE mode. Drives
117 ///< every op that reads/writes the
118 ///< working image (Threshold, Sobel,
119 ///< HarrisResponse, Downsample2x, etc).
120 TextureExecutionContext structured; ///< Buffer-only readback. SCALAR mode.
121 ///< Drives ops with no image output
122 ///< of their own (ExtractPeaks).
123 TextureExecutionContext labels; ///< Image + aux SSBO. IMAGE mode.
124 ///< Drives ops needing both a resident
125 ///< image output and structured aux
126 ///< data (ConnectedComponents,
127 ///< FindContours).
128 TextureExecutionContext component_contours; ///< Shared image and buffer
129 ///< pipeline for
130 ///< ConnectedComponents and
131 ///< FindContours. Holds labels,
132 ///< component bounds, trace
133 ///< points, and contour
134 ///< metadata across the two
135 ///< steps.
136 TextureExecutionContext ingest; ///< Sampled-in, rgba32f-storage-out.
137 ///< IMAGE mode. Runs vision_ingest.comp
138 ///< at the top of a fresh run to convert
139 ///< a non-storage seed frame before any
140 ///< rgba32f op reads it.
141 TextureExecutionContext flow; ///< Pyramidal optical flow. Fixed layout:
142 ///< gray source image, two rgba16f pyramid
143 ///< atlases, the dense flow images, and
144 ///< shared buffers for detections, retained
145 ///< points, tracks, and selection state.
146 ///< Drives TrackKeypoints and
147 ///< OpticalFlowDense, and reuses the
148 ///< extract_peaks layout unchanged.
149
151
152 /**
153 * @brief Walk state for the current run: sequence position, geometry,
154 * working image, and the result under construction.
155 *
156 * Lives here rather than as a run local so a deferred step's yield
157 * preserves it without copying. Reset by begin() at the top of a fresh
158 * run; left intact across a suspension.
159 */
161
162 /**
163 * @brief Input image the current walk started from.
164 *
165 * Ops needing the original frame rather than the working image read this
166 * (contour_march stages it at binding 1). Set on a fresh run and untouched
167 * across suspensions, so a polling call uses the frame the sequence began
168 * on rather than whatever argument it was passed.
169 *
170 * GPU-only. The CPU pass has no equivalent: its handle is an index into a
171 * reused slot pool, so retaining the input handle would retain a slot whose
172 * contents the ping-pong overwrites.
173 */
174 std::shared_ptr<Core::VKImage> source;
175
176 /**
177 * @brief Shader currently bound on pixel, and the image staged into it.
178 *
179 * TextureExecutionContext does not report its own state, so run tracks
180 * it. Held here rather than as a run local: a swap_shader or stage_image
181 * elided on one call stays elided on the next. The allocated output
182 * dimensions live in pass.storage_w / pass.storage_h.
183 */
185 std::shared_ptr<Core::VKImage> bound_staged;
186
187 /**
188 * @brief One image cache per Snapshot step, indexed by the step's order
189 * among the snapshots of a run.
190 *
191 * Kept across runs so a sequence that snapshots every frame reuses its
192 * images instead of allocating new ones.
193 */
194 std::vector<Portal::Graphics::ImageCacheSet> snapshot_images;
195
196 /**
197 * @brief Outstanding work at a deferred step, and the point to resume.
198 *
199 * fence is INVALID_FENCE when nothing is outstanding. While live, run
200 * polls it and does nothing else. The working image, geometry, and
201 * partial result the resumed sequence needs are already in pass, which
202 * is not reset while a suspension is active.
203 */
204 struct Suspension {
205 Portal::Graphics::FenceID fence { Portal::Graphics::INVALID_FENCE };
206
207 /**
208 * @brief Work to run once the fence has signaled, before the walk
209 * resumes. Empty for steps that need none.
210 *
211 * Lets a deferred step read back or commit state on completion
212 * rather than on submission. Dropped without running by reset().
213 */
214 std::function<void(VisionGpuContexts&)> finalize;
215
216 [[nodiscard]] bool is_active() const
217 {
218 return fence != Portal::Graphics::INVALID_FENCE;
219 }
220 };
221
223
224 /// op_ingest's dispatch + trailing-barrier fences. Not awaited by run();
225 /// reaped by reap_ingest_fences on the next fresh run and in reset().
226 Portal::Graphics::FenceID ingest_fence { Portal::Graphics::INVALID_FENCE };
227 Portal::Graphics::FenceID ingest_barrier_fence { Portal::Graphics::INVALID_FENCE };
228
229 /**
230 * @brief Construct all three contexts in place with the one correct
231 * binding layout for every currently GPU-implemented VisionOp.
232 *
233 * TextureExecutionContext has no copy or move constructor (it owns GPU
234 * resource handles), so each member is built directly in this
235 * constructor's initializer list rather than assigned from a temporary.
236 * Constructed lazily by VisionGpuExecutor on first run(); never
237 * constructed directly by callers.
238 */
240};
241
242/**
243 * @class VisionGpuExecutor
244 * @brief Stateful GPU dispatch engine for VisionSequence execution.
245 *
246 * Owns a lazily-constructed VisionGpuContexts (m_contexts) plus any
247 * op-specific persistent GPU state that doesn't belong on a shared
248 * context (e.g. ConnectedComponents' ping-pong output image). Mirrors
249 * VisionExecutor's ownership model on the CPU side: construct one
250 * instance per independent pipeline, hold it, call run() every frame.
251 *
252 * Immovable: TextureExecutionContext owns GPU resource handles with no
253 * copy or move constructor, so VisionGpuContexts and therefore
254 * VisionGpuExecutor cannot be copied or moved either. Construct once,
255 * hold by reference, pointer, or shared_ptr, reuse indefinitely.
256 *
257 * Not safe to call run() concurrently from multiple threads on the same
258 * instance. Independent pipelines running concurrently should each own
259 * a separate VisionGpuExecutor instance.
260 */
261class MAYAFLUX_API VisionGpuExecutor {
262public:
263 /**
264 * @brief GpuComputeConfig for a given VisionOp and its parameters.
265 *
266 * Assembled ops (Threshold, NormalizeInplace, NormalizeRange, RgbaToGray,
267 * GrayToRgba) produce a config via ShaderSpec::Assemble + config_from_spec
268 * with no .comp file. All other implemented ops reference a .comp path
269 * under Portal/Shaders/Vision/. Unimplemented ops return a config with
270 * shader_id == INVALID_SHADER.
271 *
272 * Stateless; does not depend on or affect m_contexts.
273 *
274 * @param op VisionOp to look up.
275 * @param params Parameters for that op; used to derive push constant size
276 * for assembled ops.
277 */
278 [[nodiscard]] static GpuComputeConfig config(
280 const Kinesis::Vision::VisionParams& params);
281
282 /**
283 * @brief Host tracks decoded from result.buffers.tracks, or empty.
284 *
285 * For occasional host access, not per-frame use: reads a device-local
286 * buffer through its host mapping. Valid for one more run after the
287 * result was delivered.
288 */
289 [[nodiscard]] static std::vector<Kinesis::Vision::TrackResult> read_exported_tracks(
290 const Kinesis::Vision::VisionResult& result);
291
292 /**
293 * @brief Host keypoints decoded from result.buffers.keypoints, or empty.
294 *
295 * Independent of VisionResult::structured. For occasional host access,
296 * not per-frame use. Valid for one more run after the result was
297 * delivered.
298 */
299 [[nodiscard]] static std::vector<Kinesis::Vision::Keypoint> read_exported_keypoints(
300 const Kinesis::Vision::VisionResult& result);
301
302 /**
303 * @brief Host contours decoded from result.buffers.contours, or empty.
304 *
305 * Always in compacted (unsorted) order; sort the returned list yourself
306 * if you need top-K-by-area order. For occasional host access, not
307 * per-frame use. Valid for one more run after the result was delivered.
308 */
309 [[nodiscard]] static std::vector<Kinesis::Vision::Contour> read_exported_contours(
310 const Kinesis::Vision::VisionResult& result);
311
312 /**
313 * @brief Execute a VisionSequence on the GPU through an explicit context set.
314 *
315 * contexts is caller-supplied rather than the instance's own lazily-built
316 * m_contexts. Reused across calls with no reset needed; construction is
317 * the caller's responsibility and never happens inside this function.
318 *
319 * @param contexts Long-lived context set. Never constructed internally.
320 * @param sequence Ordered steps to execute.
321 * @param image Input frame in eShaderReadOnlyOptimal layout.
322 * @param w Frame width in pixels.
323 * @param h Frame height in pixels.
324 * @return VisionResult matching the VisionExecutor::run() contract.
325 */
327 VisionGpuContexts& contexts,
328 const Kinesis::Vision::VisionSequence& sequence,
329 const std::shared_ptr<Core::VKImage>& image,
330 uint32_t w, uint32_t h);
331
332 /**
333 * @brief Execute a VisionSequence on the GPU using this instance's own
334 * lazily-constructed context set.
335 *
336 * m_contexts is built on first call and reused for every subsequent
337 * call to this overload on the same VisionGpuExecutor instance. The
338 * primary entry point; prefer this over the explicit-contexts overload
339 * unless a caller specifically needs to inspect or share a
340 * VisionGpuContexts across multiple calls outside this class.
341 *
342 * @param sequence Ordered steps to execute.
343 * @param image Input frame in eShaderReadOnlyOptimal layout.
344 * @param w Frame width in pixels.
345 * @param h Frame height in pixels.
346 * @return VisionResult matching the VisionExecutor::run() contract.
347 */
349 const Kinesis::Vision::VisionSequence& sequence,
350 const std::shared_ptr<Core::VKImage>& image,
351 uint32_t w, uint32_t h);
352
353 /**
354 * @brief Isolate one ConnectedComponents label's silhouette on GPU,
355 * through the explicit context set that produced the label
356 * buffer.
357 *
358 * Dispatches vision_label_select.comp through contexts.component_contours,
359 * the same context ConnectedComponents/FindContours already own: reads
360 * dense_label in place at its existing binding, no cross-context buffer
361 * copy. Requires a ConnectedComponents step to have already run against
362 * these exact contexts (this run or an earlier one); dense_label holds
363 * whichever frame's labels were computed last.
364 *
365 * @param contexts The same context set a prior run() populated.
366 * @param source Frame to select pixels from, eShaderReadOnlyOptimal.
367 * @param target_label 1-based label id, matching BoundingBox::label_id /
368 * Contour::label_id from that same run.
369 * @param w Frame width in pixels.
370 * @param h Frame height in pixels.
371 * @return New image, transparent everywhere outside the
372 * selected label's silhouette.
373 */
374 [[nodiscard]] std::shared_ptr<Core::VKImage> select_label(
375 VisionGpuContexts& contexts,
376 const std::shared_ptr<Core::VKImage>& source,
377 uint32_t target_label,
378 uint32_t w, uint32_t h);
379
380 /**
381 * @brief select_label() using this instance's own lazily-constructed
382 * context set. See the explicit-contexts overload for the
383 * ConnectedComponents-must-have-already-run requirement.
384 */
385 [[nodiscard]] std::shared_ptr<Core::VKImage> select_label(
386 const std::shared_ptr<Core::VKImage>& source,
387 uint32_t target_label,
388 uint32_t w, uint32_t h);
389
390 /**
391 * @brief Abandon outstanding work and clear the resume point.
392 *
393 * Waits on the fence before releasing it, then discards the retained
394 * working image and partial result. Call when the pixel source changes
395 * so the next run starts a fresh sequence. Safe with nothing outstanding.
396 */
397 void reset();
398
399 /**
400 * @brief True when a deferred step has work outstanding and the next run
401 * will poll rather than start a fresh sequence.
402 */
403 [[nodiscard]] bool is_suspended() const
404 {
405 return m_contexts && m_contexts->suspended.is_active();
406 }
407
408 VisionGpuExecutor() = default;
414
415private:
416 std::unique_ptr<VisionGpuContexts> m_contexts;
417
418 /**
419 * @brief 2D Gaussian kernel for convolution, cached by (radius, sigma
420 * bit pattern).
421 *
422 * Sigma is a tuning parameter that rarely changes frame to frame;
423 * recomputing exp() over (2*radius+1)^2 taps and reallocating the
424 * kernel every call is pure repeated work for an identical result.
425 *
426 * @param radius Radius of the kernel in pixels. Kernel size is (2*radius + 1)^2.
427 * @param sigma Standard deviation of the Gaussian.
428 * @return Normalized kernel weights as a flat vector in row-major order.
429 */
430 const std::vector<float>& gaussian_kernel_2d(uint32_t radius, float sigma);
431
432 /**
433 * @brief Apply an Otsu threshold to the current image.
434 *
435 * Computes the histogram and threshold on the GPU, then replaces the
436 * working image with the binary result and publishes it as
437 * VisionResult::images.threshold_otsu.
438 *
439 * @return The resulting image and the image it was derived from.
440 */
441 Kinesis::Vision::GpuVisionPass::Completed op_threshold_otsu(
442 VisionGpuContexts& contexts,
444
445 /**
446 * @brief Arbitrary rectangular sub-region of the current image,
447 * optionally resized back to the frame's own size before this
448 * step. Publishes the result as VisionResult::images.confine.
449 *
450 * @return The resulting image and the image it was derived from.
451 */
452 Kinesis::Vision::GpuVisionPass::Completed op_confine(
453 VisionGpuContexts& contexts,
455
456 /**
457 * @brief Apply morphological opening or closing to the current image.
458 *
459 * Opening erodes then dilates; closing dilates then erodes. The final
460 * image becomes the working image for the following step.
461 *
462 * @return The resulting image and the image it was derived from.
463 */
464 Kinesis::Vision::GpuVisionPass::Completed op_open_close(
465 VisionGpuContexts& contexts,
468
469 /**
470 * @brief Detect edges in the current image with the Canny pipeline.
471 *
472 * Applies smoothing, gradients, suppression, threshold classification,
473 * and hysteresis. The final edge image becomes the working image and is
474 * published as VisionResult::images.canny.
475 *
476 * @return The resulting edge image and the original input image.
477 */
478 Kinesis::Vision::GpuVisionPass::Completed op_canny(
479 VisionGpuContexts& contexts,
480 const Kinesis::Vision::VisionParams& params,
482
483 /**
484 * @brief Compute the Harris response of the current image.
485 *
486 * Packs and smooths image gradients before evaluating the response. The
487 * response image becomes the working image for a following ExtractPeaks.
488 *
489 * @return The response image and the original input image.
490 */
491 Kinesis::Vision::GpuVisionPass::Completed op_harris_response(
492 VisionGpuContexts& contexts,
494
495 /**
496 * @brief Extract and rank keypoints from the current response image.
497 *
498 * Produces structured host keypoints unless TrackKeypoints follows
499 * immediately. In that sequence, tracking extracts detections directly
500 * into its GPU buffers.
501 */
502 void op_extract_peaks(
503 VisionGpuContexts& contexts,
505
506 /**
507 * @brief Label components in the current image on the GPU.
508 *
509 * Produces component counts and bounds for structured output. When
510 * FindContours follows immediately, the labels stay on the GPU for that
511 * step and component bounds are not read back to the host.
512 */
513 void op_connected_components(
514 VisionGpuContexts& contexts,
516
517 /**
518 * @brief Trace contours from the immediately preceding component labels.
519 *
520 * Publishes either structured contours or a rendered contour image,
521 * according to the step parameters.
522 *
523 * @return False if ConnectedComponents is not the preceding step.
524 */
525 bool op_find_contours(
526 VisionGpuContexts& contexts,
528
529 /**
530 * @brief Track the previous frame's keypoints into the current frame.
531 *
532 * Adjacency mirrors ConnectedComponents into FindContours: ExtractPeaks
533 * must immediately precede, and its work is folded into this step so the
534 * detections are written straight into the flow context's buffers. The
535 * whole step is one dependency sequence: peaks, one Lucas-Kanade dispatch
536 * per pyramid level from coarse to fine, and the selection phases that
537 * build the next point list. Tracks persist: survivors carry over with
538 * their id and age, and new detections fill only the freed capacity,
539 * strongest first, one per grid cell. The first frame after a reset runs
540 * peaks and selection only.
541 *
542 * @return True when the step was deferred and the run must suspend.
543 */
544 bool op_track_keypoints(VisionGpuContexts& contexts, const Kinesis::Vision::VisionStep& step);
545
546 /**
547 * @brief Dense optical flow from the previous frame to the current one.
548 *
549 * Needs an earlier RgbaToGray step, whose gray frame the pyramid hook has
550 * already turned into the current atlas. The whole solve is one dependency
551 * sequence: for each level from coarsest to finest, the previous frame's
552 * structure tensor and then a number of warp, box sum and solve
553 * iterations. The flow of a finer level starts from the coarser one
554 * upsampled and doubled, seeded inside the first warp of the level.
555 *
556 * The first frame after a reset has no previous frame, so it only ends
557 * the frame and produces no flow.
558 *
559 * @return True when the step was deferred and the run must suspend.
560 */
561 bool op_dense_flow(VisionGpuContexts& contexts, const Kinesis::Vision::VisionStep& step);
562
563 /**
564 * @brief Build the current frame's pyramid atlas from the working image.
565 *
566 * Submitted as one un-awaited dependency sequence, one fused dispatch per
567 * level. The level 0 stage carries a hazard on the working image, which
568 * orders any later dispatch that overwrites it after this read. The
569 * fence is reaped on the next fresh run and in reset().
570 *
571 * @param src_channel Channel of the working image read as intensity: 0
572 * for a gray frame, 2 for the value channel of an HSV
573 * frame.
574 */
575 static void build_flow_pyramid(VisionGpuContexts& contexts, uint32_t requested_levels, uint32_t src_channel);
576
577 /**
578 * @brief Run any work a finished step owes the flow context.
579 *
580 * The step that produces the gray or HSV image (RgbaToGray or RgbaToHsv)
581 * feeds it to the flow context before the next pixel dispatch overwrites
582 * it, when a TrackKeypoints or OpticalFlowDense step lies ahead.
583 * Sequences without one never take this branch, and when both are
584 * present the pyramid gets the larger level count.
585 */
586 static void after_step(VisionGpuContexts& contexts, size_t index);
587
588 /**
589 * @brief Copy the working image into this snapshot's own image and append
590 * it to VisionResult::snapshots. The working image is unchanged.
591 */
592 static void op_snapshot(VisionGpuContexts& contexts);
593};
594
595} // namespace MayaFlux::Yantra
vk::Fence fence
IO::ImageData image
Definition Decoder.cpp:47
float radius
uint32_t h
Definition InkPress.cpp:29
Placement of an image pyramid inside a single atlas.
uint32_t index
Definition VKDevice.cpp:122
GpuExecutionContext specialisation for image compute shaders.
VisionGpuExecutor & operator=(const VisionGpuExecutor &)=delete
VisionGpuExecutor(const VisionGpuExecutor &)=delete
VisionGpuExecutor & operator=(VisionGpuExecutor &&)=delete
VisionGpuExecutor(VisionGpuExecutor &&)=delete
std::unique_ptr< VisionGpuContexts > m_contexts
bool is_suspended() const
True when a deferred step has work outstanding and the next run will poll rather than start a fresh s...
Stateful GPU dispatch engine for VisionSequence execution.
void run()
Definition main.cpp:21
VisionOp
Named operations available in a VisionSequence.
Definition VisionOp.hpp:30
std::variant< std::monostate, ThresholdParams, ThresholdAdaptiveParams, OtsuParams, NormalizeRangeParams, GaussianBlurParams, FilterSeparableParams, CannyParams, MorphParams, HarrisParams, ExtractPeaksParams, TrackKeypointsParams, ConnectedComponentsParams, FindContoursParams, OpticalFlowDenseParams, ConfineParams > VisionParams
Parameter variant covering all ops that carry parameters.
Definition VisionOp.hpp:358
constexpr FenceID INVALID_FENCE
Connected-component label export and color output.
Definition VisionOp.hpp:302
Contour filtering, trace limits, and output selection.
Definition VisionOp.hpp:326
Harris response parameters.
Definition VisionOp.hpp:190
Placement of every pyramid level in a single atlas.
Definition Pyramid.hpp:31
Result of executing a VisionSequence on one frame.
Ordered VisionSteps and the backend chosen to execute them.
Definition VisionOp.hpp:381
One step in a VisionSequence: an op and its parameters.
Definition VisionOp.hpp:368
Plain-data description of the compute shader to dispatch.
std::shared_ptr< Core::VKImage > last_flow
Most recent flow image and track list produced from a frame that differed from the one before it.
std::shared_ptr< Core::VKImage > flow_out[2]
Dense flow images, allocated on first use of OpticalFlowDense.
Kinesis::Vision::PyramidLayout dense_layout
uint32_t last_track_count
Track count of the last distinct frame, independent of whether a host list was produced for it,...
std::shared_ptr< Core::VKImage > flow_lvl
std::shared_ptr< Portal::Graphics::GpuBufferHandle > export_view[2]
Bookkeeping for the device resident track export.
std::shared_ptr< Core::VKImage > dense_a
std::shared_ptr< Core::VKImage > dense_tensor
Kinesis::Vision::PyramidLayout layout
std::shared_ptr< Core::VKImage > flow_vis
Portal::Graphics::FenceID build_fence
std::shared_ptr< Portal::Graphics::GpuBufferHandle > last_export
std::vector< Kinesis::Vision::TrackResult > last_tracks
std::shared_ptr< Core::VKImage > dense_b
std::shared_ptr< Core::VKImage > atlas[2]
Cross-run state of the flow context.
std::function< void(VisionGpuContexts &)> finalize
Work to run once the fence has signaled, before the walk resumes.
Outstanding work at a deferred step, and the point to resume.
TextureExecutionContext component_contours
Shared image and buffer pipeline for ConnectedComponents and FindContours.
GpuComputeConfig bound_config
Shader currently bound on pixel, and the image staged into it.
TextureExecutionContext ingest
Sampled-in, rgba32f-storage-out.
TextureExecutionContext labels
Image + aux SSBO.
Kinesis::Vision::GpuVisionPass pass
Walk state for the current run: sequence position, geometry, working image, and the result under cons...
std::shared_ptr< Core::VKImage > source
Input image the current walk started from.
std::shared_ptr< Core::VKImage > bound_staged
TextureExecutionContext pixel
Image pipeline.
std::vector< Portal::Graphics::ImageCacheSet > snapshot_images
One image cache per Snapshot step, indexed by the step's order among the snapshots of a run.
TextureExecutionContext flow
Pyramidal optical flow.
TextureExecutionContext structured
Buffer-only readback.
Fixed set of TextureExecutionContexts covering every GPU-implemented VisionOp shape.