Read several fields' current values into host memory at once.
One staging buffer and one fence wait for the whole batch, rather than a full round trip per field. Prefer this over repeated read_field when more than one field is wanted from the same cycle, which is the ordinary case for interchange export.
Reads from each field's current read slot, as read_field does. A name that is not declared, or a size that does not match that field, is logged and skipped; the rest of the batch proceeds.
688{
689 if (names.size() != dsts.size()) {
691 "VolumeGridBuffer::read_fields: {} names against {} destinations",
692 names.size(), dsts.size());
693 return;
694 }
695
696 constexpr size_t k_alignment = 16;
697
700 std::vector<size_t> offsets;
702
703 for (size_t i = 0; i < names.size(); ++i) {
704 const auto* field =
find_field(names[i],
"read_fields");
705 if (!field) {
706 continue;
707 }
708
709 const size_t expected =
static_cast<size_t>(
get_cell_count()) * field->stride_bytes;
710 if (dsts[i].second != expected) {
712 "VolumeGridBuffer::read_fields: size {} does not match expected {} for '{}'",
713 dsts[i].second, expected, names[i]);
714 continue;
715 }
716
718 offsets.push_back(
total);
719 total += (dsts[i].second + k_alignment - 1) & ~(k_alignment - 1);
720 }
721
723 return;
724 }
725
727
730 }
731
732 std::vector<TransferHandle> handles;
733 handles.reserve(
indices.size());
734
735 for (
size_t k = 0; k <
indices.size(); ++k) {
737 const uint32_t slot = field->read_is_a ? field->slot_a : field->slot_b;
739 resources.back_buffers[slot], dsts[
indices[k]].second,
741 }
742
743 for (
size_t k = 0; k <
indices.size(); ++k) {
745 const uint32_t slot = field->read_is_a ? field->slot_a : field->slot_b;
747 handles[k], resources.back_buffers[slot],
750 }
751}
#define MF_ERROR(comp, ctx,...)
std::vector< uint32_t > indices
const VKBufferResources & get_buffer_resources() const
Get all buffer resources at once (read-only)
const Field * find_field(const std::string &name, const char *context) const
Resolve a field by name.
TransferHandle m_pending_transfer
In-flight seed upload, resolved before the next transfer.
uint32_t get_cell_count() const
Total cell count.
std::shared_ptr< VKBuffer > m_transfer_staging
Reused across seed and read calls.
void resolve_transfer(TransferHandle &handle)
Wait for a transfer and release its resources.
std::shared_ptr< VKBuffer > create_staging_buffer(size_t size)
Create staging buffer for transfers.
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.
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.
@ BufferManagement
Buffer Management (Buffers::BufferManager, creating buffers)
@ Buffers
Buffers, Managers, processors and processing chains.