Download image data to a host pointer.
872{
873 if (!
image || !data) {
875 "download_image_data: invalid parameters");
876 return;
877 }
878
879 std::shared_ptr<Buffers::VKBuffer> local_staging;
880 Buffers::VKBuffer* active_staging {};
881 if (!staging) {
882 local_staging = std::make_shared<Buffers::VKBuffer>(
883 size,
884 Buffers::VKBuffer::Usage::STAGING,
887 active_staging = local_staging.get();
888 } else {
889 active_staging = staging.get();
890 }
891
892 auto record_command = [&](vk::CommandBuffer
cmd) {
893 vk::ImageMemoryBarrier barrier {};
894 barrier.oldLayout =
image->get_current_layout();
895 barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
896 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
897 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
898 barrier.image =
image->get_image();
899 barrier.subresourceRange.aspectMask =
image->get_aspect_flags();
900 barrier.subresourceRange.baseMipLevel = 0;
901 barrier.subresourceRange.levelCount =
image->get_mip_levels();
902 barrier.subresourceRange.baseArrayLayer = 0;
903 barrier.subresourceRange.layerCount =
image->get_array_layers();
904 barrier.srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead;
905 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
906
908 vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eComputeShader,
909 vk::PipelineStageFlagBits::eTransfer,
910 vk::DependencyFlags {}, {}, {}, barrier);
911
912 vk::BufferImageCopy region {};
913 region.bufferOffset = 0;
914 region.bufferRowLength = 0;
915 region.bufferImageHeight = 0;
916 region.imageSubresource.aspectMask =
image->get_aspect_flags();
917 region.imageSubresource.mipLevel = 0;
918 region.imageSubresource.baseArrayLayer = 0;
919 region.imageSubresource.layerCount =
image->get_array_layers();
920 region.imageOffset = vk::Offset3D { 0, 0, 0 };
921 region.imageExtent = vk::Extent3D {
925 };
926
927 cmd.copyImageToBuffer(
929 vk::ImageLayout::eTransferSrcOptimal,
930 active_staging->get_buffer(),
931 1, ®ion);
932
933 barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
934 barrier.newLayout = restore_layout;
935 barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
936 barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
937
939 vk::PipelineStageFlagBits::eTransfer,
940 restore_stage,
941 vk::DependencyFlags {}, {}, {}, barrier);
942 };
943
944 if (deferred && staging) {
946 image->set_current_layout(restore_layout);
947 return;
948 }
949
951
955
956 vk::FenceCreateInfo fence_info {};
957 vk::Fence
fence = device.createFence(fence_info);
958
959 vk::SubmitInfo submit_info {};
960 submit_info.commandBufferCount = 1;
961 submit_info.pCommandBuffers = &
cmd;
962
964 result != vk::Result::eSuccess) {
966 "download_image_data: queue submit failed: {}", vk::to_string(result));
967 device.destroyFence(
fence);
969 if (local_staging)
971 return;
972 }
973
974 image->set_current_layout(restore_layout);
975
976 if (
auto result = device.waitForFences(1, &
fence, VK_TRUE, UINT64_MAX);
977 result != vk::Result::eSuccess) {
979 "download_image_data: waitForFences failed: {}", vk::to_string(result));
980 }
981
982 vk::MappedMemoryRange
range { active_staging->get_buffer_resources().memory, 0, VK_WHOLE_SIZE };
983 if (auto result = device.invalidateMappedMemoryRanges(1, &range);
984 result != vk::Result::eSuccess) {
986 "download_image_data: invalidate failed: {}", vk::to_string(result));
987 }
988
989 void* mapped = active_staging->get_mapped_ptr();
990 if (mapped) {
991 std::memcpy(data, mapped, size);
992 } else {
994 "download_image_data: staging buffer has no mapped pointer");
995 }
996
997 device.destroyFence(
fence);
999
1000 if (local_staging)
1002
1004 "download_image_data: {} bytes from image {}x{}",
1005 size,
image->get_width(),
image->get_height());
1006}
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
void cleanup_buffer(const std::shared_ptr< Buffers::VKBuffer > &buffer)
Cleanup a buffer and release associated resources.
VKCommandManager & m_command_manager
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.
vk::Queue get_graphics_queue() const
Get graphics queue.
@ 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.