MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ run() [2/2]

VisionResult MayaFlux::Yantra::VisionGpuExecutor::run ( VisionGpuContexts contexts,
const Kinesis::Vision::VisionSequence sequence,
const std::shared_ptr< Core::VKImage > &  image,
uint32_t  w,
uint32_t  h 
)

Execute a VisionSequence on the GPU through an explicit context set.

contexts is caller-supplied rather than the instance's own lazily-built m_contexts. Reused across calls with no reset needed; construction is the caller's responsibility and never happens inside this function.

Parameters
contextsLong-lived context set. Never constructed internally.
sequenceOrdered steps to execute.
imageInput frame in eShaderReadOnlyOptimal layout.
wFrame width in pixels.
hFrame height in pixels.
Returns
VisionResult matching the VisionExecutor::run() contract.

Definition at line 1375 of file VisionGpuDispatch.cpp.

1380{
1381 auto& pixel_ctx = contexts.pixel;
1382 auto& structured_ctx = contexts.structured;
1383 auto& label_ctx = contexts.labels;
1384 auto& cc_pipeline = contexts.cc_pipeline;
1385
1386 auto& foundry = Portal::Graphics::get_shader_foundry();
1387 std::unordered_map<size_t, CompletedOp> completed_ops;
1388 size_t begin = 0;
1389
1390 if (contexts.suspended.is_active()) {
1391 if (&sequence != contexts.pass.sequence) {
1393 "run_gpu: polling a suspension with a different sequence; "
1394 "the walk continues on the sequence the run started from");
1395 }
1396
1397 if (!foundry.is_fence_signaled(contexts.suspended.fence)) {
1398 VisionResult pending;
1399 pending.status = VisionStatus::SUSPENDED;
1400 pending.suspended_at = contexts.pass.index;
1401 return pending;
1402 }
1403
1404 foundry.release_fence(contexts.suspended.fence);
1405 contexts.suspended.fence = Portal::Graphics::INVALID_FENCE;
1406
1407 begin = contexts.pass.index + 1;
1408 } else {
1409 reap_ingest_fences(contexts);
1410 contexts.pass.begin(sequence, w, h);
1411 const auto seed = op_ingest(contexts, image, w, h);
1412 contexts.pass.current = seed;
1413 contexts.source = seed;
1414 }
1415
1416 for (contexts.pass.index = begin; contexts.pass.index < sequence.steps.size(); ++contexts.pass.index) {
1417 const auto& step = sequence.steps[contexts.pass.index];
1418
1419 const uint32_t w = contexts.pass.w;
1420 const uint32_t h = contexts.pass.h;
1421
1422 const auto cfg = config(step.op, step.params);
1423
1424 if (cfg.shader_id == Portal::Graphics::INVALID_SHADER && cfg.shader_path.empty()) {
1426 "run_gpu: no GPU implementation for VisionOp {}",
1427 static_cast<int>(step.op));
1428 return VisionResult {};
1429 }
1430
1431 if (cfg.shader_id != contexts.bound_config.shader_id
1432 || cfg.shader_path != contexts.bound_config.shader_path) {
1433 pixel_ctx.swap_shader(cfg);
1434 contexts.bound_config = cfg;
1435 }
1436 if (contexts.pass.current != contexts.bound_staged) {
1437 pixel_ctx.stage_image(contexts.pass.current);
1438 contexts.bound_staged = contexts.pass.current;
1439 }
1440 if (w != contexts.pass.storage_w || h != contexts.pass.storage_h) {
1441 pixel_ctx.prepare_output_image(w, h);
1442 contexts.pass.storage_w = w;
1443 contexts.pass.storage_h = h;
1444 }
1445 pixel_ctx.set_output_dimensions(w, h);
1446
1447 switch (step.op) {
1448 case VisionOp::Downsample2x: {
1449 const uint32_t new_w = std::max(1U, w / 2);
1450 const uint32_t new_h = std::max(1U, h / 2);
1451
1452 pixel_ctx.prepare_output_image(new_w, new_h);
1453 pixel_ctx.set_output_dimensions(new_w, new_h);
1454 {
1455 const auto f = pixel_ctx.dispatch_async({});
1456 foundry.wait_for_fence(f);
1457 foundry.release_fence(f);
1458 }
1459 pixel_ctx.clear_output_dimensions();
1460
1461 auto downsampled = pixel_ctx.get_output_image(0);
1462 completed_ops[Kinesis::Vision::hash_vision_step(step.op, step.params)] = { .output = downsampled, .input = contexts.pass.current };
1463 contexts.pass.current = downsampled;
1464 contexts.bound_staged = contexts.pass.current;
1465
1466 contexts.pass.set_geometry(new_w, new_h);
1467 contexts.pass.storage_w = new_w;
1468 contexts.pass.storage_h = new_h;
1469
1470 continue;
1471 }
1472 case VisionOp::Threshold:
1473 pixel_ctx.set_push_constants(ThresholdPC {
1474 .value = std::get<ThresholdParams>(step.params).value });
1475 break;
1476 case VisionOp::NormalizeRange: {
1477 const auto& p = std::get<NormalizeRangeParams>(step.params);
1478 const float scale = (p.hi > p.lo) ? 1.0F / (p.hi - p.lo) : 1.0F;
1479 const float off = (p.hi > p.lo) ? -p.lo / (p.hi - p.lo) : 0.0F;
1480 pixel_ctx.set_push_constants(NormalizePC { .scale = scale, .offset = off });
1481 break;
1482 }
1483 case VisionOp::RgbaToGray:
1484 pixel_ctx.set_push_constants(RgbaToGrayPC {
1485 .wr = 0.299F, .wg = 0.587F, .wb = 0.114F, .wa = 0.0F });
1486 break;
1487 case VisionOp::GaussianBlur: {
1488 const auto& p = std::get<GaussianBlurParams>(step.params);
1489 const auto radius = static_cast<uint32_t>(std::ceil(p.sigma * 3.0F));
1490 const auto& weights = gaussian_kernel_1d(radius, p.sigma);
1491 pixel_ctx.set_binding_data(2, std::span<const float>(weights));
1492 pixel_ctx.set_push_constants(GaussianPC { .radius = radius, .width = w, .height = h });
1493 break;
1494 }
1495 case VisionOp::Erode:
1496 case VisionOp::Dilate:
1497 case VisionOp::MorphGradient:
1498 pixel_ctx.set_push_constants(MorphPC {
1499 .radius = std::get<MorphParams>(step.params).radius });
1500 break;
1501 case VisionOp::ThresholdAdaptive: {
1502 const auto& p = std::get<ThresholdAdaptiveParams>(step.params);
1503 pixel_ctx.set_push_constants(ThresholdAdaptivePC { .block_size = p.block_size, .offset = p.offset });
1504 break;
1505 }
1506 case VisionOp::ThresholdOtsu: {
1507 contexts.pass.completed[Kinesis::Vision::hash_vision_step(step.op, step.params)] = op_threshold_otsu(contexts);
1508 continue;
1509 }
1510 case VisionOp::Open:
1511 case VisionOp::Close: {
1512 contexts.pass.completed[Kinesis::Vision::hash_vision_step(step.op, step.params)] = op_open_close(contexts, step.op, std::get<MorphParams>(step.params));
1513 continue;
1514 }
1515 case VisionOp::Canny: {
1516 auto done = op_canny(contexts, step.params, std::get<CannyParams>(step.params));
1517 contexts.pass.completed[Kinesis::Vision::hash_vision_step(step.op, step.params)] = done;
1518 continue;
1519 }
1520 case VisionOp::HarrisResponse: {
1521 contexts.pass.completed[Kinesis::Vision::hash_vision_step(step.op, step.params)] = op_harris_response(contexts, std::get<HarrisParams>(step.params));
1522 continue;
1523 }
1524 case VisionOp::ExtractPeaks: {
1525 op_extract_peaks(contexts, std::get<ExtractPeaksParams>(step.params));
1526 continue;
1527 }
1528 case VisionOp::ConnectedComponents: {
1529 if (!contexts.pass.current) {
1530 continue;
1531 }
1532 op_connected_components(contexts, std::get<Kinesis::Vision::ConnectedComponentsParams>(step.params));
1533 continue;
1534 }
1535 case VisionOp::FindContours: {
1536 if (!op_find_contours(contexts,
1537 std::get<Kinesis::Vision::FindContoursParams>(step.params)))
1538 return VisionResult {};
1539 continue;
1540 }
1541 default:
1542 break;
1543 }
1544
1545 auto dispatch_input = contexts.pass.current;
1546 const auto fence = pixel_ctx.dispatch_async({});
1547
1548 if (step.deferred) {
1549 pixel_ctx.clear_output_dimensions();
1550 contexts.pass.current = pixel_ctx.get_output_image(0);
1551 contexts.bound_staged = contexts.pass.current;
1552
1553 const Kinesis::Vision::GpuVisionPass::Completed done {
1554 .output = contexts.pass.current,
1555 .input = dispatch_input
1556 };
1557 contexts.pass.completed[Kinesis::Vision::hash_vision_step(step.op, step.params)] = done;
1558
1559 contexts.suspended.fence = fence;
1560
1561 VisionResult pending;
1562 pending.status = VisionStatus::SUSPENDED;
1563 pending.suspended_at = contexts.pass.index;
1564 return pending;
1565 }
1566
1567 foundry.wait_for_fence(fence);
1568 foundry.release_fence(fence);
1569
1570 pixel_ctx.clear_output_dimensions();
1571 contexts.pass.current = pixel_ctx.get_output_image(0);
1572 contexts.bound_staged = contexts.pass.current;
1573 completed_ops[Kinesis::Vision::hash_vision_step(step.op, step.params)] = { .output = contexts.pass.current, .input = dispatch_input };
1574 }
1575
1576 return std::move(contexts.pass.result);
1577}
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
vk::Fence fence
IO::ImageData image
Definition Decoder.cpp:64
float radius
uint32_t h
Definition InkPress.cpp:28
float scale
static GpuComputeConfig config(Kinesis::Vision::VisionOp op, const Kinesis::Vision::VisionParams &params)
GpuComputeConfig for a given VisionOp and its parameters.
@ ComputeMatrix
Compute operations (Yantra - algorithms, matrices, DSP)
@ Yantra
DSP algorithms, computational units, matrix operations, Grammar.
size_t hash_vision_step(VisionOp op, const VisionParams &params)
Hash a VisionStep's op and parameters together.
Definition VisionOp.hpp:367
std::shared_ptr< Vruta::Routine > sequence(std::vector< std::pair< double, std::function< void()> > > sequence, Vruta::ProcessingToken token)
Creates a temporal sequence that executes callbacks at specified time offsets.
Definition Tasks.cpp:36
constexpr ShaderID INVALID_SHADER
constexpr FenceID INVALID_FENCE
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.

References MayaFlux::Kinesis::Vision::VisionPass< Handle >::begin(), MayaFlux::Yantra::VisionGpuContexts::bound_config, MayaFlux::Yantra::VisionGpuContexts::bound_staged, MayaFlux::Yantra::VisionGpuContexts::cc_pipeline, MayaFlux::Kinesis::Vision::VisionPass< Handle >::completed, MayaFlux::Journal::ComputeMatrix, MayaFlux::Kinesis::Vision::VisionPass< Handle >::current, fence, MayaFlux::Yantra::VisionGpuContexts::Suspension::fence, MayaFlux::Portal::Graphics::get_shader_foundry(), MayaFlux::Kinesis::Vision::VisionPass< Handle >::h, h, MayaFlux::Kinesis::Vision::hash_vision_step(), image, MayaFlux::Kinesis::Vision::VisionPass< Handle >::index, MayaFlux::Portal::Graphics::INVALID_FENCE, MayaFlux::Portal::Graphics::INVALID_SHADER, MayaFlux::Yantra::VisionGpuContexts::Suspension::is_active(), MayaFlux::Yantra::VisionGpuContexts::labels, MF_ERROR, MF_WARN, MayaFlux::Yantra::VisionGpuContexts::pass, MayaFlux::Yantra::VisionGpuContexts::pixel, radius, MayaFlux::Kinesis::Vision::VisionPass< Handle >::result, scale, MayaFlux::Kinesis::Vision::VisionPass< Handle >::sequence, MayaFlux::Kinesis::Vision::VisionPass< Handle >::set_geometry(), MayaFlux::Portal::Graphics::GpuComputeConfig::shader_id, MayaFlux::Portal::Graphics::GpuComputeConfig::shader_path, MayaFlux::Yantra::VisionGpuContexts::source, MayaFlux::Kinesis::Vision::VisionResult::status, MayaFlux::Kinesis::Vision::VisionPass< Handle >::storage_h, MayaFlux::Kinesis::Vision::VisionPass< Handle >::storage_w, MayaFlux::Yantra::VisionGpuContexts::structured, MayaFlux::Yantra::VisionGpuContexts::suspended, MayaFlux::Kinesis::Vision::VisionResult::suspended_at, MayaFlux::Kinesis::Vision::VisionPass< Handle >::w, and MayaFlux::Journal::Yantra.

+ Here is the call graph for this function: