39 auto& pixel_ctx = contexts.
pixel;
40 auto w = contexts.
pass.
w;
51 const std::array<uint32_t, 768> histogram_reset {};
52 pixel_ctx.upload_shared_raw(0, 3,
reinterpret_cast<const uint8_t*
>(histogram_reset.data()),
sizeof(histogram_reset));
57 const uint32_t select_groups =
channels == 0U ? 1U : 3U;
58 const auto otsu_hazard = [](uint32_t binding) {
60 return std::vector<HazardResource> {
67 std::shared_ptr<Core::VKImage> thresholded;
68 std::vector<DependencyStage> otsu_stages;
69 otsu_stages.reserve(3);
70 otsu_stages.push_back({
71 .config = { .shader_path =
"otsu_histogram.comp.spv", .workgroup_size =
k_wg2d, .push_constant_size =
sizeof(
OtsuHistPC) },
73 pixel_ctx.stage_image(otsu_input);
74 ctx.set_push_constants(hist_pc); },
75 .hazard_fn = otsu_hazard(3),
76 .explicit_groups = image_groups,
78 otsu_stages.push_back({
79 .config = { .shader_path =
"otsu_select.comp.spv", .workgroup_size = { 256, 1, 1 } },
80 .stage_fn = [&pixel_ctx, otsu_input](
GpuDispatchCore&) { pixel_ctx.stage_image(otsu_input); },
81 .hazard_fn = otsu_hazard(4),
82 .explicit_groups = std::array<uint32_t, 3> { select_groups, 1U, 1U },
84 otsu_stages.push_back({
85 .config = { .shader_path =
"otsu_apply.comp.spv", .workgroup_size =
k_wg2d, .push_constant_size =
sizeof(
OtsuApplyPC) },
86 .stage_fn = [&pixel_ctx, &thresholded, otsu_input, w,
h, apply_pc](
GpuDispatchCore& ctx) {
87 pixel_ctx.stage_image(otsu_input);
88 ctx.set_push_constants(apply_pc);
89 pixel_ctx.prepare_output_image(w,
h);
90 thresholded = pixel_ctx.get_output_image(0); },
91 .explicit_groups = image_groups,
98 otsu_params.
stages = otsu_stages;
99 otsu_params.
async =
true;
101 const auto result = pixel_ctx.execute(
Datum<> {}, otsu_ctx);
103 foundry.wait_for_fence(f);
104 foundry.release_fence(f);
111 return { .output = thresholded, .input = otsu_input };
169 auto& pixel_ctx = contexts.
pixel;
170 auto w = contexts.
pass.
w;
176 const bool is_open = (op == VisionOp::Open);
180 .
shader_path = is_open ?
"erode.comp.spv" :
"dilate.comp.spv",
182 .push_constant_size =
sizeof(
MorphPC),
185 .
shader_path = is_open ?
"dilate.comp.spv" :
"erode.comp.spv",
187 .push_constant_size =
sizeof(
MorphPC),
191 std::shared_ptr<Core::VKImage> intermediate;
192 std::shared_ptr<Core::VKImage> opened_closed;
194 std::vector<DependencyStage> morph_stages;
195 morph_stages.reserve(2);
196 morph_stages.push_back({
198 .stage_fn = [&pixel_ctx, &intermediate, morph_input, morph_pc, w,
h](
GpuDispatchCore& ctx) {
199 pixel_ctx.stage_image(morph_input);
200 pixel_ctx.prepare_output_image(w,
h);
201 intermediate = pixel_ctx.get_output_image(0);
202 ctx.set_push_constants(morph_pc); },
203 .hazard_fn = [&intermediate](
GpuDispatchCore&) {
return std::vector<HazardResource> {
205 .image = intermediate->get_image() },
207 .explicit_groups = image_groups,
209 morph_stages.push_back({
210 .config = second_cfg,
211 .stage_fn = [&pixel_ctx, &intermediate, &opened_closed, morph_pc, w,
h](
GpuDispatchCore& ctx) {
212 pixel_ctx.stage_image(intermediate);
213 pixel_ctx.prepare_output_image(w,
h);
214 opened_closed = pixel_ctx.get_output_image(0);
215 ctx.set_push_constants(morph_pc); },
216 .explicit_groups = image_groups,
223 morph_params.
stages = morph_stages;
224 morph_params.
async =
true;
226 const auto result = pixel_ctx.execute(
Datum<> {}, morph_ctx);
228 foundry.wait_for_fence(f);
229 foundry.release_fence(f);
240 return { .output = opened_closed, .input = morph_input };
248 auto& pixel_ctx = contexts.
pixel;
249 auto& label_ctx = contexts.
labels;
250 auto w = contexts.
pass.
w;
256 const auto radius =
static_cast<uint32_t
>(std::ceil(p.
sigma * 3.0F));
259 pixel_ctx.swap_shader(blur_cfg);
260 pixel_ctx.stage_image(canny_input);
261 pixel_ctx.set_binding_data(2, std::span<const float>(weights));
263 pixel_ctx.prepare_output_image(w,
h);
265 const auto f = pixel_ctx.dispatch_async({});
266 foundry.wait_for_fence(f);
267 foundry.release_fence(f);
269 const auto blurred = pixel_ctx.get_output_image(0);
272 pixel_ctx.swap_shader(sobel_cfg);
273 pixel_ctx.stage_image(blurred);
274 pixel_ctx.prepare_output_image(w,
h);
276 const auto f = pixel_ctx.dispatch_async({});
277 foundry.wait_for_fence(f);
278 foundry.release_fence(f);
280 const auto grad = pixel_ctx.get_output_image(0);
286 pixel_ctx.swap_shader(nms_cfg);
287 pixel_ctx.stage_image(grad);
288 pixel_ctx.prepare_output_image(w,
h);
290 const auto f = pixel_ctx.dispatch_async({});
291 foundry.wait_for_fence(f);
292 foundry.release_fence(f);
294 auto suppressed = pixel_ctx.get_output_image(0);
297 pixel_ctx.swap_shader(classify_cfg);
298 pixel_ctx.stage_image(suppressed);
300 pixel_ctx.prepare_output_image(w,
h);
302 const auto f = pixel_ctx.dispatch_async({});
303 foundry.wait_for_fence(f);
304 foundry.release_fence(f);
306 auto classified_weak = pixel_ctx.get_output_image(0);
308 pixel_ctx.stage_image(classified_weak);
310 pixel_ctx.prepare_output_image(w,
h);
312 const auto f = pixel_ctx.dispatch_async({});
313 foundry.wait_for_fence(f);
314 foundry.release_fence(f);
316 auto classified = pixel_ctx.get_output_image(0);
318 constexpr uint32_t k_max_hysteresis_rounds = 64;
319 label_ctx.set_output_size(2,
sizeof(uint32_t));
320 label_ctx.set_output_dimensions(w,
h);
321 label_ctx.swap_shader({
322 .shader_path =
"canny_hysteresis.comp.spv",
330 label_ctx.set_binding_data(2, std::span<const uint32_t>(&zero, 1));
336 .pc_updater = [hpc](uint32_t,
void*
dst) { std::memcpy(
dst, &hpc,
sizeof(
HysteresisPC)); },
337 .passes_per_batch = k_max_hysteresis_rounds,
339 label_ctx.execute(
Datum<> {}, chained_ctx);
342 auto hysteresis_result = classified;
347 .storage_image(
"src", BindingDirection::Input)
349 .op(KernelOp::CompareGE)
352 pixel_ctx.swap_shader(finalize_cfg);
353 pixel_ctx.stage_image(hysteresis_result);
355 pixel_ctx.prepare_output_image(w,
h);
357 const auto f = pixel_ctx.dispatch_async({});
358 foundry.wait_for_fence(f);
359 foundry.release_fence(f);
361 auto finalized = pixel_ctx.get_output_image(0);
370 return { .output = finalized, .input = canny_input };
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.
ExecutionMode mode
Execution mode controlling scheduling behavior.
ExecutionParams parameters
Optional parameters specific to the execution mode.
Context information controlling how a compute operation executes.
GpuComputeConfig bound_config
Shader currently bound on pixel, and the image staged into it.
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...
Fixed set of TextureExecutionContexts covering every GPU-implemented VisionOp shape.