5using namespace VisionInternal;
7using namespace Portal::Graphics;
8using namespace Kinesis::Vision;
14 auto& pixel_ctx = contexts.
pixel;
15 auto w = contexts.
pass.
w;
19 const auto radius =
static_cast<uint32_t
>(std::ceil(p.
sigma * 3.0F));
24 pixel_ctx.swap_shader({ .shader_path =
"harris_grad_pack.comp.spv", .workgroup_size =
k_wg2d });
25 pixel_ctx.stage_image(harris_input);
26 pixel_ctx.prepare_output_image(w,
h);
28 const auto f = pixel_ctx.dispatch_async({});
29 foundry.wait_for_fence(f);
30 foundry.release_fence(f);
32 auto packed = pixel_ctx.get_output_image(0);
35 pixel_ctx.swap_shader(blur_cfg);
36 pixel_ctx.stage_image(packed);
37 pixel_ctx.set_binding_data(2, std::span<const float>(weights));
39 pixel_ctx.prepare_output_image(w,
h);
41 const auto f = pixel_ctx.dispatch_async({});
42 foundry.wait_for_fence(f);
43 foundry.release_fence(f);
45 auto smoothed = pixel_ctx.get_output_image(0);
50 .push_constant_size =
sizeof(
HarrisPC),
52 pixel_ctx.swap_shader(harris_resp_cfg);
53 pixel_ctx.stage_image(smoothed);
57 const uint32_t peak_reset = 0U;
58 pixel_ctx.set_binding_data(2, std::span<const uint32_t>(&peak_reset, 1));
60 pixel_ctx.set_push_constants(
HarrisPC { .
k = p.
k, .pass = 0U, .width = w, .height =
h, .rect = rect });
61 pixel_ctx.prepare_output_image(w,
h);
63 const auto f = pixel_ctx.dispatch_async({});
64 foundry.wait_for_fence(f);
65 foundry.release_fence(f);
68 pixel_ctx.set_binding_data(2, std::span<const uint32_t>(&peak_reset, 0));
69 pixel_ctx.set_push_constants(
HarrisPC { .
k = p.
k, .pass = 1U, .width = w, .height =
h, .rect = rect });
71 const auto f = pixel_ctx.dispatch_async({});
72 foundry.wait_for_fence(f);
73 foundry.release_fence(f);
76 contexts.
pass.
current = pixel_ctx.get_output_image(0);
83 return { .output = contexts.
pass.
current, .input = harris_input };
91 auto w = contexts.
pass.
w;
95 constexpr uint32_t k_max_kp = 4096;
97 const auto* tracker = contexts.
pass.
ahead();
98 if (tracker && tracker->op == VisionOp::TrackKeypoints) {
105 structured_ctx.swap_shader({
106 .shader_path =
"extract_peaks.comp.spv",
107 .workgroup_size = { 8, 8, 1 },
111 structured_ctx.set_output_size(1,
sizeof(uint32_t));
112 structured_ctx.set_output_size(2,
static_cast<size_t>(k_max_kp) * 4 *
sizeof(float));
113 structured_ctx.ensure_shared_buffer(0, 3, (
static_cast<size_t>(k_max_kp) + 1U) * 4U,
122 .max_keypoints = k_max_kp,
126 structured_ctx.set_output_dimensions(w,
h);
127 const auto fence = structured_ctx.dispatch_async({});
128 structured_ctx.clear_output_dimensions();
129 foundry.wait_for_fence(
fence);
130 foundry.release_fence(
fence);
132 const auto gpu_result = structured_ctx.collect_result();
135 if (
auto it = gpu_result.aux.find(1); it != gpu_result.aux.end())
136 std::memcpy(&
count, it->second.data(),
sizeof(uint32_t));
140 const glm::vec4 header { std::bit_cast<float>(
count), 0.0F, 0.0F, 0.0F };
141 structured_ctx.upload_shared_raw(0, 3,
reinterpret_cast<const uint8_t*
>(&header),
sizeof(glm::vec4));
143 structured_ctx.shared_buffer_handle(0, 3));
147 float x, y, response, pad;
149 std::vector<GpuKp> raw(
count);
151 if (
auto it = gpu_result.aux.find(2); it != gpu_result.aux.end())
152 std::memcpy(raw.data(), it->second.data(),
count *
sizeof(GpuKp));
155 std::vector<Kinesis::Vision::Keypoint> kpts;
157 for (
const auto& kp : raw) {
158 kpts.push_back({ .position = { kp.x, kp.y },
159 .response = kp.response,
163 std::ranges::sort(kpts, [](
const auto&
a,
const auto&
b) {
return a.response >
b.response; });
178 const auto* records =
static_cast<const glm::vec4*
>(handle->mapped_ptr) + 1;
179 std::vector<Kinesis::Vision::Keypoint>
out;
181 for (uint32_t i = 0; i < *
count; ++i) {
183 .position = { records[i].x, records[i].y },
184 .response = records[i].z,
std::vector< float > * out
const std::vector< float > & gaussian_kernel_2d(uint32_t radius, float sigma)
2D Gaussian kernel for convolution, cached by (radius, sigma bit pattern).
static GpuComputeConfig config(Kinesis::Vision::VisionOp op, const Kinesis::Vision::VisionParams ¶ms)
GpuComputeConfig for a given VisionOp and its parameters.
Kinesis::Vision::GpuVisionPass::Completed op_harris_response(VisionGpuContexts &contexts, const Kinesis::Vision::HarrisParams &p)
Compute the Harris response of the current image.
void op_extract_peaks(VisionGpuContexts &contexts, const Kinesis::Vision::ExtractPeaksParams &p)
Extract and rank keypoints from the current response image.
static std::vector< Kinesis::Vision::Keypoint > read_exported_keypoints(const Kinesis::Vision::VisionResult &result)
Host keypoints decoded from result.buffers.keypoints, or empty.
MAYAFLUX_API ShaderFoundry & get_shader_foundry()
Get the global shader compiler instance.
@ COMPUTE
Storage buffer for compute shaders (device-local)
std::optional< uint32_t > exported_record_count(const std::shared_ptr< Portal::Graphics::GpuBufferHandle > &handle, size_t stride_vec4)
Clamped record count from an exported buffer's vec4 header, or nullopt when the buffer isn't readable...
PixelRect region_rect(const std::optional< Kinesis::Vision::BoundingBox > ®ion, uint32_t w, uint32_t h)
Pixel rectangle of a normalised region over a w x h image, clamped to the image.
constexpr std::array< uint32_t, 3 > k_wg2d
Standard 2D workgroup used by all pixel-to-pixel vision shaders.
std::shared_ptr< Portal::Graphics::GpuBufferHandle > keypoints
std::optional< BoundingBox > region
Harris response parameters.
std::shared_ptr< Core::VKImage > harris_response
const VisionStep * ahead(size_t offset=1) const noexcept
Op at offset steps ahead, or nullptr past the end.
BufferOutputs buffers
GPU-resident export buffers, one named slot per exporting op.
StructuredOutput structured
ImageOutputs images
Image output of whichever image-producing ops ran in this sequence, one named slot per op.
Result of executing a VisionSequence on one frame.
enum MayaFlux::Portal::Graphics::GpuBufferBinding::ElementType FLOAT32
Plain-data description of the compute shader to dispatch.
GpuComputeConfig bound_config
Shader currently bound on pixel, and the image staged into it.
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 > bound_staged
TextureExecutionContext pixel
Image pipeline.
TextureExecutionContext structured
Buffer-only readback.
Fixed set of TextureExecutionContexts covering every GPU-implemented VisionOp shape.