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

◆ download_image_data()

void MayaFlux::Core::BackendResourceManager::download_image_data ( std::shared_ptr< VKImage >  image,
void *  data,
size_t  size,
const std::shared_ptr< Buffers::VKBuffer > &  staging = nullptr,
bool  deferred = false,
vk::ImageLayout  restore_layout = vk::ImageLayout::eShaderReadOnlyOptimal,
vk::PipelineStageFlags  restore_stage = vk::PipelineStageFlagBits::eFragmentShader 
)

Download image data to a host pointer.

When staging is null, allocates and destroys a per-call staging buffer internally. When staging is supplied, it is used as-is and not destroyed after — the caller owns its lifetime.

When deferred is false (default), submits under a fence and blocks the calling thread on vkWaitForFences. This is non-blocking relative to the graphics queue (waitIdle is never called). When deferred is true and staging is supplied, records commands for deferred submission; the caller is responsible for flushing.

Parameters
imageSource image.
dataDestination host pointer, at least size bytes.
sizeByte count to read.
stagingPersistent host-visible buffer, or nullptr for per-call allocation.
deferredRecord for deferred submission (requires staging).
restore_layoutLayout to restore after the copy.
restore_stagePipeline stage that consumes the image after restore.

Definition at line 862 of file BackendResoureManager.cpp.

870{
871 if (!image || !data) {
873 "download_image_data: invalid parameters");
874 return;
875 }
876
877 std::shared_ptr<Buffers::VKBuffer> local_staging;
878 Buffers::VKBuffer* active_staging {};
879 if (!staging) {
880 local_staging = std::make_shared<Buffers::VKBuffer>(
881 size,
882 Buffers::VKBuffer::Usage::STAGING,
884 initialize_buffer(local_staging);
885 active_staging = local_staging.get();
886 } else {
887 active_staging = staging.get();
888 }
889
890 auto record_command = [&](vk::CommandBuffer cmd) {
891 vk::ImageMemoryBarrier barrier {};
892 barrier.oldLayout = image->get_current_layout();
893 barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
894 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
895 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
896 barrier.image = image->get_image();
897 barrier.subresourceRange.aspectMask = image->get_aspect_flags();
898 barrier.subresourceRange.baseMipLevel = 0;
899 barrier.subresourceRange.levelCount = image->get_mip_levels();
900 barrier.subresourceRange.baseArrayLayer = 0;
901 barrier.subresourceRange.layerCount = image->get_array_layers();
902 barrier.srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead;
903 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
904
905 cmd.pipelineBarrier(
906 vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eComputeShader,
907 vk::PipelineStageFlagBits::eTransfer,
908 vk::DependencyFlags {}, {}, {}, barrier);
909
910 vk::BufferImageCopy region {};
911 region.bufferOffset = 0;
912 region.bufferRowLength = 0;
913 region.bufferImageHeight = 0;
914 region.imageSubresource.aspectMask = image->get_aspect_flags();
915 region.imageSubresource.mipLevel = 0;
916 region.imageSubresource.baseArrayLayer = 0;
917 region.imageSubresource.layerCount = image->get_array_layers();
918 region.imageOffset = vk::Offset3D { 0, 0, 0 };
919 region.imageExtent = vk::Extent3D {
920 image->get_width(),
921 image->get_height(),
922 image->get_depth()
923 };
924
925 cmd.copyImageToBuffer(
926 image->get_image(),
927 vk::ImageLayout::eTransferSrcOptimal,
928 active_staging->get_buffer(),
929 1, &region);
930
931 barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
932 barrier.newLayout = restore_layout;
933 barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
934 barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
935
936 cmd.pipelineBarrier(
937 vk::PipelineStageFlagBits::eTransfer,
938 restore_stage,
939 vk::DependencyFlags {}, {}, {}, barrier);
940 };
941
942 if (deferred && staging) {
943 record_deferred_commands(record_command);
944 image->set_current_layout(restore_layout);
945 return;
946 }
947
948 auto device = m_context.get_device();
949
951 record_command(cmd);
952 cmd.end();
953
954 vk::FenceCreateInfo fence_info {};
955 vk::Fence fence = device.createFence(fence_info);
956
957 vk::SubmitInfo submit_info {};
958 submit_info.commandBufferCount = 1;
959 submit_info.pCommandBuffers = &cmd;
960
961 if (auto result = m_context.get_graphics_queue().submit(1, &submit_info, fence);
962 result != vk::Result::eSuccess) {
964 "download_image_data: queue submit failed: {}", vk::to_string(result));
965 device.destroyFence(fence);
967 if (local_staging)
968 cleanup_buffer(local_staging);
969 return;
970 }
971
972 image->set_current_layout(restore_layout);
973
974 if (auto result = device.waitForFences(1, &fence, VK_TRUE, UINT64_MAX);
975 result != vk::Result::eSuccess) {
977 "download_image_data: waitForFences failed: {}", vk::to_string(result));
978 }
979
980 vk::MappedMemoryRange range { active_staging->get_buffer_resources().memory, 0, VK_WHOLE_SIZE };
981 if (auto result = device.invalidateMappedMemoryRanges(1, &range);
982 result != vk::Result::eSuccess) {
984 "download_image_data: invalidate failed: {}", vk::to_string(result));
985 }
986
987 void* mapped = active_staging->get_mapped_ptr();
988 if (mapped) {
989 std::memcpy(data, mapped, size);
990 } else {
992 "download_image_data: staging buffer has no mapped pointer");
993 }
994
995 device.destroyFence(fence);
997
998 if (local_staging)
999 cleanup_buffer(local_staging);
1000
1002 "download_image_data: {} bytes from image {}x{}",
1003 size, image->get_width(), image->get_height());
1004}
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
vk::Fence fence
vk::CommandBuffer cmd
IO::ImageData image
Definition Decoder.cpp:47
bool size
vk::PhysicalDevice device
Definition VKDevice.cpp:121
void cleanup_buffer(const std::shared_ptr< Buffers::VKBuffer > &buffer)
Cleanup a buffer and release associated resources.
void initialize_buffer(const std::shared_ptr< Buffers::VKBuffer > &buffer)
Initialize a buffer for use with the graphics backend.
void record_deferred_commands(const std::function< void(vk::CommandBuffer)> &recorder)
Record deferred command recording for buffer operations.
void free_command_buffer(vk::CommandBuffer command_buffer)
Free a command buffer back to the pool.
vk::CommandBuffer begin_single_time_commands()
Begin single-time command (for transfers, etc.)
vk::Device get_device() const
Get logical device.
Definition VKContext.hpp:49
vk::Queue get_graphics_queue() const
Get graphics queue.
Definition VKContext.hpp:54
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ Core
Core engine, backend, subsystems.
@ IMAGE_COLOR
2D RGB/RGBA image
std::vector< double > range(std::span< const double > data, size_t n_windows, uint32_t hop_size, uint32_t window_size)
Value range (max - min) per window.
Definition Analysis.cpp:452

References MayaFlux::Core::VKCommandManager::begin_single_time_commands(), cleanup_buffer(), cmd, MayaFlux::Journal::Core, device, fence, MayaFlux::Core::VKCommandManager::free_command_buffer(), MayaFlux::Core::VKContext::get_device(), MayaFlux::Core::VKContext::get_graphics_queue(), MayaFlux::Journal::GraphicsBackend, image, MayaFlux::Kakshya::IMAGE_COLOR, initialize_buffer(), m_command_manager, m_context, MF_DEBUG, MF_ERROR, record_deferred_commands(), and size.

Referenced by MayaFlux::Portal::Graphics::TextureLoom::download_data(), and MayaFlux::Core::BackendWindowHandler::setup_backend_service().

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