Download data from an image into a caller-supplied buffer.
Transitions the image to eTransferSrcOptimal, copies to a staging buffer, then restores it to restore_layout using restore_stage.
The defaults cover the common case of a device-local texture in shader read-only layout. Pass ePresentSrcKHR / eBottomOfPipe for swapchain images.
699{
700 if (!image || !data) {
702 "Invalid parameters for download_image_data");
703 return;
704 }
705
706 auto staging = std::make_shared<Buffers::VKBuffer>(
707 size,
710
712
714 vk::ImageMemoryBarrier barrier {};
715 barrier.oldLayout = image->get_current_layout();
716 barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
717 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
718 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
719 barrier.image = image->get_image();
720 barrier.subresourceRange.aspectMask = image->get_aspect_flags();
721 barrier.subresourceRange.baseMipLevel = 0;
722 barrier.subresourceRange.levelCount = image->get_mip_levels();
723 barrier.subresourceRange.baseArrayLayer = 0;
724 barrier.subresourceRange.layerCount = image->get_array_layers();
725 barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead;
726 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
727
728 cmd.pipelineBarrier(
729 vk::PipelineStageFlagBits::eFragmentShader,
730 vk::PipelineStageFlagBits::eTransfer,
731 vk::DependencyFlags {}, {}, {}, barrier);
732
733 vk::BufferImageCopy region {};
734 region.bufferOffset = 0;
735 region.bufferRowLength = 0;
736 region.bufferImageHeight = 0;
737 region.imageSubresource.aspectMask = image->get_aspect_flags();
738 region.imageSubresource.mipLevel = 0;
739 region.imageSubresource.baseArrayLayer = 0;
740 region.imageSubresource.layerCount = image->get_array_layers();
741 region.imageOffset = vk::Offset3D { 0, 0, 0 };
742 region.imageExtent = vk::Extent3D {
743 image->get_width(),
744 image->get_height(),
745 image->get_depth()
746 };
747
748 cmd.copyImageToBuffer(
749 image->get_image(),
750 vk::ImageLayout::eTransferSrcOptimal,
751 staging->get_buffer(),
752 1, ®ion);
753
754 barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
755 barrier.newLayout = restore_layout;
756 barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
757 barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
758
759 cmd.pipelineBarrier(
760 vk::PipelineStageFlagBits::eTransfer,
761 restore_stage,
762 vk::DependencyFlags {}, {}, {}, barrier);
763 });
764
765 staging->mark_invalid_range(0, size);
766 auto& resources = staging->get_buffer_resources();
767 vk::MappedMemoryRange
range { resources.memory, 0, VK_WHOLE_SIZE };
768
770 result != vk::Result::eSuccess) {
772 "Failed to invalidate mapped memory range: {}", vk::to_string(result));
773 }
774
775 if (void* mapped = staging->get_mapped_ptr()) {
776 std::memcpy(data, mapped, size);
777 }
778
780
782 "Downloaded {} bytes from image {}x{}",
783 size, image->get_width(), image->get_height());
784}
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
@ STAGING
Host-visible staging buffer (CPU-writable)
void cleanup_buffer(const std::shared_ptr< Buffers::VKBuffer > &buffer)
Cleanup a buffer and release associated resources.
void execute_immediate_commands(const std::function< void(vk::CommandBuffer)> &recorder)
Execute immediate command recording for buffer operations.
void initialize_buffer(const std::shared_ptr< Buffers::VKBuffer > &buffer)
Initialize a buffer for use with the graphics backend.
vk::Device get_device() const
Get logical device.
@ 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.