MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ upload_intervals()

MAYAFLUX_API void MayaFlux::Buffers::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.

Parameters
baseStart of the source; range [s, e) is read from base + s.
intervalsHalf-open byte ranges. Overlapping and adjacent ranges are merged first.
targetDestination buffer, already large enough for the highest end.
stagingStaging buffer for device-local targets, grown when too small. May be null for host-visible targets.

Host-visible targets are written straight from base with one flush per merged range. Device-local targets pack the ranges into staging and record every copy in one blocking submit, so N ranges cost one submit, not N. Source and destination share offsets, which is what lets a CPU mirror of the target be the source.

Definition at line 556 of file StagingUtils.cpp.

561{
562 if (!target) {
563 error<std::invalid_argument>(
564 Journal::Component::Buffers,
565 Journal::Context::BufferProcessing,
566 std::source_location::current(),
567 "upload_intervals: target buffer is null");
568 }
569
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);
575 }
576 }
577
578 if (!base || pending.empty()) {
579 return;
580 }
581
582 const auto merged = Kinesis::Discrete::merge_intervals(pending);
583
584 if (merged.back().second > target->get_size_bytes()) {
585 error<std::runtime_error>(
586 Journal::Component::Buffers,
587 Journal::Context::BufferProcessing,
588 std::source_location::current(),
589 "upload_intervals: range end {} exceeds buffer capacity {}",
590 merged.back().second, target->get_size_bytes());
591 }
592
593 auto buffer_service = Registry::BackendRegistry::instance()
594 .get_service<Registry::Service::BufferService>();
595
596 if (!buffer_service || !buffer_service->flush_range) {
597 error<std::runtime_error>(
598 Journal::Component::Buffers,
599 Journal::Context::BufferProcessing,
600 std::source_location::current(),
601 "upload_intervals requires a valid buffer service");
602 }
603
604 const auto* src = static_cast<const uint8_t*>(base);
605
606 if (target->is_host_visible()) {
607 auto* mapped = static_cast<uint8_t*>(target->get_mapped_ptr());
608 if (!mapped) {
609 error<std::runtime_error>(
610 Journal::Component::Buffers,
611 Journal::Context::BufferProcessing,
612 std::source_location::current(),
613 "Host-visible buffer has no mapped pointer");
614 }
615
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);
620 }
621 return;
622 }
623
624 if (!buffer_service->execute_immediate) {
625 error<std::runtime_error>(
626 Journal::Component::Buffers,
627 Journal::Context::BufferProcessing,
628 std::source_location::current(),
629 "upload_intervals requires execute_immediate for device-local targets");
630 }
631
632 size_t packed_bytes = 0;
633 for (const auto& [start, end] : merged) {
634 packed_bytes += end - start;
635 }
636
637 if (!staging || staging->get_size_bytes() < packed_bytes) {
638 staging = create_staging_buffer(packed_bytes);
639 }
640
641 auto* staged = static_cast<uint8_t*>(staging->get_mapped_ptr());
642 if (!staged) {
643 error<std::runtime_error>(
644 Journal::Component::Buffers,
645 Journal::Context::BufferProcessing,
646 std::source_location::current(),
647 "Staging buffer has no mapped pointer");
648 }
649
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);
657 packed_offset += length;
658 }
659
660 auto& staging_resources = staging->get_buffer_resources();
661 buffer_service->flush_range(staging_resources.memory, 0, packed_bytes);
662
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);
668 });
669}
vk::CommandBuffer cmd
uint64_t length
Definition Composite.cpp:11
const uint32_t * src
std::shared_ptr< VKBuffer > create_staging_buffer(size_t size)
Create staging buffer for transfers.
Source source()
Begin a Source chain.
Definition Plot.hpp:127

References MayaFlux::Journal::BufferProcessing, MayaFlux::Journal::Buffers, cmd, create_staging_buffer(), MayaFlux::Registry::BackendRegistry::get_service(), MayaFlux::Registry::BackendRegistry::instance(), length, MayaFlux::Kinesis::Discrete::merge_intervals(), and src.

Referenced by MayaFlux::Buffers::SliceSet::flush().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: