23 target->get_modality());
27 if (dst_offset + bytes > target->get_size_bytes()) {
28 error<std::runtime_error>(
31 std::source_location::current(),
32 "Upload data size {} at offset {} exceeds buffer capacity {}",
33 bytes, dst_offset, target->get_size_bytes());
36 auto& target_resources = target->get_buffer_resources();
37 void* mapped = target_resources.mapped_ptr;
39 error<std::runtime_error>(
42 std::source_location::current(),
43 "Host-visible buffer has no mapped pointer");
46 std::memcpy(
static_cast<uint8_t*
>(mapped) + dst_offset,
ptr, bytes);
48 target->mark_dirty_range(dst_offset, bytes);
53 if (!buffer_service) {
54 error<std::runtime_error>(
57 std::source_location::current(),
58 "upload_host_visible requires a valid buffer service");
61 auto dirty_ranges = target->get_and_clear_dirty_ranges();
63 buffer_service->flush_range(
64 target_resources.memory,
75 target->get_modality());
79 if (dst_offset + bytes > target->get_size_bytes()) {
80 error<std::runtime_error>(
83 std::source_location::current(),
84 "Upload data size {} at offset {} exceeds buffer capacity {}",
85 bytes, dst_offset, target->get_size_bytes());
88 auto& staging_resources = staging_buffer->get_buffer_resources();
90 void* staging_mapped = staging_resources.mapped_ptr;
91 if (!staging_mapped) {
92 error<std::runtime_error>(
95 std::source_location::current(),
96 "Staging buffer has no mapped pointer");
99 std::memcpy(staging_mapped,
ptr, bytes);
100 staging_buffer->mark_dirty_range(0, bytes);
105 if (!buffer_service) {
106 error<std::runtime_error>(
109 std::source_location::current(),
110 "upload_host_visible requires a valid buffer service");
113 auto dirty_ranges = staging_buffer->get_and_clear_dirty_ranges();
115 buffer_service->flush_range(
116 staging_resources.memory,
121 buffer_service->copy_buffer(
122 static_cast<void*
>(staging_buffer->get_buffer()),
123 static_cast<void*
>(target->get_buffer()),
124 bytes, 0, dst_offset);
131 std::shared_ptr<VKBuffer>& staging)
141 std::shared_ptr<VKBuffer>& staging)
143 if (!data ||
size == 0)
155 || !buffer_service->execute_fenced
156 || !buffer_service->wait_fenced
157 || !buffer_service->release_fenced
158 || !buffer_service->flush_range) {
159 error<std::runtime_error>(
162 std::source_location::current(),
163 "upload_back_buffer_async: BufferService unavailable");
166 if (!staging || staging->get_size_bytes() <
size)
169 void*
ptr = staging->get_mapped_ptr();
171 error<std::runtime_error>(
174 std::source_location::current(),
175 "upload_back_buffer_async: staging buffer has no mapped pointer");
180 auto& resources = staging->get_buffer_resources();
181 buffer_service->flush_range(resources.memory, 0,
size);
183 auto handle = buffer_service->copy_buffer_fenced(
184 static_cast<void*
>(staging->get_buffer()),
185 static_cast<void*
>(slot.
buffer),
189 error<std::runtime_error>(
192 std::source_location::current(),
193 "upload_back_buffer_async: copy_buffer_fenced returned null");
207 if (buffer_service && buffer_service->wait_fenced && buffer_service->release_fenced) {
209 buffer_service->release_fenced(handle);
217 auto& source_resources = source->get_buffer_resources();
218 void* mapped = source_resources.mapped_ptr;
220 error<std::runtime_error>(
223 std::source_location::current(),
224 "Host-visible buffer has no mapped pointer");
227 source->mark_invalid_range(0, source->get_size_bytes());
232 if (!buffer_service) {
233 error<std::runtime_error>(
236 std::source_location::current(),
237 "upload_host_visible requires a valid buffer service");
240 auto invalid_ranges = source->get_and_clear_invalid_ranges();
242 buffer_service->invalidate_range(
243 source_resources.memory,
248 std::vector<uint8_t> raw_bytes(source->get_size_bytes());
249 std::memcpy(raw_bytes.data(), mapped, source->get_size_bytes());
251 std::dynamic_pointer_cast<VKBuffer>(target)->set_data({ raw_bytes });
254void download_device_local(
const std::shared_ptr<VKBuffer>& source,
const std::shared_ptr<VKBuffer>& target,
const std::shared_ptr<VKBuffer>& staging_buffer)
259 if (!buffer_service) {
260 error<std::runtime_error>(
263 std::source_location::current(),
264 "download_device_local requires a valid buffer service");
267 buffer_service->copy_buffer(
268 static_cast<void*
>(source->get_buffer()),
269 static_cast<void*
>(staging_buffer->get_buffer()),
270 source->get_size_bytes(), 0, 0);
272 staging_buffer->mark_invalid_range(0, source->get_size_bytes());
274 auto& staging_resources = staging_buffer->get_buffer_resources();
275 auto invalid_ranges = staging_buffer->get_and_clear_invalid_ranges();
277 buffer_service->invalidate_range(
278 staging_resources.memory,
283 void* staging_mapped = staging_resources.mapped_ptr;
284 if (!staging_mapped) {
285 error<std::runtime_error>(
288 std::source_location::current(),
289 "Staging buffer has no mapped pointer");
292 std::vector<uint8_t> raw_bytes(source->get_size_bytes());
293 std::memcpy(raw_bytes.data(), staging_mapped, source->get_size_bytes());
295 std::dynamic_pointer_cast<VKBuffer>(target)->set_data({ raw_bytes });
301 std::shared_ptr<VKBuffer>& staging,
302 size_t staging_offset)
311 || !buffer_service->execute_fenced
312 || !buffer_service->wait_fenced
313 || !buffer_service->release_fenced
314 || !buffer_service->invalidate_range) {
315 error<std::runtime_error>(
318 std::source_location::current(),
319 "download_back_buffer_async: BufferService unavailable");
322 if (!staging || staging->get_size_bytes() < staging_offset +
size)
325 return buffer_service->copy_buffer_fenced(
326 static_cast<void*
>(slot.
buffer),
327 static_cast<void*
>(staging->get_buffer()),
328 size, 0, staging_offset);
336 std::shared_ptr<VKBuffer>& staging,
337 size_t staging_offset)
339 if (!data ||
size == 0)
354 auto& resources = staging->get_buffer_resources();
355 buffer_service->invalidate_range(resources.memory, staging_offset,
size);
357 const auto* base =
static_cast<const uint8_t*
>(staging->get_mapped_ptr());
358 std::memcpy(data, base + staging_offset,
size);
360 buffer_service->release_fenced(handle);
368 std::shared_ptr<VKBuffer>& staging)
382 &&
static_cast<bool>(
buffer->get_usage_flags() & vk::BufferUsageFlagBits::eTransferSrc);
391 const auto& resources =
buffer->get_buffer_resources();
393 .
buffer = resources.buffer,
394 .mapped_ptr = resources.mapped_ptr,
395 .size_bytes =
buffer->get_size_bytes(),
410 .size_bytes = size_bytes,
423 const std::shared_ptr<VKBuffer>& source)
425 if (!source || !source->is_initialized()) {
429 auto layout = source->get_vertex_layout();
430 if (!layout || layout->stride_bytes == 0 || layout->vertex_count == 0
431 || layout->vertex_count > source->get_size_bytes() / layout->stride_bytes) {
441 std::ranges::iota(
indices, 0U);
447 std::span<const uint32_t>(
indices),
449 auto access = ins.
build();
452 "triangle_soup_mesh: MeshInsertion::build() failed");
455 mesh_data.layout = access->layout;
461 const std::shared_ptr<ComputeMeshBuffer>&
buffer)
465 "download_compute_mesh: null buffer");
469 const auto vertex_count =
buffer->get_live_vertex_count();
472 "download_compute_mesh: no mesh processor (setup_processors() has not been called) "
473 "or the counter buffer is not host-visible or not allocated yet");
476 if (*vertex_count == 0) {
478 "download_compute_mesh: live vertex count is zero");
482 std::vector<uint8_t> bytes(
static_cast<size_t>(*vertex_count) *
sizeof(
Kakshya::MeshVertex));
483 std::shared_ptr<VKBuffer> staging;
491 auto buffer = std::make_shared<VKBuffer>(
493 VKBuffer::Usage::STAGING,
498 if (!buffer_service) {
499 error<std::runtime_error>(
502 std::source_location::current(),
503 "create_staging_buffer requires a valid buffer service");
506 buffer_service->initialize_buffer(
buffer);
513 auto buf = std::make_shared<VKBuffer>(
515 VKBuffer::Usage::STAGING,
521 if (!buffer_service) {
522 error<std::runtime_error>(
525 std::source_location::current(),
526 "create_image_staging_buffer requires a valid buffer service");
529 buffer_service->initialize_buffer(buf);
532 "create_image_staging_buffer: allocated {} bytes",
size);
538 const std::shared_ptr<VKBuffer>& target,
539 const std::shared_ptr<VKBuffer>& staging,
543 if (required <= target->get_size_bytes()) {
547 const auto new_size =
static_cast<size_t>(
static_cast<float>(required) * growth_factor);
549 target->resize(new_size,
false);
552 staging->resize(new_size,
false);
558 std::span<
const std::pair<size_t, size_t>> intervals,
559 const std::shared_ptr<VKBuffer>& target,
560 std::shared_ptr<VKBuffer>& staging)
563 error<std::invalid_argument>(
566 std::source_location::current(),
567 "upload_intervals: target buffer is null");
570 std::vector<std::pair<size_t, size_t>> pending;
571 pending.reserve(intervals.size());
572 for (
const auto& interval : intervals) {
573 if (interval.first < interval.second) {
574 pending.push_back(interval);
578 if (!base || pending.empty()) {
584 if (merged.back().second > target->get_size_bytes()) {
585 error<std::runtime_error>(
588 std::source_location::current(),
589 "upload_intervals: range end {} exceeds buffer capacity {}",
590 merged.back().second, target->get_size_bytes());
596 if (!buffer_service || !buffer_service->flush_range) {
597 error<std::runtime_error>(
600 std::source_location::current(),
601 "upload_intervals requires a valid buffer service");
604 const auto*
src =
static_cast<const uint8_t*
>(base);
606 if (target->is_host_visible()) {
607 auto* mapped =
static_cast<uint8_t*
>(target->get_mapped_ptr());
609 error<std::runtime_error>(
612 std::source_location::current(),
613 "Host-visible buffer has no mapped pointer");
616 const auto memory = target->get_buffer_resources().memory;
617 for (
const auto& [start, end] : merged) {
618 std::memcpy(mapped + start,
src + start, end - start);
619 buffer_service->flush_range(memory, start, end - start);
624 if (!buffer_service->execute_immediate) {
625 error<std::runtime_error>(
628 std::source_location::current(),
629 "upload_intervals requires execute_immediate for device-local targets");
632 size_t packed_bytes = 0;
633 for (
const auto& [start, end] : merged) {
634 packed_bytes += end - start;
637 if (!staging || staging->get_size_bytes() < packed_bytes) {
641 auto* staged =
static_cast<uint8_t*
>(staging->get_mapped_ptr());
643 error<std::runtime_error>(
646 std::source_location::current(),
647 "Staging buffer has no mapped pointer");
650 std::vector<vk::BufferCopy> regions;
651 regions.reserve(merged.size());
652 size_t packed_offset = 0;
653 for (
const auto& [start, end] : merged) {
654 const size_t length = end - start;
655 std::memcpy(staged + packed_offset,
src + start,
length);
656 regions.emplace_back(packed_offset, start,
length);
660 auto& staging_resources = staging->get_buffer_resources();
661 buffer_service->flush_range(staging_resources.memory, 0, packed_bytes);
663 const vk::Buffer source = staging_resources.buffer;
664 const vk::Buffer destination = target->get_buffer_resources().buffer;
665 buffer_service->execute_immediate([&](
void* command_buffer) {
666 vk::CommandBuffer
cmd(
static_cast<VkCommandBuffer
>(command_buffer));
667 cmd.copyBuffer(source, destination, regions);
674 const std::shared_ptr<VKBuffer>& target,
675 const std::shared_ptr<VKBuffer>& staging,
679 error<std::invalid_argument>(
682 std::source_location::current(),
683 "upload_to_gpu: target buffer is null");
690 std::vector<uint8_t> raw_bytes(
size);
691 std::memcpy(raw_bytes.data(), data,
size);
694 if (target->is_host_visible()) {
697 std::shared_ptr<VKBuffer> staging_buf = staging;
709 if (!target || !target->is_initialized()) {
711 "clear_gpu_buffer: buffer is null or not registered");
715 if (target->is_host_visible() && target->get_mapped_ptr()) {
716 std::memset(target->get_mapped_ptr(), 0, target->get_size_bytes());
720 if (!(target->get_usage_flags() & vk::BufferUsageFlagBits::eTransferDst)) {
722 "clear_gpu_buffer: unmapped buffer usage lacks transfer destination");
729 if (!buffer_service || !buffer_service->execute_immediate) {
731 "clear_gpu_buffer: BufferService unavailable");
735 const vk::Buffer
buffer = target->get_buffer_resources().buffer;
736 buffer_service->execute_immediate([
buffer](
void* command_buffer) {
737 vk::CommandBuffer
cmd(
static_cast<VkCommandBuffer
>(command_buffer));
738 cmd.fillBuffer(
buffer, 0, VK_WHOLE_SIZE, 0);
747 const std::shared_ptr<VKBuffer>& target,
748 const std::shared_ptr<VKBuffer>& staging,
756 const std::shared_ptr<VKBuffer>& source,
759 const std::shared_ptr<VKBuffer>& staging)
762 error<std::invalid_argument>(
765 std::source_location::current(),
766 "download_from_gpu: source buffer is null");
773 auto temp_target = std::make_shared<VKBuffer>(
779 if (!buffer_service) {
780 error<std::runtime_error>(
783 std::source_location::current(),
784 "download_from_gpu requires a valid buffer service");
787 buffer_service->initialize_buffer(temp_target);
789 if (source->is_host_visible()) {
792 std::shared_ptr<VKBuffer> staging_buf = staging;
801 auto temp_data = temp_target->get_data();
803 if (temp_data.empty()) {
804 error<std::runtime_error>(
807 std::source_location::current(),
808 "download_from_gpu: failed to retrieve data from temporary buffer");
811 if (temp_data.size() > 1) {
813 "download_from_gpu: unexpected multiple data variants in temporary buffer. Only the first will be used.");
819 source->get_modality());
823 std::memcpy(data,
ptr, std::min(
size, bytes));
827 const std::shared_ptr<VKBuffer>& source,
830 std::shared_ptr<VKBuffer>& staging)
832 if (!source || !data ||
size == 0)
839 || !buffer_service->execute_fenced
840 || !buffer_service->wait_fenced
841 || !buffer_service->release_fenced
842 || !buffer_service->invalidate_range) {
843 error<std::runtime_error>(
846 std::source_location::current(),
847 "download_from_gpu_async: BufferService unavailable");
850 if (!staging || staging->get_size_bytes() <
size)
853 auto handle = buffer_service->copy_buffer_fenced(
854 static_cast<void*
>(source->get_buffer()),
855 static_cast<void*
>(staging->get_buffer()),
859 error<std::runtime_error>(
862 std::source_location::current(),
863 "download_from_gpu_async: execute_fenced returned null");
866 buffer_service->wait_fenced(handle);
868 auto& resources = staging->get_buffer_resources();
869 buffer_service->invalidate_range(resources.memory, 0,
size);
871 void*
ptr = staging->get_mapped_ptr();
873 buffer_service->release_fenced(handle);
874 error<std::runtime_error>(
877 std::source_location::current(),
878 "download_from_gpu_async: staging buffer has no mapped pointer");
882 buffer_service->release_fenced(handle);
886 const std::shared_ptr<Core::VKImage>&
image,
887 std::vector<uint8_t>& raw_staging,
888 std::vector<float>& work,
889 const std::shared_ptr<VKBuffer>& gpu_staging)
896 const auto fmt_opt = loom.from_vulkan_format(
image->get_format());
900 const size_t byte_size =
static_cast<size_t>(
image->get_width())
901 *
image->get_height()
902 * loom.get_bytes_per_pixel(*fmt_opt);
907 raw_staging.resize(byte_size);
908 loom.download_data(
image, raw_staging.data(), byte_size, gpu_staging);
915 const std::shared_ptr<AudioBuffer>& audio_buffer,
916 const std::shared_ptr<VKBuffer>& gpu_buffer,
917 const std::shared_ptr<VKBuffer>& staging)
919 const auto modality = gpu_buffer->get_modality();
924 error<std::runtime_error>(
927 std::source_location::current(),
928 "GPU buffer modality is {} but audio requires AUDIO_1D or AUDIO_MULTICHANNEL. "
929 "Create VKBuffer with DataModality::AUDIO_1D or AUDIO_MULTICHANNEL.",
933 auto& audio_data = audio_buffer->get_data();
935 if (audio_data.empty()) {
937 "AudioBuffer contains no data to upload");
941 const void* data_ptr = audio_data.data();
942 size_t data_bytes = audio_data.size() *
sizeof(double);
947 "Uploaded {} bytes of double-precision audio to GPU", data_bytes);
951 const std::shared_ptr<VKBuffer>& gpu_buffer,
952 const std::shared_ptr<AudioBuffer>& audio_buffer,
953 const std::shared_ptr<VKBuffer>& staging)
957 auto dimensions = std::vector<Kakshya::DataDimension> {
959 gpu_buffer->get_size_bytes() /
sizeof(
double),
963 gpu_buffer, downloaded_data, dimensions,
966 auto double_view = accessor.
view<
double>();
968 audio_buffer->get_data() = std::vector<double>(double_view.begin(), double_view.end());
971 "Downloaded {} samples of double-precision audio from GPU", double_view.size());
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
std::vector< uint32_t > indices
std::shared_ptr< NetworkGeometryBuffer > buffer
auto gpu_buffer() const
Get raw buffer info for GPU upload.
auto view() const
Get explicit typed view of data.
Type-erased accessor for NDData with semantic view construction.
std::optional< MeshAccess > build() const
Produce a MeshAccess over the current variant contents.
void insert_flat(std::span< const uint8_t > vertex_bytes, std::span< const uint32_t > index_data, const VertexLayout &layout)
Insert a single flat mesh (no submesh tracking).
Write counterpart to MeshAccess.
static TextureLoom & instance()
Interface * get_service()
Query for a backend service.
static BackendRegistry & instance()
Get the global registry instance.
void resolve_transfer(TransferHandle &handle)
Wait for a transfer and release its resources.
std::shared_ptr< VKBuffer > create_image_staging_buffer(size_t size)
Allocate a persistent host-visible staging buffer sized for repeated streaming uploads to an image of...
std::shared_ptr< void > TransferHandle
Opaque handle to an in-flight transfer.
void upload_resizing(const void *data, size_t size, const std::shared_ptr< VKBuffer > &target, const std::shared_ptr< VKBuffer > &staging, float growth_factor)
Upload size bytes to target, growing both buffers first if needed.
Portal::Graphics::GpuBufferHandle gpu_buffer_handle(const std::shared_ptr< VKBuffer > &buffer)
View a buffer's primary GPU storage without reading it back.
TransferHandle upload_back_buffer_async(const VKBufferResources::GenerationSlot &slot, const void *data, size_t size, std::shared_ptr< VKBuffer > &staging)
Upload to a back_buffers slot without waiting for completion.
void upload_intervals(const void *base, std::span< const std::pair< size_t, size_t > > intervals, const std::shared_ptr< VKBuffer > &target, std::shared_ptr< VKBuffer > &staging)
Upload several byte ranges of one source to the same offsets in target.
void download_audio_from_gpu(const std::shared_ptr< VKBuffer > &gpu_buffer, const std::shared_ptr< AudioBuffer > &audio_buffer, const std::shared_ptr< VKBuffer > &staging)
Download GPU buffer to AudioBuffer (expects double precision)
std::optional< Kakshya::MeshData > triangle_soup_mesh(std::span< const uint8_t > vertex_bytes)
Wrap non-indexed triangle vertices as MeshData.
std::span< const float > download_and_normalise(const std::shared_ptr< Core::VKImage > &image, std::vector< uint8_t > &raw_staging, std::vector< float > &work, const std::shared_ptr< VKBuffer > &gpu_staging)
Download a VKImage to CPU and return a normalised float span.
VKBufferResources::GenerationSlot generation_slot(const Portal::Graphics::GpuBufferHandle &handle)
Express a buffer handle as the slot the back_buffers transfer helpers take.
void download_from_gpu_async(const std::shared_ptr< VKBuffer > &source, void *data, size_t size, std::shared_ptr< VKBuffer > &staging)
Download from a device-local GPU buffer without stalling the graphics queue.
std::shared_ptr< VKBuffer > create_staging_buffer(size_t size)
Create staging buffer for transfers.
bool is_device_local(const std::shared_ptr< VKBuffer > &buffer)
Check if buffer is device-local (staging needed)
std::optional< Kakshya::MeshData > download_compute_mesh(const std::shared_ptr< ComputeMeshBuffer > &buffer)
Download a ComputeMeshBuffer's current live geometry to CPU.
bool clear_gpu_buffer(const std::shared_ptr< VKBuffer > &target)
Zero a registered GPU buffer in place (auto-detects host-visible vs device-local)
void upload_to_gpu(const void *data, size_t size, const std::shared_ptr< VKBuffer > &target, const std::shared_ptr< VKBuffer > &staging, size_t dst_offset)
Upload raw data to GPU buffer (auto-detects host-visible vs device-local)
std::optional< Kakshya::VertexLayout > resolve_vertex_layout(const std::shared_ptr< VKBuffer > &source)
Resolve the vertex extent of a buffer's primary storage for reading.
void download_from_gpu(const std::shared_ptr< VKBuffer > &source, void *data, size_t size, const std::shared_ptr< VKBuffer > &staging)
Download from GPU buffer to raw data (auto-detects host-visible vs device-local)
void download_host_visible(const std::shared_ptr< VKBuffer > &source, const std::shared_ptr< VKBuffer > &target)
Download data from a host-visible buffer.
void upload_audio_to_gpu(const std::shared_ptr< AudioBuffer > &audio_buffer, const std::shared_ptr< VKBuffer > &gpu_buffer, const std::shared_ptr< VKBuffer > &staging)
Upload AudioBuffer to GPU (always double precision)
void ensure_gpu_capacity(const std::shared_ptr< VKBuffer > &target, const std::shared_ptr< VKBuffer > &staging, size_t required, float growth_factor)
Grow a GPU buffer (and its paired staging buffer) to fit required bytes.
void download_back_buffer(const VKBufferResources::GenerationSlot &slot, void *data, size_t size, std::shared_ptr< VKBuffer > &staging)
Download a raw back_buffers slot to host memory.
void resolve_back_buffer_read(TransferHandle &handle, const VKBufferResources::GenerationSlot &slot, void *data, size_t size, std::shared_ptr< VKBuffer > &staging, size_t staging_offset)
Wait for a recorded download, then copy it out of staging.
bool is_transfer_source(const std::shared_ptr< VKBuffer > &buffer)
Whether a buffer's memory can be the source of a transfer.
void download_device_local(const std::shared_ptr< VKBuffer > &source, const std::shared_ptr< VKBuffer > &target, const std::shared_ptr< VKBuffer > &staging_buffer)
Download data from a device-local buffer using a staging buffer.
void upload_host_visible(const std::shared_ptr< VKBuffer > &target, const Kakshya::DataVariant &data, size_t dst_offset)
Upload data to a host-visible buffer.
void upload_device_local(const std::shared_ptr< VKBuffer > &target, const std::shared_ptr< VKBuffer > &staging_buffer, const Kakshya::DataVariant &data, size_t dst_offset)
Upload data to a device-local buffer using a staging buffer.
void upload_back_buffer(const VKBufferResources::GenerationSlot &slot, const void *data, size_t size, std::shared_ptr< VKBuffer > &staging)
Upload host memory into a raw back_buffers slot.
TransferHandle download_back_buffer_async(const VKBufferResources::GenerationSlot &slot, size_t size, std::shared_ptr< VKBuffer > &staging, size_t staging_offset)
Record a slot-to-staging copy without waiting for completion.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
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.
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.
@ AUDIO_MULTICHANNEL
Multi-channel audio.
@ AUDIO_1D
1D audio signal
@ UNKNOWN
Unknown or undefined modality.
@ IMAGE_COLOR
2D RGB/RGBA image
std::string_view modality_to_string(DataModality modality)
Convert DataModality enum to string representation.
std::vector< std::pair< size_t, size_t > > merge_intervals(const std::vector< std::pair< size_t, size_t > > &intervals)
Merge overlapping or adjacent half-open intervals.
static DataDimension time(uint64_t samples, std::string name="time")
Convenience constructor for a temporal (time) dimension.
static MeshData empty()
Construct an empty MeshData with the canonical 60-byte mesh layout.
Vertex type for indexed triangle mesh primitives (TRIANGLE_LIST topology)
static VertexLayout for_meshes(uint32_t stride=60)
Factory: layout for MeshVertex (position, color, weight, uv, normal, tangent)
Non-owning view of a GPU storage buffer produced by a compute path.
std::function< void(const std::shared_ptr< void > &)> wait_fenced
Wait for a fenced submission to complete.
Backend buffer management service interface.