16using Portal::Graphics::TextureLoom;
20 std::vector<std::atomic<bool>> extended(
const std::vector<std::atomic<bool>>& flags,
bool value)
22 std::vector<std::atomic<bool>>
out(flags.size() + 1);
23 for (
size_t i = 0; i < flags.size(); ++i)
24 out[i].
store(flags[i].load(std::memory_order_acquire), std::memory_order_relaxed);
25 out.back().store(
value, std::memory_order_relaxed);
47 m_chain = std::make_shared<DataProcessingChain>();
50 for (uint32_t i = 0; i < layers.
value; ++i) {
60 flag.store(
true, std::memory_order_relaxed);
64 flag.store(
false, std::memory_order_relaxed);
72 "TextureContainer created: {}x{} layers={} fmt={} bpp={}",
91 const auto n =
static_cast<uint64_t
>(
m_data.size());
110 const auto layer =
static_cast<uint32_t
>(
m_data.size());
122 .image = std::move(
image),
142 if (layer >=
m_data.size())
148 m_cpu_stale[layer].store(
true, std::memory_order_release);
160 std::shared_ptr<Core::VKImage>
image;
169 if (!
m_cpu_stale[layer].load(std::memory_order_acquire))
178 "TextureContainer: GPU-held layer {} could not be downloaded", layer);
181 m_cpu_stale[layer].store(
false, std::memory_order_release);
187 for (uint32_t i = 0; i < static_cast<uint32_t>(
m_data.size()); ++i)
200 m_cpu_stale[layer].store(
false, std::memory_order_release);
211 "TextureContainer::from_image called with uninitialised image");
215 if (layer >=
m_data.size()) {
217 "TextureContainer::from_image layer {} out of range ({})", layer,
m_data.size());
228 if (!
ptr || bytes != sz) {
230 "TextureContainer::from_image variant size mismatch ({} vs {})", bytes, sz);
234 m_cpu_stale[layer].store(
false, std::memory_order_release);
242 const std::shared_ptr<Core::VKImage>&
image,
243 const std::shared_ptr<Buffers::VKBuffer>& staging,
248 "TextureContainer::from_image(staging) called with uninitialised image");
252 if (layer >=
m_data.size()) {
254 "TextureContainer::from_image(staging) layer {} out of range ({})", layer,
m_data.size());
265 if (!
ptr || bytes != sz) {
267 "TextureContainer::from_image(staging) variant size mismatch ({} vs {})", bytes, sz);
271 m_cpu_stale[layer].store(
false, std::memory_order_release);
282 "TextureContainer::from_image_array called with uninitialised image");
286 const auto n =
static_cast<uint32_t
>(
m_data.size());
287 if (
image->get_array_layers() < n) {
289 "TextureContainer::from_image_array image has {} layers, container expects {}",
290 image->get_array_layers(), n);
295 std::vector<uint8_t> combined(layer_bytes * n);
299 for (uint32_t i = 0; i < n; ++i) {
303 if (
ptr && bytes == layer_bytes)
304 std::memcpy(
ptr, combined.data() + i * layer_bytes, layer_bytes);
305 m_cpu_stale[i].store(
false, std::memory_order_release);
314 const std::shared_ptr<Core::VKImage>&
image,
315 const std::shared_ptr<Buffers::VKBuffer>& staging)
319 "TextureContainer::from_image_array(staging) called with uninitialised image");
323 const auto n =
static_cast<uint32_t
>(
m_data.size());
324 if (
image->get_array_layers() < n) {
326 "TextureContainer::from_image_array(staging) image has {} layers, container expects {}",
327 image->get_array_layers(), n);
332 std::vector<uint8_t> combined(layer_bytes * n);
336 for (uint32_t i = 0; i < n; ++i) {
340 if (
ptr && bytes == layer_bytes)
341 std::memcpy(
ptr, combined.data() + i * layer_bytes, layer_bytes);
342 m_cpu_stale[i].store(
false, std::memory_order_release);
356 uint32_t layer,
const std::shared_ptr<Buffers::VKBuffer>& staging)
const
362 uint32_t layer,
const std::shared_ptr<Buffers::VKBuffer>& staging)
const
364 if (layer >=
m_data.size()) {
366 "TextureContainer::to_image layer {} out of range ({})", layer,
m_data.size());
370 if (
m_cpu_stale[layer].load(std::memory_order_acquire)) {
378 if (!
ptr || bytes != expected)
380 return {
ptr,
ptr + bytes };
385 "TextureContainer::to_image called on empty or invalid layer {}", layer);
403 const std::shared_ptr<Buffers::VKBuffer>& staging)
const
409 const std::shared_ptr<Buffers::VKBuffer>& staging)
const
411 const auto n =
static_cast<uint32_t
>(
m_data.size());
421 std::vector<uint8_t> combined(layer_bytes * n);
422 for (uint32_t i = 0; i < n; ++i) {
424 const bool copied = seqlock_read_void(
m_slot_locks[i], 8, [&] {
426 valid =
ptr && bytes == layer_bytes;
428 std::memcpy(combined.data() + i * layer_bytes,
ptr, layer_bytes);
430 if (!copied || !valid) {
432 "TextureContainer::to_image_array layer {} has invalid pixel data", i);
446 const std::shared_ptr<Core::VKImage>&
image,
448 const std::shared_ptr<Buffers::VKBuffer>& staging)
const
452 "TextureContainer::upload_image null image or layer {} out of range ({})", layer,
m_data.size());
458 bool uploaded =
false;
461 if (!
ptr || bytes == 0) {
463 "TextureContainer::upload_image called on empty/invalid buffer");
473 const std::shared_ptr<Core::VKImage>&
image,
474 const std::shared_ptr<Buffers::VKBuffer>& staging)
const
476 const auto n =
static_cast<uint32_t
>(
m_data.size());
477 if (!
image || n == 0)
486 std::vector<uint8_t> combined(layer_bytes * n);
487 for (uint32_t i = 0; i < n; ++i) {
488 const bool ok = seqlock_read_void(
m_slot_locks[i], 8, [&] {
490 if (!
ptr || bytes != layer_bytes) {
492 "TextureContainer::upload_image_array layer {} size mismatch", i);
495 std::memcpy(combined.data() + i * layer_bytes,
ptr, layer_bytes);
511 if (layer >=
m_data.size())
515 return ptr ? std::span<const uint8_t>(
ptr, bytes) : std::span<const uint8_t> {};
520 if (layer >=
m_data.size())
524 return ptr ? std::span<uint8_t>(
ptr, bytes) : std::span<uint8_t> {};
529 if (layer >=
m_data.size())
532 const auto* v = std::get_if<std::vector<uint8_t>>(&
m_data[layer]);
533 return v ? std::span<const uint8_t>(v->data(), v->size()) : std::span<const uint8_t> {};
538 if (layer >=
m_data.size())
541 const auto* v = std::get_if<std::vector<uint16_t>>(&
m_data[layer]);
542 return v ? std::span<const uint16_t>(v->data(), v->size()) : std::span<const uint16_t> {};
547 if (layer >=
m_data.size())
550 const auto* v = std::get_if<std::vector<float>>(&
m_data[layer]);
551 return v ? std::span<const float>(v->data(), v->size()) : std::span<const float> {};
556 if (layer >=
m_data.size()) {
558 "TextureContainer::set_pixels(u8) layer {} out of range", layer);
562 auto* buf = std::get_if<std::vector<uint8_t>>(&
m_data[layer]);
565 "TextureContainer::set_pixels(u8) called on non-uint8 format {}",
569 if (data.size() != buf->size()) {
571 "TextureContainer::set_pixels(u8) size mismatch: got {} expected {}",
572 data.size(), buf->size());
577 std::ranges::copy(data, buf->begin());
583 if (layer >=
m_data.size()) {
585 "TextureContainer::set_pixels(u16) layer {} out of range", layer);
589 auto* buf = std::get_if<std::vector<uint16_t>>(&
m_data[layer]);
592 "TextureContainer::set_pixels(u16) called on non-uint16 format {}",
596 if (data.size() != buf->size()) {
598 "TextureContainer::set_pixels(u16) size mismatch: got {} expected {}",
599 data.size(), buf->size());
604 std::ranges::copy(data, buf->begin());
610 if (layer >=
m_data.size()) {
612 "TextureContainer::set_pixels(f32) layer {} out of range", layer);
616 auto* buf = std::get_if<std::vector<float>>(&
m_data[layer]);
619 "TextureContainer::set_pixels(f32) called on non-float format {}",
623 if (data.size() != buf->size()) {
625 "TextureContainer::set_pixels(f32) size mismatch: got {} expected {}",
626 data.size(), buf->size());
631 std::ranges::copy(data, buf->begin());
637 if (layer >=
m_data.size())
645 std::span<const float> result;
699 if (layer >=
m_data.size())
704 std::optional<std::vector<DataVariant>> result;
707 [&](
const auto& vec) -> std::vector<DataVariant> {
708 using T =
typename std::decay_t<
decltype(vec)>::value_type;
709 if constexpr (std::is_same_v<T, uint8_t>
710 || std::is_same_v<T, uint16_t>
711 || std::is_same_v<T, float>) {
712 auto extracted = extract_region_data<T>(
713 std::span<const T>(vec.data(), vec.size()),
723 return result.value_or(std::vector<DataVariant> {});
727 const std::vector<RegionSegment>& )
const
731 std::vector<DataVariant>
out;
733 for (
size_t i = 0; i <
m_data.size(); ++i) {
742 const Region& region,
const std::vector<DataVariant>& data)
753 if (layer >=
m_data.size())
758 const size_t coord_offset = (
m_data.size() > 1) ? 1 : 0;
762 const uint64_t x1 = std::min(region.
end_coordinates[coord_offset + 1],
static_cast<uint64_t
>(
m_width - 1));
767 using T =
typename std::decay_t<
decltype(dst_vec)>::value_type;
768 if constexpr (std::is_same_v<T, uint8_t>
769 || std::is_same_v<T, uint16_t>
770 || std::is_same_v<T, float>) {
771 const auto*
src = std::get_if<std::vector<T>>(&data[0]);
772 if (!
src ||
src->empty()) {
774 "TextureContainer::set_region_data source variant does not match "
775 "container element type");
779 for (uint64_t y = y0; y <= y1 && src_idx <
src->size(); ++y) {
780 for (uint64_t x = x0; x <= x1 && src_idx <
src->size(); ++x) {
782 for (uint32_t c = 0; c <
m_channels && src_idx <
src->size(); ++c, ++src_idx) {
783 if (dst_idx + c < dst_vec.size())
784 dst_vec[dst_idx + c] = (*
src)[src_idx];
796 if (element_size == 1) {
797 return typeid(uint8_t);
799 if (element_size == 2) {
800 return typeid(uint16_t);
802 if (element_size == 4) {
803 return typeid(float);
806 return typeid(uint8_t);
823 for (
size_t i = 0; i <
m_data.size(); ++i) {
826 m_cpu_stale[i].store(
false, std::memory_order_release);
855 std::function<
void(
const std::shared_ptr<SignalSourceContainer>&,
ProcessingState)> cb)
898 static DataVariant empty = std::vector<uint8_t> {};
899 static std::vector<DataDimension> empty_dims;
909 std::vector<DataAccess> result;
925 std::optional<RegionGroup> result;
930 return result.value_or(empty);
935 std::optional<std::unordered_map<std::string, RegionGroup>> result;
939 return result.value_or(std::unordered_map<std::string, RegionGroup> {});
956 return (
ptr && bytes > 0) ?
static_cast<const void*
>(
ptr) :
nullptr;
965 if (
m_cpu_stale[0].load(std::memory_order_acquire))
969 return ptr && bytes > 0;
975 m_chain = std::make_shared<DataProcessingChain>();
983 uint64_t start_frame,
985 const std::type_info&
type)
const
992 if (frame_index >= m_data.size()) {
993 return { std::span<const uint8_t> {} };
996 ensure_cpu(
static_cast<uint32_t
>(frame_index));
998 const size_t layer_elems =
static_cast<size_t>(m_width) * m_height * m_channels;
1000 seqlock_read_void(m_slot_locks[frame_index], 8, [&] {
1003 using T =
typename std::decay_t<
decltype(vec)>::value_type;
1004 if constexpr (std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> || std::is_same_v<T, float>) {
1005 const size_t nn = std::min(layer_elems, vec.size());
1008 return { std::span<const uint8_t> {} };
1011 m_data[frame_index]);
1019 uint64_t start_frame,
1020 uint64_t num_frames,
1021 const std::type_info&
type)
const
1023 if (
type ==
typeid(uint8_t)) {
1024 get_frames_typed_as<uint8_t>(std::span<uint8_t>(
static_cast<uint8_t*
>(output),
count), start_frame, num_frames);
1027 if (
type ==
typeid(uint16_t)) {
1028 get_frames_typed_as<uint16_t>(std::span<uint16_t>(
static_cast<uint16_t*
>(output),
count), start_frame, num_frames);
1031 if (
type ==
typeid(
float)) {
1032 get_frames_typed_as<float>(std::span<float>(
static_cast<float*
>(output),
count), start_frame, num_frames);
1036 error<std::runtime_error>(
1039 std::source_location::current(),
1040 "TextureContainer supports only uint8_t, uint16_t, and float for typed frame extraction");
1043template <
typename T>
1046 if (frame_index >= m_data.size())
1049 ensure_cpu(
static_cast<uint32_t
>(frame_index));
1051 std::span<const T> result;
1052 seqlock_read_void(m_slot_locks[frame_index], 8, [&] {
1053 const auto* vec = std::get_if<std::vector<T>>(&m_data[frame_index]);
1054 if (!vec || vec->empty())
1056 const size_t layer_elems =
static_cast<size_t>(m_width) * m_height * m_channels;
1057 const size_t n = std::min(layer_elems, vec->size());
1058 result = std::span<const T>(vec->data(), n);
1064template <
typename T>
1070 for (uint64_t layer = start_frame;
1071 layer < start_frame + num_frames && layer <
m_data.size() && out_idx < output.size();
1075 const auto* vec = std::get_if<std::vector<T>>(&
m_data[layer]);
1076 if (!vec || vec->empty())
1078 const size_t copy_n = std::min(layer_elems, std::min(vec->size(), output.size() - out_idx));
1079 std::copy_n(vec->begin(),
static_cast<std::ptrdiff_t
>(copy_n), output.begin() +
static_cast<std::ptrdiff_t
>(out_idx));
1084 if (out_idx < output.size()) {
1085 std::fill(output.begin() +
static_cast<std::ptrdiff_t
>(out_idx), output.end(), T {});
1090 const std::vector<uint64_t>&
coords,
1092 const std::type_info&
type)
const
1097 const size_t layer = (
m_data.size() > 1) ?
static_cast<size_t>(
coords[0]) : 0;
1103 const size_t co = (
m_data.size() > 1) ? 1 : 0;
1107 std::visit([&](
const auto& vec) {
1108 using T =
typename std::decay_t<
decltype(vec)>::value_type;
1109 if (
type !=
typeid(T) || idx >= vec.size())
1111 *
static_cast<T*
>(
out) = vec[idx];
1118 const std::vector<uint64_t>&
coords,
1120 const std::type_info&
type)
1125 const size_t layer = (
m_data.size() > 1) ?
static_cast<size_t>(
coords[0]) : 0;
1131 const size_t co = (
m_data.size() > 1) ? 1 : 0;
1135 std::visit([&](
auto& vec) {
1136 using T =
typename std::decay_t<
decltype(vec)>::value_type;
1137 if (
type !=
typeid(T) || idx >= vec.size())
1139 vec[idx] = *
static_cast<const T*
>(in);
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
const std::vector< float > * pixels
std::vector< float > * out
std::vector< glm::ivec3 > coords
vk::PhysicalDeviceType type
Type-erased accessor for NDData with semantic view construction.
auto get_frame_typed_as(uint64_t frame_index) const -> std::span< const T >
std::span< const uint8_t > as_uint8(uint32_t layer=0) const
Typed view over the uint8 variant.
auto get_frame_typed(uint64_t frame_index) const -> DataSpanVariant
std::atomic< ProcessingState > m_processing_state
void register_state_change_callback(std::function< void(const std::shared_ptr< SignalSourceContainer > &, ProcessingState)> cb) override
Register a callback to be invoked on processing state changes.
TextureContainer(uint32_t width, uint32_t height, ImageFormat format, uint32_t layers=1)
Construct an empty container with declared dimensions.
std::vector< std::atomic< bool > > m_normalised_dirty
std::shared_ptr< Core::VKImage > to_image(uint32_t layer=0) const
Refresh the container-owned VKImage for one layer.
std::unordered_map< std::string, RegionGroup > m_region_groups
void set_pixels(std::span< const uint8_t > data, uint32_t layer=0)
Replace the layer's pixel buffer with a byte source.
void hold_layer(uint32_t layer)
Mark layer as held on the GPU after its image was rewritten.
void mark_ready_for_processing(bool ready) override
Mark the container as ready or not ready for processing.
std::vector< DataAccess > all_channel_data() override
Get all channel data as accessors.
std::shared_ptr< Core::VKImage > cached_array_image(const std::shared_ptr< Buffers::VKBuffer > &staging) const
std::vector< DataVariant > get_region_data(const Region ®ion) const override
Get data for a specific region.
void unregister_state_change_callback() override
Unregister the state change callback, if any.
ProcessingState get_processing_state() const override
Get the current processing state of the container.
void get_frames_typed_as(std::span< T > output, uint64_t start_frame, uint64_t num_frames) const
DataAccess channel_data(size_t channel_index) override
Get channel data with semantic interpretation.
std::shared_ptr< DataProcessingChain > get_processing_chain() override
Get the current processing chain for this container.
Memory::SeqlockArray m_slot_locks
std::span< const float > as_normalised_float(uint32_t layer=0) const
Layer pixel data as a normalised float span.
void claim_cpu(uint32_t layer)
Give a GPU-held layer fresh CPU storage before a full overwrite.
uint64_t get_frame_size() const override
Get the number of elements that constitute one "frame".
std::vector< std::atomic< bool > > m_cpu_stale
Per layer: the GPU image in m_layer_image_cache holds the content, m_data does not.
std::atomic< bool > m_ready_for_processing
uint32_t append_image_layer(std::shared_ptr< Core::VKImage > image)
Append one layer held on the GPU by image.
void update_processing_state(ProcessingState state) override
Update the processing state of the container.
void get_frames_impl(void *output, size_t count, uint64_t start_frame, uint64_t num_frames, const std::type_info &type) const override
Implementation-specific method to retrieve multiple frames.
uint64_t coordinates_to_linear_index(const std::vector< uint64_t > &coords) const override
Convert coordinates to linear index based on current memory layout.
void from_image_array(const std::shared_ptr< Core::VKImage > &image)
Download each array layer of a Vulkan 2D array image into the corresponding layer slot.
std::function< void(const std::shared_ptr< SignalSourceContainer > &, ProcessingState)> m_state_cb
std::shared_ptr< Core::VKImage > to_image_array() const
Upload all layers as a Vulkan 2D array texture.
std::vector< DataVariant > m_processed_data
std::vector< DataVariant > get_segments_data(const std::vector< RegionSegment > &segments) const override
Get data for multiple region segments efficiently.
uint64_t get_num_frames() const override
Get the number of frames in the primary (temporal) dimension.
Memory::Seqlock m_region_lock
std::unordered_map< std::string, RegionGroup > get_all_region_groups() const override
Get all region groups in the container.
std::shared_ptr< Core::VKImage > layer_image(uint32_t layer) const
The GPU image backing layer, without uploading CPU pixels.
void set_memory_layout(MemoryLayout layout) override
Set the memory layout for this container.
std::span< const uint8_t > pixel_bytes(uint32_t layer=0) const
Read-only byte-level view over the pixel buffer.
std::shared_ptr< DataProcessingChain > m_chain
std::vector< DataDimension > get_dimensions() const override
Get the dimensions describing the structure of the data.
uint64_t get_total_elements() const override
Get the total number of elements in the container.
bool upload_image(const std::shared_ptr< Core::VKImage > &image, uint32_t layer, const std::shared_ptr< Buffers::VKBuffer > &staging) const
Upload one layer into an existing VKImage instead of creating one.
void set_value_impl(const std::vector< uint64_t > &coords, const void *in, const std::type_info &type) override
Type-erased single-element write.
void get_frames_typed(void *output, size_t count, uint64_t start_frame, uint64_t num_frames, const std::type_info &type) const
const void * get_raw_data() const override
Get a raw pointer to the underlying data storage.
RegionGroup get_region_group(const std::string &name) const override
Get a region group by name.
std::shared_ptr< Core::VKImage > cached_layer_image(uint32_t layer, const std::shared_ptr< Buffers::VKBuffer > &staging) const
void get_value_impl(const std::vector< uint64_t > &coords, void *out, const std::type_info &type) const override
Type-erased single-element read.
std::vector< Portal::Graphics::ImageCacheEntry > m_layer_image_cache
bool is_ready_for_processing() const override
Check if the container is ready for processing.
std::span< const float > as_float(uint32_t layer=0) const
Typed view over the float variant.
void clear() override
Clear all data in the container.
std::span< const uint16_t > as_uint16(uint32_t layer=0) const
Typed view over the uint16 variant.
ContainerDataStructure m_structure
void set_region_data(const Region ®ion, const std::vector< DataVariant > &data) override
Write DataVariant bytes into the pixel buffer at the region bounds.
void add_region_group(const RegionGroup &group) override
Add a named group of regions to the container.
std::vector< DataVariant > m_data
std::vector< uint64_t > linear_index_to_coordinates(uint64_t index) const override
Convert linear index to coordinates based on current memory layout.
const std::vector< DataVariant > & get_data() override
Get a reference to the raw data stored in the container.
Memory::Seqlock m_cb_lock
std::vector< std::vector< float > > m_normalised_cache
void ensure_cpu(uint32_t layer) const
Download a GPU-held layer into m_data before a CPU read.
bool upload_image_array(const std::shared_ptr< Core::VKImage > &image, const std::shared_ptr< Buffers::VKBuffer > &staging) const
Upload all layers into an existing VKImage instead of creating one.
void ensure_cpu_all() const
std::type_index value_element_type() const override
Runtime query for the native scalar element type of this container.
std::vector< DataVariant > & get_processed_data() override
Get a mutable reference to the processed data buffer.
size_t byte_size() const
Total byte count of the pixel buffer.
Memory::Seqlock m_image_cache_lock
MemoryLayout get_memory_layout() const override
Get the memory layout used by this container.
void from_image(const std::shared_ptr< Core::VKImage > &image, uint32_t layer=0)
Download pixel data from a VKImage into this container.
Portal::Graphics::ImageCacheEntry m_array_image_cache
void remove_region_group(const std::string &name) override
Remove a region group by name.
bool has_data() const override
Check if the container currently holds any data.
SignalSourceContainer wrapping GPU texture data as addressable pixel bytes.
void resize(size_t n)
Replace the slot array with n default-constructed Seqlock instances.
void extend(size_t n)
Add n default-constructed Seqlock instances after the existing slots.
RAII guard that brackets a Seqlock write region.
Scope guard for a serialized Seqlock write.
void download_data(const std::shared_ptr< Core::VKImage > &image, void *data, size_t size, const std::shared_ptr< Buffers::VKBuffer > &staging, bool deferred=false, vk::ImageLayout restore_layout=vk::ImageLayout::eShaderReadOnlyOptimal, vk::PipelineStageFlags restore_stage=vk::PipelineStageFlagBits::eFragmentShader)
Download pixel data from a VKImage, reusing a caller-supplied persistent staging buffer.
std::shared_ptr< Core::VKImage > refresh_cached_image(ImageCacheEntry &entry, const ImageKey &key, std::span< const uint8_t > pixels, const std::shared_ptr< Buffers::VKBuffer > &staging={})
Refresh a sampled image in an owner-held cache entry.
void upload_data(const std::shared_ptr< Core::VKImage > &image, const void *data, size_t size)
Upload pixel data to an existing texture.
static TextureLoom & instance()
Portal-level texture creation and management.
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
ProcessingState
Represents the current processing lifecycle state of a container.
@ READY
Container has data loaded and is ready for processing.
@ IDLE
Container is inactive with no data or not ready for processing.
ImageFormat
User-friendly image format enum.
DataVariant make_empty_storage(ImageFormat format, size_t element_count)
Allocate a zeroed DataVariant of the alternative backing a format.
typename detail::span_const_from_vector_variant< DataVariant >::type DataSpanVariant
std::span< const float > as_normalised_float(const DataVariant &variant, std::vector< float > &storage)
Extract a DataVariant holding pixel data as a normalised float span.
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.
std::pair< const uint8_t *, size_t > variant_bytes(const DataVariant &v)
Get a pointer to the raw bytes of a DataVariant and its size.
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.
@ IMAGE_COLOR_ARRAY
4D (idx + 2D + color)
@ IMAGE_COLOR
2D RGB/RGBA image
size_t storage_element_size(ImageFormat format)
Byte width of the DataVariant element backing a given ImageFormat.
MemoryLayout
Memory layout for multi-dimensional data.
@ ROW_MAJOR
C/C++ style (last dimension varies fastest)
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.
std::pair< uint8_t *, size_t > variant_bytes_mutable(DataVariant &v)
Get a mutable pointer to the raw bytes of a DataVariant and its size.
std::shared_ptr< T > store(std::shared_ptr< T > obj)
Transfer ownership of an existing object to the persistent store for process lifetime.
std::vector< DataDimension > 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.
MemoryLayout memory_layout
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.
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)
std::vector< uint64_t > start_coordinates
Starting frame index (inclusive)
Represents a point or span in N-dimensional space.
Exact layer count for subclasses, zero allowed.
Immutable properties that determine whether an image can be reused.