MayaFlux 0.2.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
11namespace MayaFlux::Kakshya {
12
13WindowContainer::WindowContainer(std::shared_ptr<Core::Window> window)
14 : m_window(std::move(window))
15{
16 if (!m_window) {
17 error<std::invalid_argument>(
20 std::source_location::current(),
21 "WindowContainer requires a valid window");
22 }
23
26
28 "WindowContainer created for window '{}' ({}x{})",
29 m_window->get_create_info().title,
31}
32
33// =========================================================================
34// Setup
35// =========================================================================
36
38{
39 const auto& fmt = m_window->get_create_info().container_format;
40 const uint32_t w = m_window->get_create_info().width;
41 const uint32_t h = m_window->get_create_info().height;
42 const uint32_t c = fmt.color_channels;
43
47 { static_cast<uint64_t>(h), static_cast<uint64_t>(w), static_cast<uint64_t>(c) },
49
50 const size_t sz = static_cast<size_t>(w) * h * c;
51 m_processed_data.resize(1);
52 m_processed_data[0] = std::vector<uint8_t>(sz, 0U);
53}
54
55// =========================================================================
56// NDDimensionalContainer
57// =========================================================================
58
59std::vector<DataDimension> WindowContainer::get_dimensions() const
60{
62}
63
68
73
78
79std::vector<DataVariant> WindowContainer::get_region_data(const Region& region) const
80{
81 std::shared_lock lock(m_data_mutex);
82
83 if (m_processed_data.empty())
84 return {};
85
86 const auto* src = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
87 if (!src || src->empty())
88 return {};
89
90 const auto& dims = m_structure.dimensions;
91 const std::span<const uint8_t> src_span { src->data(), src->size() };
92
93 std::vector<DataVariant> result;
94
95 for (const auto& [name, group] : m_region_groups) {
96 for (const auto& r : group.regions) {
97 if (!regions_intersect(r, region))
98 continue;
99 try {
100 result.emplace_back(extract_nd_region<uint8_t>(src_span, r, dims));
101 } catch (const std::exception& e) {
103 "WindowContainer::get_region_data extraction failed — {}", e.what());
104 }
105 }
106 }
107
108 return result;
109}
110
111void WindowContainer::set_region_data(const Region& /*region*/, const std::vector<DataVariant>& /*data*/)
112{
114 "WindowContainer::set_region_data — write path not yet implemented");
115}
116
117std::vector<DataVariant> WindowContainer::get_region_group_data(const RegionGroup& /*group*/) const
118{
119 std::shared_lock lock(m_data_mutex);
120 return m_processed_data;
121}
122
123std::vector<DataVariant> WindowContainer::get_segments_data(const std::vector<RegionSegment>& /*segments*/) const
124{
125 std::shared_lock lock(m_data_mutex);
126 return m_processed_data;
127}
128
129double WindowContainer::get_value_at(const std::vector<uint64_t>& coordinates) const
130{
131 if (coordinates.size() < 3 || m_processed_data.empty())
132 return 0.0;
133
134 const auto* pixels = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
135 if (!pixels)
136 return 0.0;
137
138 const uint64_t w = m_structure.get_width();
139 const uint64_t c = m_structure.get_channel_count();
140 const uint64_t idx = (coordinates[0] * w + coordinates[1]) * c + coordinates[2];
141
142 if (idx >= pixels->size())
143 return 0.0;
144
145 return static_cast<double>((*pixels)[idx]) / 255.0;
146}
147
148void WindowContainer::set_value_at(const std::vector<uint64_t>& /*coords*/, double /*value*/) { }
149
150uint64_t WindowContainer::coordinates_to_linear_index(const std::vector<uint64_t>& coordinates) const
151{
152 return coordinates_to_linear(coordinates, m_structure.dimensions);
153}
154
155std::vector<uint64_t> WindowContainer::linear_index_to_coordinates(uint64_t index) const
156{
158}
159
161{
162 std::unique_lock lock(m_data_mutex);
163 const size_t sz = m_structure.get_total_elements();
164 m_processed_data.resize(1);
165 m_processed_data[0] = std::vector<uint8_t>(sz, 0U);
167}
168
171bool WindowContainer::try_lock() { return m_data_mutex.try_lock(); }
172
174{
175 if (m_processed_data.empty())
176 return nullptr;
177 const auto* v = std::get_if<std::vector<uint8_t>>(&m_processed_data[0]);
178 return (v && !v->empty()) ? v->data() : nullptr;
179}
180
182{
183 std::shared_lock lock(m_data_mutex);
184 if (m_processed_data.empty())
185 return false;
186 return std::visit([](const auto& v) { return !v.empty(); }, m_processed_data[0]);
187}
188
190{
192 "WindowContainer::load_region — no-op. Register regions via add_region_group()");
193}
194
196{
198 "WindowContainer::unload_region — no-op. Remove regions via remove_region_group()");
199}
200
201bool WindowContainer::is_region_loaded(const Region& /*region*/) const
202{
203 return true;
204}
205
206// =========================================================================
207// RegionGroup management
208// =========================================================================
209
211{
212 std::lock_guard lock(m_state_mutex);
213 m_region_groups[group.name] = group;
214}
215
216const RegionGroup& WindowContainer::get_region_group(const std::string& name) const
217{
218 static const RegionGroup empty;
219 std::shared_lock lock(m_data_mutex);
220 auto it = m_region_groups.find(name);
221 return it != m_region_groups.end() ? it->second : empty;
222}
223
224std::unordered_map<std::string, RegionGroup> WindowContainer::get_all_region_groups() const
225{
226 std::shared_lock lock(m_data_mutex);
227 return m_region_groups;
228}
229
230void WindowContainer::remove_region_group(const std::string& name)
231{
232 std::lock_guard lock(m_state_mutex);
233 m_region_groups.erase(name);
234}
235
236// =========================================================================
237// SignalSourceContainer
238// =========================================================================
239
244
246{
247 ProcessingState old = m_processing_state.exchange(new_state);
248 if (old == new_state)
249 return;
250
251 std::lock_guard lock(m_state_mutex);
253 m_state_callback(shared_from_this(), new_state);
254}
255
257 std::function<void(const std::shared_ptr<SignalSourceContainer>&, ProcessingState)> callback)
258{
259 std::lock_guard lock(m_state_mutex);
260 m_state_callback = std::move(callback);
261}
262
264{
265 std::lock_guard lock(m_state_mutex);
266 m_state_callback = nullptr;
267}
268
270{
271 return m_ready_for_processing.load(std::memory_order_acquire);
272}
273
275{
276 m_ready_for_processing.store(ready, std::memory_order_release);
277}
278
280{
281 auto readback = std::make_shared<WindowAccessProcessor>();
282 readback->on_attach(shared_from_this());
283 m_default_processor = readback;
284}
285
287{
289 m_default_processor->process(shared_from_this());
290}
291
292void WindowContainer::set_default_processor(const std::shared_ptr<DataProcessor>& proc)
293{
295 m_default_processor->on_detach(shared_from_this());
296 m_default_processor = proc;
298 m_default_processor->on_attach(shared_from_this());
299}
300
301std::shared_ptr<DataProcessor> WindowContainer::get_default_processor() const
302{
303 return m_default_processor;
304}
305
306std::shared_ptr<DataProcessingChain> WindowContainer::get_processing_chain()
307{
308 return m_processing_chain;
309}
310
311void WindowContainer::set_processing_chain(const std::shared_ptr<DataProcessingChain>& chain)
312{
313 m_processing_chain = chain;
314}
315
316// =========================================================================
317// Consumer tracking
318// =========================================================================
319
320uint32_t WindowContainer::register_dimension_reader(uint32_t /*slot_index*/)
321{
323 return m_next_reader_id.fetch_add(1, std::memory_order_relaxed);
324}
325
327{
328 if (m_registered_readers.load(std::memory_order_relaxed) > 0)
330}
331
333{
334 return m_registered_readers.load(std::memory_order_acquire) > 0;
335}
336
337void WindowContainer::mark_dimension_consumed(uint32_t /*slot_index*/, uint32_t /*reader_id*/)
338{
339 m_consumed_readers.fetch_add(1, std::memory_order_release);
340}
341
343{
344 return m_consumed_readers.load(std::memory_order_acquire)
345 >= m_registered_readers.load(std::memory_order_acquire);
346}
347
348// =========================================================================
349// Data access
350// =========================================================================
351
352std::vector<DataVariant>& WindowContainer::get_processed_data()
353{
354 return m_processed_data;
355}
356
357const std::vector<DataVariant>& WindowContainer::get_processed_data() const
358{
359 return m_processed_data;
360}
361
362const std::vector<DataVariant>& WindowContainer::get_data()
363{
364 return m_data;
365}
366
368{
370 "WindowContainer::channel_data — not meaningful for interleaved image data; returning full surface");
372}
373
378
379} // namespace MayaFlux::Kakshya
#define MF_INFO(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
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.
void set_memory_layout(MemoryLayout layout) override
Set the memory layout for this container.
WindowContainer(std::shared_ptr< Core::Window > window)
Construct from an existing managed window.
void unregister_dimension_reader(uint32_t dimension_index) override
Unregister a reader for a specific dimension.
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::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
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.
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
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.
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.
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.
@ 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:6
@ 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:36
@ 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.
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 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.
Represents a point or span in N-dimensional space.
Definition Region.hpp:67