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

◆ build_flow_pyramid()

void MayaFlux::Yantra::VisionGpuExecutor::build_flow_pyramid ( VisionGpuContexts &  contexts,
uint32_t  requested_levels,
uint32_t  src_channel 
)
staticprivate

Build the current frame's pyramid atlas from the working image.

Submitted as one un-awaited dependency sequence, one fused dispatch per level. The level 0 stage carries a hazard on the working image, which orders any later dispatch that overwrites it after this read. The fence is reaped on the next fresh run and in reset().

Parameters
src_channelChannel of the working image read as intensity: 0 for a gray frame, 2 for the value channel of an HSV frame.

Definition at line 709 of file VisionFlowDispatch.cpp.

710{
711 auto& flow = contexts.flow;
712 auto& state = contexts.flow_state;
713 const auto gray = contexts.pass.current;
714
715 if (!gray || !gray->is_initialized())
716 return;
717
718 const uint32_t w = contexts.pass.w;
719 const uint32_t h = contexts.pass.h;
720 const auto layout = pyramid_layout(w, h, requested_levels, k_flow_min_level_extent);
721
722 ensure_flow_resources(contexts);
723
724 if (!state.atlas[0] || !(state.layout == layout)) {
726 state.atlas[0] = loom.create_storage_image(layout.atlas_w, layout.atlas_h, ImageFormat::RGBA16F);
727 state.atlas[1] = loom.create_storage_image(layout.atlas_w, layout.atlas_h, ImageFormat::RGBA16F);
728 state.layout = layout;
729 state.have_prev = false;
730 state.curr = 0;
731 }
732
733 const auto atlas_a = state.atlas[0];
734 const auto atlas_b = state.atlas[1];
735 const auto target = state.atlas[state.curr];
736
737 std::vector<DependencyStage> stages;
738 stages.reserve(layout.levels);
739
740 for (uint32_t level = 0; level < layout.levels; ++level) {
741 const PyramidLevel dst = layout.level[level];
742 const PyramidLevel src = level == 0 ? PyramidLevel { .ox = 0, .oy = 0, .w = w, .h = h } : layout.level[level - 1];
743
744 const FlowPyramidPC pc {
745 .target_atlas = state.curr,
746 .level = level,
747 .src_w = src.w,
748 .src_h = src.h,
749 .src_ox = src.ox,
750 .src_oy = src.oy,
751 .dst_w = dst.w,
752 .dst_h = dst.h,
753 .dst_ox = dst.ox,
754 .dst_oy = dst.oy,
755 .src_channel = src_channel,
756 };
757
758 stages.push_back({
759 .config = { .shader_path = "flow_pyramid.comp.spv", .workgroup_size = k_wg2d, .push_constant_size = sizeof(FlowPyramidPC) },
760 .stage_fn = [gray, atlas_a, atlas_b, pc](GpuDispatchCore& ctx) {
761 ctx.stage_image_at(0, gray, GpuBufferBinding::ElementType::IMAGE_STORAGE);
762 ctx.stage_image_at(3, atlas_a, GpuBufferBinding::ElementType::IMAGE_STORAGE);
763 ctx.stage_image_at(4, atlas_b, GpuBufferBinding::ElementType::IMAGE_STORAGE);
764 ctx.set_push_constants(pc); },
765 .hazard_fn = [target, gray, level](GpuDispatchCore&) {
766 std::vector<HazardResource> hazards;
767 hazards.push_back({
768 .binding = { .set = 0, .binding = 3, .direction = GpuBufferBinding::Direction::INPUT_OUTPUT, .element_type = GpuBufferBinding::ElementType::IMAGE_STORAGE },
769 .image = target->get_image(),
770 });
771 if (level == 0) {
772 hazards.push_back({
773 .binding = { .set = 0, .binding = 0, .direction = GpuBufferBinding::Direction::INPUT_OUTPUT, .element_type = GpuBufferBinding::ElementType::IMAGE_STORAGE },
774 .image = gray->get_image(),
775 });
776 }
777 return hazards; },
778 .explicit_groups = std::array<uint32_t, 3> { (dst.w + k_wg2d[0] - 1U) / k_wg2d[0], (dst.h + k_wg2d[1] - 1U) / k_wg2d[1], 1U },
779 });
780 }
781
782 auto& foundry = Portal::Graphics::get_shader_foundry();
783 if (state.build_fence != Portal::Graphics::INVALID_FENCE) {
784 foundry.wait_for_fence(state.build_fence);
785 foundry.release_fence(state.build_fence);
786 state.build_fence = Portal::Graphics::INVALID_FENCE;
787 }
788
789 const std::array<uint32_t, 4> cleared {};
790 flow.upload_shared_raw(1, 3, reinterpret_cast<const uint8_t*>(cleared.data()), sizeof(cleared));
791
792 ExecutionContext pyramid_ctx;
793 pyramid_ctx.mode = ExecutionMode::DEPENDENCY;
794 DependencyParams pyramid_params;
795 pyramid_params.stages = stages;
796 pyramid_params.async = true;
797 pyramid_ctx.parameters = pyramid_params;
798 const auto pyramid_dispatch_result = flow.execute(Datum<> {}, pyramid_ctx);
799 state.build_fence = pyramid_dispatch_result.get_metadata<Portal::Graphics::FenceID>("gpu_fence").value_or(Portal::Graphics::INVALID_FENCE);
800 state.curr_ready = state.build_fence != Portal::Graphics::INVALID_FENCE;
801}
uint32_t h
Definition InkPress.cpp:29
uint32_t * dst
const uint32_t * src
PyramidLayout pyramid_layout(uint32_t w, uint32_t h, uint32_t requested, uint32_t min_extent=16)
Place up to requested pyramid levels for a w x h base image.
Definition Pyramid.hpp:63
constexpr FenceID INVALID_FENCE
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
constexpr uint32_t k_flow_min_level_extent
Smallest pyramid level edge worth building.
constexpr std::array< uint32_t, 3 > k_wg2d
Standard 2D workgroup used by all pixel-to-pixel vision shaders.
@ DEPENDENCY
Part of dependency graph.

References MayaFlux::Yantra::DependencyParams::async, MayaFlux::Kinesis::Vision::VisionPass< Handle >::current, MayaFlux::Yantra::DEPENDENCY, dst, MayaFlux::Yantra::VisionGpuContexts::flow, MayaFlux::Yantra::VisionGpuContexts::flow_state, MayaFlux::Portal::Graphics::get_shader_foundry(), MayaFlux::Kinesis::Vision::VisionPass< Handle >::h, h, MayaFlux::Portal::Graphics::GpuBufferBinding::IMAGE_STORAGE, MayaFlux::Portal::Graphics::GpuBufferBinding::INPUT_OUTPUT, MayaFlux::Portal::Graphics::TextureLoom::instance(), MayaFlux::Portal::Graphics::INVALID_FENCE, MayaFlux::Yantra::VisionInternal::k_flow_min_level_extent, MayaFlux::Yantra::VisionInternal::k_wg2d, MayaFlux::Yantra::ExecutionContext::mode, MayaFlux::Kinesis::Vision::PyramidLevel::ox, MayaFlux::Yantra::ExecutionContext::parameters, MayaFlux::Yantra::VisionGpuContexts::pass, MayaFlux::Kinesis::Vision::pyramid_layout(), src, MayaFlux::Yantra::DependencyParams::stages, MayaFlux::Yantra::VisionInternal::FlowPyramidPC::target_atlas, and MayaFlux::Kinesis::Vision::VisionPass< Handle >::w.

+ Here is the call graph for this function: