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 409 of file TextureLoom.cpp.

411{
412 if (!is_initialized() || !image || !data) {
414 "Invalid parameters for download_data_async");
415 return;
416 }
417
418 auto buffer_service = Registry::BackendRegistry::instance()
419 .get_service<Registry::Service::BufferService>();
420 if (!buffer_service || !buffer_service->execute_fenced
421 || !buffer_service->wait_fenced || !buffer_service->release_fenced
422 || !buffer_service->initialize_buffer || !buffer_service->destroy_buffer
423 || !buffer_service->invalidate_range) {
425 "download_data_async: BufferService unavailable or incomplete");
426 return;
427 }
428
429 auto staging = std::make_shared<Buffers::VKBuffer>(
430 size,
433
434 buffer_service->initialize_buffer(std::static_pointer_cast<void>(staging));
435
436 auto handle = buffer_service->execute_fenced([&](void* cmd_ptr) {
437 vk::CommandBuffer cmd(static_cast<VkCommandBuffer>(cmd_ptr));
438
439 vk::ImageMemoryBarrier barrier {};
440 barrier.oldLayout = image->get_current_layout();
441 barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
442 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
443 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
444 barrier.image = image->get_image();
445 barrier.subresourceRange.aspectMask = image->get_aspect_flags();
446 barrier.subresourceRange.baseMipLevel = 0;
447 barrier.subresourceRange.levelCount = image->get_mip_levels();
448 barrier.subresourceRange.baseArrayLayer = 0;
449 barrier.subresourceRange.layerCount = image->get_array_layers();
450 barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead;
451 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
452
453 cmd.pipelineBarrier(
454 vk::PipelineStageFlagBits::eFragmentShader,
455 vk::PipelineStageFlagBits::eTransfer,
456 vk::DependencyFlags {}, {}, {}, barrier);
457
458 vk::BufferImageCopy region {};
459 region.bufferOffset = 0;
460 region.bufferRowLength = 0;
461 region.bufferImageHeight = 0;
462 region.imageSubresource.aspectMask = image->get_aspect_flags();
463 region.imageSubresource.mipLevel = 0;
464 region.imageSubresource.baseArrayLayer = 0;
465 region.imageSubresource.layerCount = image->get_array_layers();
466 region.imageOffset = vk::Offset3D { 0, 0, 0 };
467 region.imageExtent = vk::Extent3D {
468 image->get_width(),
469 image->get_height(),
470 image->get_depth()
471 };
472
473 cmd.copyImageToBuffer(
474 image->get_image(),
475 vk::ImageLayout::eTransferSrcOptimal,
476 staging->get_buffer(),
477 1, &region);
478
479 barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
480 barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
481 barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
482 barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
483
484 cmd.pipelineBarrier(
485 vk::PipelineStageFlagBits::eTransfer,
486 vk::PipelineStageFlagBits::eFragmentShader,
487 vk::DependencyFlags {}, {}, {}, barrier);
488 });
489
490 if (!handle) {
492 "download_data_async: execute_fenced returned null handle");
493 buffer_service->destroy_buffer(std::static_pointer_cast<void>(staging));
494 return;
495 }
496
497 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
498
499 buffer_service->wait_fenced(handle);
500
501 auto& resources = staging->get_buffer_resources();
502 buffer_service->invalidate_range(resources.memory, 0, 0);
503
504 void* mapped = staging->get_mapped_ptr();
505 if (mapped) {
506 std::memcpy(data, mapped, size);
507 } else {
509 "download_data_async: staging buffer has no mapped pointer");
510 }
511
512 buffer_service->release_fenced(handle);
513 buffer_service->destroy_buffer(std::static_pointer_cast<void>(staging));
514
516 "download_data_async: completed {} byte download for {}x{}",
517 size, image->get_width(), image->get_height());
518}
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
vk::CommandBuffer cmd
IO::ImageData image
Definition Decoder.cpp:57
@ STAGING
Host-visible staging buffer (CPU-writable, eTransferSrc|Dst)
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, and MayaFlux::Buffers::VKBuffer::STAGING.

+ Here is the call graph for this function: