MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
WindowContainer.cpp
Go to the documentation of this file.
1#include "WindowContainer.hpp"
2
10
12
13namespace MayaFlux::Kakshya {
14
15namespace {
16
17 /**
18 * @brief Map a MayaFlux surface format to the closest Portal ImageFormat.
19 *
20 * Packed A2B10G10R10 has no direct ImageFormat equivalent; it is widened
21 * to RGBA16F so TextureLoom can allocate a sampled image without data loss.
22 */
23 Portal::Graphics::ImageFormat surface_format_to_image_format(
25 {
28 switch (fmt) {
29 case SF::B8G8R8A8_SRGB:
30 return IF::BGRA8_SRGB;
31 case SF::B8G8R8A8_UNORM:
32 return IF::BGRA8;
33 case SF::R8G8B8A8_SRGB:
34 return IF::RGBA8_SRGB;
35 case SF::R8G8B8A8_UNORM:
36 return IF::RGBA8;
37 case SF::R16G16B16A16_SFLOAT:
38 case SF::A2B10G10R10_UNORM:
39 return IF::RGBA16F;
40 case SF::R32G32B32A32_SFLOAT:
41 return IF::RGBA32F;
42 default:
43 return IF::BGRA8_SRGB;
44 }
45 }
46
47} // namespace
48
49WindowContainer::WindowContainer(std::shared_ptr<Core::Window> window,
50 uint32_t frame_capacity)
51 : m_window(std::move(window))
52 , m_frame_capacity(frame_capacity)
53{
54 if (!m_window) {
55 error<std::invalid_argument>(
58 std::source_location::current(),
59 "WindowContainer requires a valid window");
60 }
61
63
65 "WindowContainer created for window '{}' ({}x{} frames={})",
66 m_window->get_create_info().title,
68}
69
71{
72 return surface_format_to_image_format(query_surface_format(m_window));
73}
74
75// =========================================================================
76// Setup
77// =========================================================================
78
80{
81 const auto& fmt = m_window->get_create_info().container_format;
82 const uint32_t w = m_window->get_create_info().width;
83 const uint32_t h = m_window->get_create_info().height;
84 const uint32_t c = fmt.color_channels;
85 const size_t sz = static_cast<size_t>(w) * h * c;
86
88
91 { static_cast<uint64_t>(m_frame_capacity),
92 static_cast<uint64_t>(h),
93 static_cast<uint64_t>(w),
94 static_cast<uint64_t>(c) },
96
98 for (auto& slot : m_data)
99 slot = std::vector<uint8_t>(sz, 0U);
100
101 m_processed_data.resize(1);
102 m_processed_data[0] = std::vector<uint8_t>(sz, 0U);
103}
104
105uint8_t* WindowContainer::mutable_frame_ptr(uint32_t frame_index)
106{
107 if (frame_index >= m_data.size())
108 return nullptr;
109
110 auto* v = std::get_if<std::vector<uint8_t>>(&m_data[frame_index]);
111 return (v && !v->empty()) ? v->data() : nullptr;
112}
113
115{
116 m_write_head.store((m_write_head.load(std::memory_order_relaxed) + 1U) % m_frame_capacity,
117 std::memory_order_release);
118 m_frames_written.fetch_add(1U, std::memory_order_release);
119}
120
121// =========================================================================
122// NDDimensionalContainer
123// =========================================================================
124
125std::vector<DataDimension> WindowContainer::get_dimensions() const
126{
127 return m_structure.dimensions;
128}
129
134
139
144
145std::vector<DataVariant> WindowContainer::get_region_data(const Region& region) const
146{
147 std::shared_lock lock(m_data_mutex);
148
149 if (m_processed_data.empty())
150 return {};
151
152 const auto* src = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
153 if (!src || src->empty())
154 return {};
155
156 const auto& dims = m_structure.dimensions;
157 const std::span<const uint8_t> src_span { src->data(), src->size() };
158
159 std::vector<DataVariant> result;
160
161 for (const auto& [name, group] : m_region_groups) {
162 for (const auto& r : group.regions) {
163 if (!regions_intersect(r, region))
164 continue;
165 try {
166 result.emplace_back(extract_nd_region<uint8_t>(src_span, r, dims));
167 } catch (const std::exception& e) {
169 "WindowContainer::get_region_data extraction failed — {}", e.what());
170 }
171 }
172 }
173
174 return result;
175}
176
177std::shared_ptr<Core::VKImage> WindowContainer::to_image() const
178{
179 std::shared_lock lock(m_data_mutex);
180
181 if (m_processed_data.empty()) {
183 "WindowContainer::to_image : no readback data available for '{}'",
184 m_window->get_create_info().title);
185 return nullptr;
186 }
187
188 const auto* pixels = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
189 if (!pixels || pixels->empty()) {
191 "WindowContainer::to_image : processed_data[0] is not uint8_t or is empty for '{}'",
192 m_window->get_create_info().title);
193 return nullptr;
194 }
195
196 const auto fmt = query_surface_format(m_window);
197 const auto img_fmt = surface_format_to_image_format(fmt);
198 const uint32_t w = m_structure.get_width();
199 const uint32_t h = m_structure.get_height();
200
202 w, h, img_fmt, pixels->data());
203
204 if (!img) {
206 "WindowContainer::to_image : TextureLoom::create_2d failed for '{}'",
207 m_window->get_create_info().title);
208 }
209
210 return img;
211}
212
213std::shared_ptr<Core::VKImage> WindowContainer::to_image(
214 const std::shared_ptr<Buffers::VKBuffer>& staging) const
215{
216 std::shared_lock lock(m_data_mutex);
217
218 if (m_processed_data.empty()) {
220 "WindowContainer::to_image(staging) : no readback data for '{}'",
221 m_window->get_create_info().title);
222 return nullptr;
223 }
224
225 const auto* pixels = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
226 if (!pixels || pixels->empty()) {
228 "WindowContainer::to_image(staging) : processed_data[0] is not uint8_t or is empty for '{}'",
229 m_window->get_create_info().title);
230 return nullptr;
231 }
232
233 const auto fmt = query_surface_format(m_window);
234 const auto img_fmt = surface_format_to_image_format(fmt);
235 const uint32_t w = m_structure.get_width();
236 const uint32_t h = m_structure.get_height();
237
239
240 auto img = loom.create_2d(w, h, img_fmt, nullptr);
241 if (!img) {
243 "WindowContainer::to_image(staging) : VKImage allocation failed for '{}'",
244 m_window->get_create_info().title);
245 return nullptr;
246 }
247
248 loom.upload_data(img, pixels->data(), pixels->size(), staging);
249 return img;
250}
251
252std::shared_ptr<Core::VKImage> WindowContainer::image_at(uint32_t frame_index) const
253{
254 std::shared_lock lock(m_data_mutex);
255
256 if (frame_index >= m_data.size()) {
258 "WindowContainer::to_image({}) : out of range (capacity={})",
259 frame_index, m_frame_capacity);
260 return nullptr;
261 }
262
263 {
264 const uint64_t written = m_frames_written.load(std::memory_order_acquire);
265 const uint32_t head = m_write_head.load(std::memory_order_acquire);
266 const bool ring_full = written >= m_frame_capacity;
267 const bool slot_valid = ring_full || frame_index < head;
268 if (!slot_valid) {
270 "WindowContainer::image_at({}) : frame index is ahead of write head ({}), data may be stale or uninitialized",
271 frame_index, head);
272 return nullptr;
273 }
274 }
275
276 const auto* pixels = std::get_if<std::vector<uint8_t>>(&m_data[frame_index]);
277 if (!pixels || pixels->empty()) {
279 "WindowContainer::image_at({}) : slot is empty", frame_index);
280 return nullptr;
281 }
282
283 const auto img_fmt = surface_format_to_image_format(query_surface_format(m_window));
285 m_structure.get_width(), m_structure.get_height(), img_fmt, pixels->data());
286
287 if (!img) {
289 "WindowContainer::image_at({}) : TextureLoom::create_2d failed", frame_index);
290 }
291
292 return img;
293}
294
295std::shared_ptr<Core::VKImage> WindowContainer::image_at(
296 const std::shared_ptr<Buffers::VKBuffer>& staging, uint32_t frame_index) const
297{
298 std::shared_lock lock(m_data_mutex);
299
300 if (frame_index >= m_data.size()) {
302 "WindowContainer::image_at(staging, {}) : out of range (capacity={})",
303 frame_index, m_frame_capacity);
304 return nullptr;
305 }
306
307 {
308 const uint64_t written = m_frames_written.load(std::memory_order_acquire);
309 const uint32_t head = m_write_head.load(std::memory_order_acquire);
310 const bool ring_full = written >= m_frame_capacity;
311 const bool slot_valid = ring_full || frame_index < head;
312 if (!slot_valid) {
314 "WindowContainer::image_at(staging, {}) : frame index is ahead of write head ({}), data may be stale or uninitialized",
315 frame_index, head);
316 return nullptr;
317 }
318 }
319
320 const auto* pixels = std::get_if<std::vector<uint8_t>>(&m_data[frame_index]);
321 if (!pixels || pixels->empty()) {
323 "WindowContainer::image_at(staging, {}) — slot is empty", frame_index);
324 return nullptr;
325 }
326
327 const auto img_fmt = surface_format_to_image_format(query_surface_format(m_window));
329
330 auto img = loom.create_2d(
331 m_structure.get_width(), m_structure.get_height(), img_fmt, nullptr);
332 if (!img) {
334 "WindowContainer::image_at(staging, {}) : VKImage allocation failed", frame_index);
335 return nullptr;
336 }
337
338 loom.upload_data(img, pixels->data(), pixels->size(), staging);
339 return img;
340}
341
342std::shared_ptr<Core::VKImage> WindowContainer::region_to_image(const Region& region) const
343{
344 std::shared_lock lock(m_data_mutex);
345
346 if (m_processed_data.empty()) {
348 "WindowContainer::region_to_image — no readback data for '{}'",
349 m_window->get_create_info().title);
350 return nullptr;
351 }
352
353 const auto* src = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
354 if (!src || src->empty()) {
356 "WindowContainer::region_to_image — processed_data[0] is not uint8_t or is empty for '{}'",
357 m_window->get_create_info().title);
358 return nullptr;
359 }
360
361 std::vector<uint8_t> cropped;
362 try {
363 cropped = extract_region_data<uint8_t>(
364 std::span<const uint8_t> { src->data(), src->size() },
365 region,
367 } catch (const std::exception& e) {
369 "WindowContainer::region_to_image — crop failed for '{}': {}",
370 m_window->get_create_info().title, e.what());
371 return nullptr;
372 }
373
374 if (region.start_coordinates.size() < 2 || region.end_coordinates.size() < 2) {
376 "WindowContainer::region_to_image — region must have at least 2 coordinates (SPATIAL_Y, SPATIAL_X)");
377 return nullptr;
378 }
379
380 const auto rh = static_cast<uint32_t>(
381 region.end_coordinates[0] - region.start_coordinates[0] + 1);
382 const auto rw = static_cast<uint32_t>(
383 region.end_coordinates[1] - region.start_coordinates[1] + 1);
384
385 const auto fmt = query_surface_format(m_window);
386 const auto img_fmt = surface_format_to_image_format(fmt);
387
389 rw, rh, img_fmt, cropped.data());
390
391 if (!img) {
393 "WindowContainer::region_to_image — TextureLoom::create_2d failed ({}x{}) for '{}'",
394 rw, rh, m_window->get_create_info().title);
395 }
396
397 return img;
398}
399
400void WindowContainer::set_region_data(const Region& /*region*/, const std::vector<DataVariant>& /*data*/)
401{
403 "WindowContainer::set_region_data — write path not yet implemented");
404}
405
406std::vector<DataVariant> WindowContainer::get_region_group_data(const RegionGroup& /*group*/) const
407{
408 std::shared_lock lock(m_data_mutex);
409 return m_processed_data;
410}
411
412std::vector<DataVariant> WindowContainer::get_segments_data(const std::vector<RegionSegment>& /*segments*/) const
413{
414 std::shared_lock lock(m_data_mutex);
415 return m_processed_data;
416}
417
418double WindowContainer::get_value_at(const std::vector<uint64_t>& coordinates) const
419{
420 if (coordinates.size() < 3 || m_processed_data.empty())
421 return 0.0;
422
423 const auto* pixels = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
424 if (!pixels)
425 return 0.0;
426
427 const uint64_t w = m_structure.get_width();
428 const uint64_t c = m_structure.get_channel_count();
429 const uint64_t idx = (coordinates[0] * w + coordinates[1]) * c + coordinates[2];
430
431 if (idx >= pixels->size())
432 return 0.0;
433
434 return static_cast<double>((*pixels)[idx]) / 255.0;
435}
436
437void WindowContainer::set_value_at(const std::vector<uint64_t>& /*coords*/, double /*value*/) { }
438
439uint64_t WindowContainer::coordinates_to_linear_index(const std::vector<uint64_t>& coordinates) const
440{
441 return coordinates_to_linear(coordinates, m_structure.dimensions);
442}
443
444std::vector<uint64_t> WindowContainer::linear_index_to_coordinates(uint64_t index) const
445{
447}
448
450{
451 std::unique_lock lock(m_data_mutex);
452 const size_t sz = m_structure.get_total_elements();
453 m_processed_data.resize(1);
454 m_processed_data[0] = std::vector<uint8_t>(sz, 0U);
456}
457
460bool WindowContainer::try_lock() { return m_data_mutex.try_lock(); }
461
463{
464 if (m_processed_data.empty())
465 return nullptr;
466 const auto* v = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
467 return (v && !v->empty()) ? v->data() : nullptr;
468}
469
471{
472 std::shared_lock lock(m_data_mutex);
473 if (m_processed_data.empty())
474 return false;
475 return std::visit([](const auto& v) { return !v.empty(); }, m_processed_data[0]);
476}
477
479{
481 "WindowContainer::load_region — no-op. Register regions via add_region_group()");
482}
483
485{
487 "WindowContainer::unload_region — no-op. Remove regions via remove_region_group()");
488}
489
490bool WindowContainer::is_region_loaded(const Region& /*region*/) const
491{
492 return true;
493}
494
495// =========================================================================
496// RegionGroup management
497// =========================================================================
498
500{
501 std::lock_guard lock(m_state_mutex);
502 m_region_groups[group.name] = group;
503}
504
505const RegionGroup& WindowContainer::get_region_group(const std::string& name) const
506{
507 static const RegionGroup empty;
508 std::shared_lock lock(m_data_mutex);
509 auto it = m_region_groups.find(name);
510 return it != m_region_groups.end() ? it->second : empty;
511}
512
513std::unordered_map<std::string, RegionGroup> WindowContainer::get_all_region_groups() const
514{
515 std::shared_lock lock(m_data_mutex);
516 return m_region_groups;
517}
518
519void WindowContainer::remove_region_group(const std::string& name)
520{
521 std::lock_guard lock(m_state_mutex);
522 m_region_groups.erase(name);
523}
524
525// =========================================================================
526// SignalSourceContainer
527// =========================================================================
528
533
535{
536 ProcessingState old = m_processing_state.exchange(new_state);
537 if (old == new_state)
538 return;
539
540 std::lock_guard lock(m_state_mutex);
542 m_state_callback(shared_from_this(), new_state);
543}
544
546 std::function<void(const std::shared_ptr<SignalSourceContainer>&, ProcessingState)> callback)
547{
548 std::lock_guard lock(m_state_mutex);
549 m_state_callback = std::move(callback);
550}
551
553{
554 std::lock_guard lock(m_state_mutex);
555 m_state_callback = nullptr;
556}
557
559{
560 return m_ready_for_processing.load(std::memory_order_acquire);
561}
562
564{
565 m_ready_for_processing.store(ready, std::memory_order_release);
566}
567
569{
570 auto readback = std::make_shared<WindowAccessProcessor>();
571 readback->on_attach(shared_from_this());
572 m_default_processor = readback;
573}
574
576{
578 m_default_processor->process(shared_from_this());
579}
580
581void WindowContainer::set_default_processor(const std::shared_ptr<DataProcessor>& proc)
582{
584 m_default_processor->on_detach(shared_from_this());
585 m_default_processor = proc;
587 m_default_processor->on_attach(shared_from_this());
588}
589
590std::shared_ptr<DataProcessor> WindowContainer::get_default_processor() const
591{
592 return m_default_processor;
593}
594
595std::shared_ptr<DataProcessingChain> WindowContainer::get_processing_chain()
596{
597 return m_processing_chain;
598}
599
600void WindowContainer::set_processing_chain(const std::shared_ptr<DataProcessingChain>& chain)
601{
602 m_processing_chain = chain;
603}
604
605// =========================================================================
606// Consumer tracking
607// =========================================================================
608
609uint32_t WindowContainer::register_dimension_reader(uint32_t /*slot_index*/)
610{
612 return m_next_reader_id.fetch_add(1, std::memory_order_relaxed);
613}
614
616{
617 if (m_registered_readers.load(std::memory_order_relaxed) > 0)
619}
620
622{
623 return m_registered_readers.load(std::memory_order_acquire) > 0;
624}
625
626void WindowContainer::mark_dimension_consumed(uint32_t /*slot_index*/, uint32_t /*reader_id*/)
627{
628 m_consumed_readers.fetch_add(1, std::memory_order_release);
629}
630
632{
633 return m_consumed_readers.load(std::memory_order_acquire)
634 >= m_registered_readers.load(std::memory_order_acquire);
635}
636
637// =========================================================================
638// Data access
639// =========================================================================
640
641std::vector<DataVariant>& WindowContainer::get_processed_data()
642{
643 return m_processed_data;
644}
645
646const std::vector<DataVariant>& WindowContainer::get_processed_data() const
647{
648 return m_processed_data;
649}
650
651const std::vector<DataVariant>& WindowContainer::get_data()
652{
653 return m_data;
654}
655
657{
659 "WindowContainer::channel_data — not meaningful for interleaved image data; returning full surface");
661}
662
667
669{
671}
672
674{
675 return m_structure.get_height();
676}
677
678std::span<const double> WindowContainer::get_frame(uint64_t frame_index) const
679{
680 std::shared_lock lock(m_data_mutex);
681
682 const uint64_t h = m_structure.get_height();
683 if (frame_index >= h || m_processed_data.empty())
684 return {};
685
686 const auto* pixels = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
687 if (!pixels || pixels->empty())
688 return {};
689
690 const uint64_t w = m_structure.get_width();
691 const uint64_t c = m_structure.get_channel_count();
692 const uint64_t row_elems = w * c;
693 const uint64_t offset = frame_index * row_elems;
694
695 if (offset + row_elems > pixels->size())
696 return {};
697
698 auto& cache = m_frame_cache;
699 cache.resize(row_elems);
700 for (uint64_t i = 0; i < row_elems; ++i)
701 cache[i] = static_cast<double>((*pixels)[offset + i]) / 255.0;
702
703 return { cache.data(), cache.size() };
704}
705
706void WindowContainer::get_frames(std::span<double> output, uint64_t start_frame, uint64_t num_frames) const
707{
708 std::shared_lock lock(m_data_mutex);
709
710 const uint64_t h = m_structure.get_height();
711 if (start_frame >= h || output.empty() || m_processed_data.empty()) {
712 std::ranges::fill(output, 0.0);
713 return;
714 }
715
716 const auto* pixels = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
717 if (!pixels || pixels->empty()) {
718 std::ranges::fill(output, 0.0);
719 return;
720 }
721
722 const uint64_t w = m_structure.get_width();
723 const uint64_t c = m_structure.get_channel_count();
724 const uint64_t row_elems = w * c;
725 const uint64_t frames_to_copy = std::min(num_frames, h - start_frame);
726 const uint64_t elems_to_copy = std::min(frames_to_copy * row_elems,
727 static_cast<uint64_t>(output.size()));
728
729 const uint64_t src_offset = start_frame * row_elems;
730 for (uint64_t i = 0; i < elems_to_copy; ++i)
731 output[i] = static_cast<double>((*pixels)[src_offset + i]) / 255.0;
732
733 if (elems_to_copy < output.size())
734 std::fill(output.begin() + elems_to_copy, output.end(), 0.0);
735}
736
737} // namespace MayaFlux::Kakshya
#define MF_INFO(comp, ctx,...)
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
const std::vector< float > * pixels
Definition Decoder.cpp:58
uint32_t h
Definition InkPress.cpp:28
Type-erased accessor for NDData with semantic view construction.
uint64_t coordinates_to_linear_index(const std::vector< uint64_t > &coordinates) const override
Convert coordinates to linear index based on current memory layout.
ProcessingState get_processing_state() const override
Get the current processing state of the container.
std::atomic< uint32_t > m_registered_readers
std::function< void(const std::shared_ptr< SignalSourceContainer > &, ProcessingState)> m_state_callback
std::atomic< ProcessingState > m_processing_state
void set_processing_chain(const std::shared_ptr< DataProcessingChain > &chain) override
Set the processing chain for this container.
void create_default_processor() override
Create and configure a default processor for this container.
DataAccess channel_data(size_t channel_index) override
Get channel data with semantic interpretation.
bool is_region_loaded(const Region &region) const override
Always returns true.
std::span< const double > get_frame(uint64_t frame_index) const override
Get a single frame of data efficiently.
Portal::Graphics::ImageFormat get_image_format() const
Portal ImageFormat corresponding to the live swapchain surface format.
void set_memory_layout(MemoryLayout layout) override
Set the memory layout for this container.
void unregister_dimension_reader(uint32_t dimension_index) override
Unregister a reader for a specific dimension.
std::shared_ptr< Core::VKImage > to_image() const
Upload the full surface readback to a new VKImage.
WindowContainer(std::shared_ptr< Core::Window > window, uint32_t frame_capacity=60)
Construct from an existing managed window.
std::shared_ptr< Core::VKImage > image_at(uint32_t frame_index) const
Upload m_data[frame_index] to a new VKImage.
void clear() override
Clear all data in the container.
void unregister_state_change_callback() override
Unregister the state change callback, if any.
std::shared_ptr< Core::Window > m_window
uint64_t get_total_elements() const override
Get the total number of elements in the container.
const void * get_raw_data() const override
Get a raw pointer to the underlying data storage.
std::shared_ptr< Core::VKImage > region_to_image(const Region &region) const
Crop a region from the last readback and upload it as a VKImage.
std::vector< DataDimension > get_dimensions() const override
Get the dimensions describing the structure of the data.
std::atomic< uint32_t > m_consumed_readers
const std::vector< DataVariant > & get_data() override
Get a reference to the raw data stored in the container.
void load_region(const Region &region) override
No-op.
void lock() override
Acquire a lock for thread-safe access.
std::vector< DataVariant > m_processed_data
uint64_t get_num_frames() const override
Get the number of frames in the primary (temporal) dimension.
const RegionGroup & get_region_group(const std::string &name) const override
Get a region group by name.
std::unordered_map< std::string, RegionGroup > m_region_groups
void mark_dimension_consumed(uint32_t dimension_index, uint32_t reader_id) override
Mark a dimension as consumed for the current processing cycle.
uint8_t * mutable_frame_ptr(uint32_t frame_index)
Mutable pointer into m_data[frame_index] for the processor to write into.
uint32_t register_dimension_reader(uint32_t dimension_index) override
Register a reader for a specific dimension.
std::unordered_map< std::string, RegionGroup > get_all_region_groups() const override
Get all region groups in the container.
void unlock() override
Release a previously acquired lock.
std::vector< DataVariant > m_data
void update_processing_state(ProcessingState new_state) override
Update the processing state of the container.
void mark_ready_for_processing(bool ready) override
Mark the container as ready or not ready for processing.
std::vector< DataVariant > get_region_group_data(const RegionGroup &group) const override
Get data for multiple regions efficiently.
std::shared_ptr< DataProcessingChain > m_processing_chain
std::shared_ptr< DataProcessor > m_default_processor
uint64_t get_frame_size() const override
Get the number of elements that constitute one "frame".
std::atomic< uint64_t > m_frames_written
bool has_data() const override
Check if the container currently holds any data.
void remove_region_group(const std::string &name) override
Remove a region group by name.
void set_default_processor(const std::shared_ptr< DataProcessor > &processor) override
Set the default data processor for this container.
MemoryLayout get_memory_layout() const override
Get the memory layout used by this container.
bool has_active_readers() const override
Check if any dimensions currently have active readers.
std::vector< DataVariant > get_segments_data(const std::vector< RegionSegment > &segments) const override
Get data for multiple region segments efficiently.
std::vector< DataVariant > get_region_data(const Region &region) const override
Extract data for all regions across all region groups that spatially intersect region.
void set_region_data(const Region &region, const std::vector< DataVariant > &data) override
Set data for a specific region.
std::shared_ptr< DataProcessor > get_default_processor() const override
Get the current default data processor.
void unload_region(const Region &region) override
No-op.
std::vector< DataAccess > all_channel_data() override
Get all channel data as accessors.
bool all_dimensions_consumed() const override
Check if all active dimensions have been consumed in this cycle.
double get_value_at(const std::vector< uint64_t > &coordinates) const override
Get a single value at the specified coordinates.
void get_frames(std::span< double > output, uint64_t start_frame, uint64_t num_frames) const override
Get multiple frames efficiently.
std::vector< DataVariant > & get_processed_data() override
Get a mutable reference to the processed data buffer.
void register_state_change_callback(std::function< void(const std::shared_ptr< SignalSourceContainer > &, ProcessingState)> callback) override
Register a callback to be invoked on processing state changes.
std::shared_ptr< DataProcessingChain > get_processing_chain() override
Get the current processing chain for this container.
void process_default() override
Process the container's data using the default processor.
void advance_write_head()
Advance the write head index, wrapping around frame_capacity.
bool is_ready_for_processing() const override
Check if the container is ready for processing.
void set_value_at(const std::vector< uint64_t > &coordinates, double value) override
Set a single value at the specified coordinates.
std::vector< uint64_t > linear_index_to_coordinates(uint64_t linear_index) const override
Convert linear index to coordinates based on current memory layout.
bool try_lock() override
Attempt to acquire a lock without blocking.
std::atomic< uint32_t > m_next_reader_id
void add_region_group(const RegionGroup &group) override
Add a named group of regions to the container.
std::shared_ptr< Core::VKImage > create_2d(uint32_t width, uint32_t height, ImageFormat format=ImageFormat::RGBA8, const void *data=nullptr, uint32_t mip_levels=1)
Create a 2D texture.
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
ProcessingState
Represents the current processing lifecycle state of a container.
@ IDLE
Container is inactive with no data or not ready for processing.
uint64_t coordinates_to_linear(const std::vector< uint64_t > &coords, const std::vector< DataDimension > &dimensions)
Convert N-dimensional coordinates to a linear index for interleaved data.
Definition CoordUtils.cpp:8
@ VIDEO_COLOR
4D video (time + 2D + color)
@ IMAGE_COLOR
2D RGB/RGBA image
std::vector< uint64_t > linear_to_coordinates(uint64_t index, const std::vector< DataDimension > &dimensions)
Convert a linear index to N-dimensional coordinates for interleaved data.
MemoryLayout
Memory layout for multi-dimensional data.
Definition NDData.hpp:39
@ ROW_MAJOR
C/C++ style (last dimension varies fastest)
bool regions_intersect(const Region &r1, const Region &r2) noexcept
Test whether two N-dimensional regions overlap on every shared axis.
Core::GraphicsSurfaceInfo::SurfaceFormat query_surface_format(const std::shared_ptr< Core::Window > &window)
Query the actual vk::Format in use by the window's live swapchain, translated back to the MayaFlux su...
ImageFormat
User-friendly image format enum.
SurfaceFormat
Default pixel format for window surfaces (Vulkan-compatible)
static uint64_t get_height(const std::vector< DataDimension > &dimensions)
Extract height from image/video dimensions.
static uint64_t get_channel_count(const std::vector< DataDimension > &dimensions)
Extract channel count from dimensions.
static size_t get_frame_size(const std::vector< DataDimension > &dimensions)
Extract the size of non time dimensions (channel, spatial, frequency)
static ContainerDataStructure image_interleaved()
Create structure for interleaved image data.
static uint64_t get_total_elements(const std::vector< DataDimension > &dimensions)
Get total elements across all dimensions.
static uint64_t get_width(const std::vector< DataDimension > &dimensions)
Extract width from image/video dimensions.
static std::vector< DataDimension > create_dimensions(DataModality modality, const std::vector< uint64_t > &shape, MemoryLayout layout=MemoryLayout::ROW_MAJOR)
Create dimension descriptors for a data modality.
Definition NDData.cpp:108
std::string name
Descriptive name of the group.
Organizes related signal regions into a categorized collection.
std::vector< uint64_t > end_coordinates
Ending frame index (inclusive)
Definition Region.hpp:78
std::vector< uint64_t > start_coordinates
Starting frame index (inclusive)
Definition Region.hpp:75
Represents a point or span in N-dimensional space.
Definition Region.hpp:73