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

◆ download_data_async()

void MayaFlux::Portal::Graphics::TextureLoom::download_data_async ( const std::shared_ptr< Core::VKImage > &  image,
void *  data,
size_t  size 
)

Download pixel data from a texture without blocking the graphics queue.

Allocates a per-call staging buffer, command buffer, and fence. Records a copy-image-to-buffer op, submits with the fence, and blocks the calling thread on vkWaitForFences until the copy completes. Unlike download_data, this does not call queue.waitIdle, so other graphics work proceeds concurrently.

Intended to be called from a worker thread (e.g. via std::async). Calling from the graphics thread or any thread that must not block will stall that thread for the duration of the copy.

Parameters
imageSource image.
dataDestination host pointer, at least size bytes.
sizeByte count to read.

Definition at line 408 of file TextureLoom.cpp.

410{
411 if (!is_initialized() || !image || !data) {
413 "Invalid parameters for download_data_async");
414 return;
415 }
416
417 auto buffer_service = Registry::BackendRegistry::instance()
418 .get_service<Registry::Service::BufferService>();
419 if (!buffer_service || !buffer_service->execute_fenced
420 || !buffer_service->wait_fenced || !buffer_service->release_fenced
421 || !buffer_service->initialize_buffer || !buffer_service->destroy_buffer
422 || !buffer_service->invalidate_range) {
424 "download_data_async: BufferService unavailable or incomplete");
425 return;
426 }
427
428 auto staging = std::make_shared<Buffers::VKBuffer>(
429 size,
432
433 buffer_service->initialize_buffer(std::static_pointer_cast<void>(staging));
434
435 auto handle = buffer_service->execute_fenced([&](void* cmd_ptr) {
436 vk::CommandBuffer cmd(static_cast<VkCommandBuffer>(cmd_ptr));
437
438 vk::ImageMemoryBarrier barrier {};
439 barrier.oldLayout = image->get_current_layout();
440 barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
441 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
442 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
443 barrier.image = image->get_image();
444 barrier.subresourceRange.aspectMask = image->get_aspect_flags();
445 barrier.subresourceRange.baseMipLevel = 0;
446 barrier.subresourceRange.levelCount = image->get_mip_levels();
447 barrier.subresourceRange.baseArrayLayer = 0;
448 barrier.subresourceRange.layerCount = image->get_array_layers();
449 barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead;
450 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
451
452 cmd.pipelineBarrier(
453 vk::PipelineStageFlagBits::eFragmentShader,
454 vk::PipelineStageFlagBits::eTransfer,
455 vk::DependencyFlags {}, {}, {}, barrier);
456
457 vk::BufferImageCopy region {};
458 region.bufferOffset = 0;
459 region.bufferRowLength = 0;
460 region.bufferImageHeight = 0;
461 region.imageSubresource.aspectMask = image->get_aspect_flags();
462 region.imageSubresource.mipLevel = 0;
463 region.imageSubresource.baseArrayLayer = 0;
464 region.imageSubresource.layerCount = image->get_array_layers();
465 region.imageOffset = vk::Offset3D { 0, 0, 0 };
466 region.imageExtent = vk::Extent3D {
467 image->get_width(),
468 image->get_height(),
469 image->get_depth()
470 };
471
472 cmd.copyImageToBuffer(
473 image->get_image(),
474 vk::ImageLayout::eTransferSrcOptimal,
475 staging->get_buffer(),
476 1, &region);
477
478 barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
479 barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
480 barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
481 barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
482
483 cmd.pipelineBarrier(
484 vk::PipelineStageFlagBits::eTransfer,
485 vk::PipelineStageFlagBits::eFragmentShader,
486 vk::DependencyFlags {}, {}, {}, barrier);
487 });
488
489 if (!handle) {
491 "download_data_async: execute_fenced returned null handle");
492 buffer_service->destroy_buffer(std::static_pointer_cast<void>(staging));
493 return;
494 }
495
496 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
497
498 buffer_service->wait_fenced(handle);
499
500 auto& resources = staging->get_buffer_resources();
501 buffer_service->invalidate_range(resources.memory, 0, 0);
502
503 void* mapped = staging->get_mapped_ptr();
504 if (mapped) {
505 std::memcpy(data, mapped, size);
506 } else {
508 "download_data_async: staging buffer has no mapped pointer");
509 }
510
511 buffer_service->release_fenced(handle);
512 buffer_service->destroy_buffer(std::static_pointer_cast<void>(staging));
513
515 "download_data_async: completed {} byte download for {}x{}",
516 size, image->get_width(), image->get_height());
517}
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
vk::CommandBuffer cmd
IO::ImageData image
Range size
@ STAGING
Host-visible staging buffer (CPU-writable)
bool is_initialized() const
Check if manager is initialized.
Interface * get_service()
Query for a backend service.
static BackendRegistry & instance()
Get the global registry instance.
@ ImageProcessing
Image processing tasks (filters, transformations)
@ Portal
High-level user-facing API layer.
@ IMAGE_COLOR
2D RGB/RGBA image

References cmd, MayaFlux::Registry::BackendRegistry::get_service(), image, MayaFlux::Kakshya::IMAGE_COLOR, MayaFlux::Journal::ImageProcessing, MayaFlux::Registry::BackendRegistry::instance(), is_initialized(), MF_DEBUG, MF_ERROR, MayaFlux::Journal::Portal, size, and MayaFlux::Buffers::VKBuffer::STAGING.

+ Here is the call graph for this function: