MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Bridge.cpp
Go to the documentation of this file.
1#include "Bridge.hpp"
2
7
11
13
15
17
19 Vruta::TaskScheduler& scheduler,
20 Buffers::BufferManager& buffer_manager)
21 : m_scheduler(scheduler)
22 , m_buffer_manager(buffer_manager)
23{
24}
25
27{
28 for (auto& [id, rec] : m_records) {
29 cancel_inbound(rec);
30 cancel_outbound(rec);
31 }
32}
33
34// =============================================================================
35// Inbound
36// =============================================================================
37
39 uint32_t id,
40 std::shared_ptr<Nodes::Node> node,
41 std::function<float(double)> project)
42{
43 auto reader = project
44 ? std::function<float()>([n = std::move(node), p = std::move(project)] {
45 return p(n->get_last_output());
46 })
47 : std::function<float()>([n = std::move(node)] {
48 return static_cast<float>(n->get_last_output());
49 });
50
51 spawn_inbound(id, std::move(reader));
52}
53
54void Bridge::bind(uint32_t id, std::function<float()> source)
55{
56 spawn_inbound(id, std::move(source));
57}
58
59void Bridge::spawn_inbound(uint32_t id, std::function<float()> source)
60{
61 auto it = m_records.find(id);
62 if (it == m_records.end()) {
64 "Bridge::bind: unknown element id {}", id);
65 return;
66 }
67
68 cancel_inbound(it->second);
69
70 auto name = make_task_name(id, "inbound");
71 it->second.inbound_task = name;
72
73 auto& rec = it->second;
74 auto writer = rec.writer;
75
76 auto routine = [](Vruta::TaskScheduler&,
77 std::function<float()> src,
78 std::function<void(float)> write) -> Vruta::GraphicsRoutine {
79 auto& p = co_await Kriya::GetGraphicsPromise {};
80 while (!p.should_terminate) {
81 write(src());
82 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
83 }
84 };
85
87 std::make_shared<Vruta::GraphicsRoutine>(
88 routine(m_scheduler, std::move(source), std::move(writer))),
89 name, false);
90}
91
92// =============================================================================
93// Outbound
94// =============================================================================
95
97 uint32_t id,
98 const std::shared_ptr<Buffers::VKBuffer>& target_buffer,
99 const std::string& shader_path,
100 uint32_t offset,
101 size_t size)
102{
103 auto it = m_records.find(id);
104 if (it == m_records.end())
105 return;
106
107 auto& rec = it->second;
108 if (!rec.bindings) {
109 rec.bindings = std::make_shared<Buffers::FormaBindingsProcessor>(shader_path);
110 m_buffer_manager.add_processor(rec.bindings, target_buffer,
112 }
113
114 rec.bindings->bind_push_constant(
115 std::to_string(id) + "_pc_" + std::to_string(offset),
116 rec.reader,
117 offset, size);
118}
119
121 uint32_t id,
122 const std::shared_ptr<Buffers::VKBuffer>& target_buffer,
123 const std::string& shader_path,
124 const std::string& descriptor_name,
125 uint32_t binding_index,
126 uint32_t set,
128{
129 auto it = m_records.find(id);
130 if (it == m_records.end()) {
132 "Bridge::write: unknown element id {}", id);
133 return;
134 }
135
136 auto& rec = it->second;
137 if (!rec.bindings) {
138 rec.bindings = std::make_shared<Buffers::FormaBindingsProcessor>(shader_path);
139 m_buffer_manager.add_processor(rec.bindings, target_buffer,
141 }
142
143 rec.bindings->bind_descriptor(
144 descriptor_name + "_" + std::to_string(id),
145 rec.reader,
146 descriptor_name,
147 binding_index, set, role);
148}
149
150void Bridge::write(uint32_t id, std::shared_ptr<Buffers::AudioWriteProcessor> target)
151{
152 auto it = m_records.find(id);
153 if (it == m_records.end()) {
155 "Bridge::write: unknown element id {}", id);
156 return;
157 }
158
159 auto name = make_task_name(id, "audio");
160 it->second.outbound_tasks.push_back(name);
161
162 auto bulk = it->second.bulk_reader;
163 auto reader = it->second.reader;
164
165 if (bulk) {
166 auto routine = [](Vruta::TaskScheduler&,
167 std::function<std::vector<float>()> b,
168 std::shared_ptr<Buffers::AudioWriteProcessor> proc)
170 auto& p = co_await Kriya::GetGraphicsPromise {};
171 while (!p.should_terminate) {
172 proc->set_data(std::span<const float>(b()));
173 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
174 }
175 };
177 std::make_shared<Vruta::GraphicsRoutine>(
178 routine(m_scheduler, std::move(bulk), std::move(target))),
179 name, false);
180 } else {
181 auto routine = [](Vruta::TaskScheduler&,
182 std::function<float()> r,
183 std::shared_ptr<Buffers::AudioWriteProcessor> proc)
185 auto& p = co_await Kriya::GetGraphicsPromise {};
186 while (!p.should_terminate) {
187 proc->set_data(std::vector<double> { static_cast<double>(r()) });
188 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
189 }
190 };
192 std::make_shared<Vruta::GraphicsRoutine>(
193 routine(m_scheduler, std::move(reader), std::move(target))),
194 name, false);
195 }
196}
197
198void Bridge::write(uint32_t id, std::shared_ptr<Buffers::DataWriteProcessor> target)
199{
200 auto it = m_records.find(id);
201 if (it == m_records.end()) {
203 "Bridge::write: unknown element id {}", id);
204 return;
205 }
206
207 auto name = make_task_name(id, "geometry");
208 it->second.outbound_tasks.push_back(name);
209
210 auto bulk = it->second.bulk_reader;
211 auto reader = it->second.reader;
212
213 if (bulk) {
214 auto routine = [](Vruta::TaskScheduler&,
215 std::function<std::vector<float>()> b,
216 std::shared_ptr<Buffers::DataWriteProcessor> proc)
218 auto& p = co_await Kriya::GetGraphicsPromise {};
219 while (!p.should_terminate) {
220 proc->set_data(Kakshya::DataVariant { b() });
221 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
222 }
223 };
225 std::make_shared<Vruta::GraphicsRoutine>(
226 routine(m_scheduler, std::move(bulk), std::move(target))),
227 name, false);
228 } else {
229 auto routine = [](Vruta::TaskScheduler&,
230 std::function<float()> r,
231 std::shared_ptr<Buffers::DataWriteProcessor> proc)
233 auto& p = co_await Kriya::GetGraphicsPromise {};
234 while (!p.should_terminate) {
235 proc->set_data(std::vector<Kakshya::DataVariant> { Kakshya::DataVariant { std::vector<float> { r() } } });
236 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
237 }
238 };
240 std::make_shared<Vruta::GraphicsRoutine>(
241 routine(m_scheduler, std::move(reader), std::move(target))),
242 name, false);
243 }
244}
245
246void Bridge::write(uint32_t id, std::shared_ptr<Nodes::Constant> node)
247{
248 auto it = m_records.find(id);
249 if (it == m_records.end()) {
251 "Bridge::write: unknown element id {}", id);
252 return;
253 }
254
255 auto name = make_task_name(id, "constant");
256 it->second.outbound_tasks.push_back(name);
257
258 auto reader = it->second.reader;
259
260 auto routine = [](Vruta::TaskScheduler&,
261 std::function<float()> r,
262 std::shared_ptr<Nodes::Constant> n)
264 auto& p = co_await Kriya::GetGraphicsPromise {};
265 while (!p.should_terminate) {
266 n->set_constant(static_cast<double>(r()));
267 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
268 }
269 };
270
272 std::make_shared<Vruta::GraphicsRoutine>(
273 routine(m_scheduler, std::move(reader), std::move(node))),
274 name, false);
275}
276
277void Bridge::write(uint32_t id, std::function<void(std::span<const float>)> sink)
278{
279 auto it = m_records.find(id);
280 if (it == m_records.end()) {
282 "Bridge::write: unknown element id {}", id);
283 return;
284 }
285
286 auto name = make_task_name(id, "bulk_sink");
287 it->second.outbound_tasks.push_back(name);
288
289 auto bulk = it->second.bulk_reader;
290 auto reader = it->second.reader;
291
292 if (bulk) {
293 auto routine = [](Vruta::TaskScheduler&,
294 std::function<std::vector<float>()> b,
295 std::function<void(std::span<const float>)> s)
297 auto& p = co_await Kriya::GetGraphicsPromise {};
298 while (!p.should_terminate) {
299 const auto v = b();
300 s(v);
301 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
302 }
303 };
305 std::make_shared<Vruta::GraphicsRoutine>(
306 routine(m_scheduler, std::move(bulk), std::move(sink))),
307 name, false);
308 } else {
309 auto routine = [](Vruta::TaskScheduler&,
310 std::function<float()> r,
311 std::function<void(std::span<const float>)> s)
313 auto& p = co_await Kriya::GetGraphicsPromise {};
314 float val {};
315 while (!p.should_terminate) {
316 val = r();
317 s(std::span<const float> { &val, 1 });
318 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
319 }
320 };
322 std::make_shared<Vruta::GraphicsRoutine>(
323 routine(m_scheduler, std::move(reader), std::move(sink))),
324 name, false);
325 }
326}
327
328// =============================================================================
329// Lifecycle
330// =============================================================================
331
332void Bridge::unbind(uint32_t id)
333{
334 auto it = m_records.find(id);
335 if (it == m_records.end())
336 return;
337
338 cancel_inbound(it->second);
339 cancel_outbound(it->second);
340}
341
342// =============================================================================
343// Private
344// =============================================================================
345
346std::string Bridge::make_task_name(uint32_t id, const char* suffix) const
347{
348 return "forma_bridge_" + std::to_string(id) + "_" + suffix
349 + "_" + std::to_string(m_next_id++);
350}
351
353{
354 if (!rec.inbound_task.empty()) {
356 rec.inbound_task.clear();
357 }
358}
359
361{
362 for (const auto& name : rec.outbound_tasks) {
364 }
365 rec.outbound_tasks.clear();
366}
367
368void Bridge::spawn_sync(uint32_t id, std::function<void()> sync_fn)
369{
370 auto name = make_task_name(id, "sync");
371 m_records[id].outbound_tasks.push_back(name);
372
373 auto routine = [](Vruta::TaskScheduler&,
374 std::function<void()> fn) -> Vruta::GraphicsRoutine {
375 auto& p = co_await Kriya::GetGraphicsPromise {};
376 while (!p.should_terminate) {
377 fn();
378 co_await Kriya::FrameDelay { .frames_to_wait = 1 };
379 }
380 };
381
383 std::make_shared<Vruta::GraphicsRoutine>(
384 routine(m_scheduler, std::move(sync_fn))),
385 name, false);
386}
387
388} // namespace MayaFlux::Portal::Forma
#define MF_ERROR(comp, ctx,...)
size_t b
void add_processor(const std::shared_ptr< BufferProcessor > &processor, const std::shared_ptr< Buffer > &buffer, ProcessingToken token=ProcessingToken::AUDIO_BACKEND)
Adds a processor to a buffer.
Token-based multimodal buffer management system for unified data stream processing.
void write(std::shared_ptr< MappedState< T > > state, std::function< void(std::span< const float >)> sink)
Definition Bridge.hpp:129
void unbind(uint32_t id)
Cancel all inbound and outbound bindings for an element.
Definition Bridge.cpp:332
Vruta::TaskScheduler & m_scheduler
Definition Bridge.hpp:522
void cancel_inbound(ElementRecord &rec)
Definition Bridge.cpp:352
std::string make_task_name(uint32_t id, const char *suffix) const
Definition Bridge.cpp:346
std::unordered_map< uint32_t, ElementRecord > m_records
Definition Bridge.hpp:527
void bind(uint32_t id, std::shared_ptr< Nodes::Node > node, std::function< float(double)> project={})
Drive element value from a Node's output each frame.
Definition Bridge.cpp:38
void spawn_inbound(uint32_t id, std::function< float()> source)
Definition Bridge.cpp:59
void spawn_sync(uint32_t id, std::function< void()> sync_fn)
Spawn a per-frame GraphicsRoutine that calls sync_fn each tick.
Definition Bridge.cpp:368
Buffers::BufferManager & m_buffer_manager
Definition Bridge.hpp:523
void cancel_outbound(ElementRecord &rec)
Definition Bridge.cpp:360
Bridge(Vruta::TaskScheduler &scheduler, Buffers::BufferManager &buffer_manager)
Definition Bridge.cpp:18
A C++20 coroutine-based graphics processing task with frame-accurate timing.
Definition Routine.hpp:496
void add_task(const std::shared_ptr< Routine > &routine, const std::string &name="", bool initialize=false)
Add a routine to the scheduler based on its processing token.
Definition Scheduler.cpp:23
bool cancel_task(const std::shared_ptr< Routine > &routine)
Cancels and removes a task from the scheduler.
Token-based multimodal task scheduling system for unified coroutine processing.
Definition Scheduler.hpp:51
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
@ Init
Engine/subsystem initialization.
@ Portal
High-level user-facing API layer.
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:76
DescriptorRole
Semantic descriptor type — maps to Vulkan descriptor types internally.
graphics-domain awaiter for frame-accurate timing delays
Templated awaitable for accessing a coroutine's promise object.
std::vector< std::string > outbound_tasks
Definition Bridge.hpp:519