MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
BufferPipelineOperations.cpp
Go to the documentation of this file.
2
5
14
15namespace MayaFlux::Kriya {
16
17namespace {
18
19 std::optional<Kakshya::DataVariant> select_operation_data(
20 const std::unordered_map<BufferOperation*, Kakshya::DataVariant>& operation_data,
21 BufferOperation& op,
22 bool graphics_read_pending)
23 {
24 if (const auto own = operation_data.find(&op); own != operation_data.end()) {
25 return own->second;
26 }
27
28 if (!operation_data.empty()) {
29 return operation_data.begin()->second;
30 }
31
32 if (graphics_read_pending) {
33 return std::nullopt;
34 }
35
36 return Kakshya::DataVariant {};
37 }
38
39 bool same_extent(const Kakshya::DataVariant& a, const Kakshya::DataVariant& b)
40 {
41 const auto size_of = [](const auto& values) { return values.size(); };
42 return a.index() == b.index() && std::visit(size_of, a) == std::visit(size_of, b);
43 }
44
45}
46
48{
49 try {
50 switch (op.get_type()) {
52 capture_operation(op, cycle);
53 break;
54
56 process_transform(op, cycle);
57 break;
58
60 process_route(op);
61 break;
62
64 process_load(op);
65 break;
66
68 process_fuse(op, cycle);
69 break;
70
72 process_dispatch(op, cycle);
73 break;
74
76 process_modify(op, cycle);
77 break;
78
80 break;
81
82 default:
85 "Unknown operation type in pipeline : {} : {}",
86 Reflect::enum_to_string(op.get_type()), std::to_string(static_cast<int>(op.get_type())));
87 break;
88 }
89 } catch (const std::exception& e) {
90 error_rethrow(Journal::Component::Kriya,
92 std::source_location::current(),
93 "Error processing operation in BufferPipeline: {}",
94 e.what());
95 }
96}
97
99{
100 auto selected = select_operation_data(m_operation_data, op, !m_readers.empty());
101 if (!selected) {
102 return;
103 }
104 auto input_data = std::move(*selected);
105
106 if (op.m_transformer) {
107 auto transformed = op.m_transformer(input_data, cycle);
108 m_operation_data[&op] = transformed;
109
110 const bool has_downstream_route = std::ranges::any_of(
112 [](const BufferOperation& o) {
114 });
115
116 if (!has_downstream_route) {
117 for (auto& candidate : std::ranges::reverse_view(m_operations)) {
118 if (&candidate == &op)
119 continue;
120 if (candidate.get_type() != BufferOperation::OpType::CAPTURE) {
121 continue;
122 }
123
124 if (const auto buf = candidate.m_capture.get_audio_buffer()) {
125 if (std::holds_alternative<std::vector<double>>(transformed)
126 && std::get<std::vector<double>>(transformed).size() == buf->get_data().size()) {
127 detail::write_to_buffer(buf, transformed);
128 }
129 break;
130 }
131
132 if (const auto target = candidate.m_capture.get_graphics_buffer()) {
133 const auto captured = m_operation_data.find(&candidate);
134 if (captured != m_operation_data.end()
136 && same_extent(captured->second, transformed)) {
137 queue_graphics_write(op, target, transformed);
138 }
139 break;
140 }
141 }
142 }
143 }
144}
145
147{
148 if (!op.m_source_images.empty()) {
149 uint32_t layer = 0;
150 for (const auto& image : op.m_source_images) {
152 }
153 return;
154 }
155
158 if (!frame) {
159 return;
160 }
161
163 m_operation_data[&op] = std::move(*frame);
164 return;
165 }
166
167 const auto selected = select_operation_data(m_operation_data, op, !m_readers.empty());
168 if (!selected) {
169 return;
170 }
171 const auto& data_to_route = *selected;
172
173 if (op.m_target_audio_buffer) {
174 if (!m_buffer_manager) {
175 error<std::invalid_argument>(Journal::Component::Kriya,
177 std::source_location::current(),
178 "BufferPipeline has no BufferManager for ROUTE-to-buffer operation");
179 }
180
181 if (!op.m_attached_processor) {
182 auto writer = std::make_shared<Buffers::AudioWriteProcessor>();
183 m_buffer_manager->add_processor(writer, op.m_target_audio_buffer,
185 op.m_attached_processor = writer;
186 }
187
188 std::static_pointer_cast<Buffers::AudioWriteProcessor>(op.m_attached_processor)
189 ->set_data(data_to_route);
190
191 } else if (op.m_target_graphics_buffer) {
192 queue_graphics_write(op, op.m_target_graphics_buffer, data_to_route);
193
194 } else if (op.m_target_audio_stream) {
196
197 } else if (op.m_target_graphics_stream) {
199 }
200}
201
216
218{
219 std::vector<Kakshya::DataVariant> fusion_inputs;
220
221 for (auto& source_buffer : op.m_source_audio_buffers) {
223 auto buffer_data = detail::extract_buffer_data(source_buffer, should_process);
224 fusion_inputs.push_back(buffer_data);
225 }
226
227 for (auto& source_container : op.m_source_audio_streams) {
228 auto container_data = detail::read_from_container(source_container, 0, 0);
229 fusion_inputs.push_back(container_data);
230 }
231
232 bool graphics_ready = true;
233 for (auto& source_buffer : op.m_source_graphics_buffers) {
234 if (auto buffer_data = read_graphics_buffer(op, source_buffer)) {
235 fusion_inputs.push_back(std::move(*buffer_data));
236 } else {
237 graphics_ready = false;
238 }
239 }
240
241 if (!graphics_ready) {
242 return;
243 }
244
245 for (auto& source_container : op.m_source_graphics_streams) {
246 fusion_inputs.push_back(detail::read_from_container(source_container, 0, 0));
247 }
248
249 if (op.m_fusion_function && !fusion_inputs.empty()) {
250 auto fused_data = op.m_fusion_function(fusion_inputs, cycle);
251
252 if (op.m_target_audio_buffer) {
254 } else if (op.m_target_graphics_buffer) {
256 } else if (op.m_target_audio_stream) {
258 } else if (op.m_target_graphics_stream) {
260 }
261
262 m_operation_data[&op] = fused_data;
263 }
264}
265
267{
268 auto selected = select_operation_data(m_operation_data, op, !m_readers.empty());
269 if (!selected) {
270 return;
271 }
272
273 if (op.m_dispatch_handler) {
274 op.m_dispatch_handler(*selected, cycle);
275 }
276}
277
279{
280 if (!m_buffer_manager) {
281 error<std::invalid_argument>(Journal::Component::Kriya,
283 std::source_location::current(),
284 "BufferPipeline has no BufferManager for MODIFY operation");
285 }
286
287 if (!op.m_attached_processor) {
289 op.m_attached_processor = m_buffer_manager->attach_quick_process(
292 } else {
293 op.m_attached_processor = m_buffer_manager->attach_quick_process(
296 }
297 if (m_max_cycles != 0 && op.is_streaming()) {
299 }
300 }
301
302 if (op.m_modify_cycle_count > 0 && cycle >= op.m_modify_cycle_count - 1) {
303 if (op.m_attached_processor) {
305 m_buffer_manager->remove_processor(
308 } else {
309 m_buffer_manager->remove_processor(
312 }
313 op.m_attached_processor = nullptr;
314 }
315 }
316}
317
319{
320 for (auto& op : m_operations) {
321 if (!op.m_render || op.m_display_attached || !op.m_target_graphics_stream) {
322 continue;
323 }
324
325 if (!m_io_manager) {
326 error<std::invalid_argument>(Journal::Component::Kriya,
328 std::source_location::current(),
329 "BufferPipeline has no IOManager to display a stream route");
330 }
331
332 auto display = m_io_manager->hook_video_container_to_buffer(op.m_target_graphics_stream);
333 if (!display) {
334 error<std::runtime_error>(Journal::Component::Kriya,
336 std::source_location::current(),
337 "Failed to hook the stream to a display buffer");
338 }
339
340 detail::ensure_rendering(display, *op.m_render);
341 op.m_display_attached = true;
342 }
343}
344
345void BufferPipeline::queue_graphics_write(BufferOperation& op, const std::shared_ptr<Buffers::VKBuffer>& target, const Kakshya::DataVariant& data)
346{
347 if (detail::accepts_layer_write(target)) {
348 detail::write_layer(target, op.m_target_layer, data);
349 return;
350 }
351
352 if (!m_buffer_manager) {
353 error<std::invalid_argument>(Journal::Component::Kriya,
355 std::source_location::current(),
356 "BufferPipeline has no BufferManager for graphics buffer write");
357 }
358
359 if (!detail::accepts_raw_write(target)) {
360 error<std::invalid_argument>(Journal::Component::Kriya,
362 std::source_location::current(),
363 "Graphics buffer regenerates its own storage; write its owner, source or image instead");
364 }
365
366 if (!op.m_attached_processor) {
367 auto writer = std::make_shared<Buffers::DataWriteProcessor>();
368 m_buffer_manager->add_processor(writer, target, Buffers::ProcessingToken::GRAPHICS_BACKEND);
369 op.m_attached_processor = writer;
370 }
371
372 std::static_pointer_cast<Buffers::DataWriteProcessor>(op.m_attached_processor)->set_data(data);
373}
374
375}
#define MF_ERROR(comp, ctx,...)
IO::ImageData image
Definition Decoder.cpp:47
bool size
size_t a
size_t b
std::vector< std::byte > values
Definition VDBWriter.cpp:26
ProcessingControl get_processing_control() const
Definition Capture.hpp:186
Buffers::GraphicsProcessingFunction m_graphics_buffer_modifier
std::vector< std::shared_ptr< Buffers::AudioBuffer > > m_source_audio_buffers
std::vector< std::shared_ptr< Buffers::VKBuffer > > m_source_graphics_buffers
std::shared_ptr< Kakshya::DynamicVideoStream > m_target_graphics_stream
Buffers::AudioProcessingFunction m_audio_buffer_modifier
Buffers::ProcessingToken get_token() const
Return the operation's processing token.
std::shared_ptr< Buffers::VKBuffer > m_source_graphics_buffer
std::shared_ptr< Buffers::AudioBuffer > m_target_audio_buffer
std::shared_ptr< Kakshya::VideoStreamContainer > m_source_graphics_stream
bool is_streaming() const
Check if this operation is a streaming operation.
TransformVectorFunction m_fusion_function
std::vector< std::shared_ptr< Core::VKImage > > m_source_images
std::shared_ptr< Buffers::BufferProcessor > m_attached_processor
OpType get_type() const
Getters for internal state (read-only)
std::vector< std::shared_ptr< Kakshya::DynamicVideoStream > > m_source_graphics_streams
std::shared_ptr< Kakshya::DynamicSoundStream > m_source_audio_stream
std::vector< std::shared_ptr< Kakshya::DynamicSoundStream > > m_source_audio_streams
TransformationFunction m_transformer
std::shared_ptr< Kakshya::DynamicSoundStream > m_target_audio_stream
@ LOAD
Load data from container to buffer with position control.
@ CONDITION
Conditional operation for branching logic.
@ FUSE
Fuse multiple sources using custom fusion functions.
@ ROUTE
Route data to destination (buffer or container)
@ CAPTURE
Capture data from source buffer using BufferCapture strategy.
@ MODIFY
Modify Buffer Data using custom quick process.
@ DISPATCH
Dispatch to external handler for custom processing.
@ TRANSFORM
Apply transformation function to data variants.
std::shared_ptr< Buffers::VKBuffer > m_target_graphics_buffer
Fundamental unit of operation in buffer processing pipelines.
std::unordered_map< BufferOperation *, Kakshya::DataVariant > m_operation_data
std::shared_ptr< IO::IOManager > m_io_manager
void queue_graphics_write(BufferOperation &op, const std::shared_ptr< Buffers::VKBuffer > &target, const Kakshya::DataVariant &data)
void process_transform(BufferOperation &op, uint64_t cycle)
void process_operation(BufferOperation &op, uint64_t cycle)
void process_modify(BufferOperation &op, uint64_t cycle)
std::map< std::pair< const BufferOperation *, const Buffers::VKBuffer * >, GraphicsReader > m_readers
std::optional< Kakshya::DataVariant > read_graphics_buffer(BufferOperation &op, const std::shared_ptr< Buffers::VKBuffer > &buffer)
void capture_operation(BufferOperation &op, uint64_t cycle)
std::vector< BufferOperation > m_operations
void process_dispatch(BufferOperation &op, uint64_t cycle)
std::shared_ptr< Buffers::BufferManager > m_buffer_manager
void process_fuse(BufferOperation &op, uint64_t cycle)
@ AUDIO_BACKEND
Standard audio processing backend configuration.
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
@ CoroutineScheduling
Coroutine scheduling and temporal coordination (Vruta::TaskScheduler)
@ Kriya
Automatable tasks and fluent scheduling api for Nodes and Buffers.
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:70
void write_layer(const std::shared_ptr< Buffers::VKBuffer > &target, uint32_t layer, const Kakshya::DataVariant &data)
Write a DataVariant into one layer of a layered buffer.
bool accepts_layer_write(const std::shared_ptr< Buffers::VKBuffer > &buffer)
Whether the buffer holds its frames as layers that can be written one at a time.
Kakshya::DataVariant read_from_container(const std::shared_ptr< Kakshya::DynamicSoundStream > &container, uint64_t, uint32_t length)
void write_to_buffer(const std::shared_ptr< Buffers::AudioBuffer > &buffer, const Kakshya::DataVariant &data)
bool ensure_rendering(const std::shared_ptr< Buffers::VKBuffer > &buffer, const Portal::Graphics::RenderConfig &config)
Make a buffer draw to the window in a render config, unless it already does.
Kakshya::DataVariant extract_buffer_data(const std::shared_ptr< Buffers::AudioBuffer > &buffer, bool should_process)
void write_to_container(const std::shared_ptr< Kakshya::DynamicSoundStream > &container, const Kakshya::DataVariant &data, uint32_t channel)
bool accepts_raw_write(const std::shared_ptr< Buffers::VKBuffer > &buffer)
Whether a DataVariant can be written to the buffer's primary storage.
constexpr std::string_view enum_to_string(EnumType value) noexcept
Universal enum to string converter using magic_enum (original case)