612{
613 if (!image || !data) {
615 "Invalid parameters for download_image_data");
616 return;
617 }
618
619 auto staging = std::make_shared<Buffers::VKBuffer>(
620 size,
623
625
627 vk::ImageMemoryBarrier barrier {};
628 barrier.oldLayout = image->get_current_layout();
629 barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
630 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
631 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
632 barrier.image = image->get_image();
633 barrier.subresourceRange.aspectMask = image->get_aspect_flags();
634 barrier.subresourceRange.baseMipLevel = 0;
635 barrier.subresourceRange.levelCount = image->get_mip_levels();
636 barrier.subresourceRange.baseArrayLayer = 0;
637 barrier.subresourceRange.layerCount = image->get_array_layers();
638 barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead;
639 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
640
641 cmd.pipelineBarrier(
642 vk::PipelineStageFlagBits::eFragmentShader,
643 vk::PipelineStageFlagBits::eTransfer,
644 vk::DependencyFlags {},
645 0, nullptr, 0, nullptr, 1, &barrier);
646
647 vk::BufferImageCopy region {};
648 region.bufferOffset = 0;
649 region.bufferRowLength = 0;
650 region.bufferImageHeight = 0;
651 region.imageSubresource.aspectMask = image->get_aspect_flags();
652 region.imageSubresource.mipLevel = 0;
653 region.imageSubresource.baseArrayLayer = 0;
654 region.imageSubresource.layerCount = image->get_array_layers();
655 region.imageOffset = vk::Offset3D { 0, 0, 0 };
656 region.imageExtent = vk::Extent3D {
657 image->get_width(),
658 image->get_height(),
659 image->get_depth()
660 };
661
662 cmd.copyImageToBuffer(
663 image->get_image(),
664 vk::ImageLayout::eTransferSrcOptimal,
665 staging->get_buffer(),
666 1, ®ion);
667
668 barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
669 barrier.newLayout = image->get_current_layout();
670 barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
671 barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
672
673 cmd.pipelineBarrier(
674 vk::PipelineStageFlagBits::eTransfer,
675 vk::PipelineStageFlagBits::eFragmentShader,
676 vk::DependencyFlags {},
677 0, nullptr, 0, nullptr, 1, &barrier);
678 });
679
680 staging->mark_invalid_range(0, size);
681 auto& resources = staging->get_buffer_resources();
682 vk::MappedMemoryRange range { resources.memory, 0, VK_WHOLE_SIZE };
683
684 if (
auto result =
m_context.
get_device().invalidateMappedMemoryRanges(1, &range); result != vk::Result::eSuccess) {
686 "Failed to invalidate mapped memory range: {}", vk::to_string(result));
687 }
688
689 void* mapped = staging->get_mapped_ptr();
690 if (mapped) {
691 std::memcpy(data, mapped, size);
692 }
693
695
697 "Downloaded {} bytes from image {}x{}",
698 size, image->get_width(), image->get_height());
699}
#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