632{
633 if (!
image || !data) {
635 "Invalid parameters for upload_image_data");
636 return;
637 }
638
639 auto staging = std::make_shared<Buffers::VKBuffer>(
640 size,
643
645
646 void* mapped = staging->get_mapped_ptr();
647 if (!mapped) {
649 "Failed to map staging buffer for image upload");
651 return;
652 }
653
654 std::memcpy(mapped, data, size);
655 staging->mark_dirty_range(0, size);
656
657 auto& resources = staging->get_buffer_resources();
658 vk::MappedMemoryRange
range { resources.memory, 0, VK_WHOLE_SIZE };
659
660 if (
auto result =
m_context.
get_device().flushMappedMemoryRanges(1, &range); result != vk::Result::eSuccess) {
662 "Failed to flush mapped memory range: {}", vk::to_string(result));
663 }
664
666 vk::ImageMemoryBarrier barrier {};
667 barrier.oldLayout =
image->get_current_layout();
668 barrier.newLayout = vk::ImageLayout::eTransferDstOptimal;
669 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
670 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
671 barrier.image =
image->get_image();
672 barrier.subresourceRange.aspectMask =
image->get_aspect_flags();
673 barrier.subresourceRange.baseMipLevel = 0;
674 barrier.subresourceRange.levelCount =
image->get_mip_levels();
675 barrier.subresourceRange.baseArrayLayer = 0;
676 barrier.subresourceRange.layerCount =
image->get_array_layers();
677 barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead;
678 barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
679
681 vk::PipelineStageFlagBits::eFragmentShader,
682 vk::PipelineStageFlagBits::eTransfer,
683 vk::DependencyFlags {},
684 0, nullptr, 0, nullptr, 1, &barrier);
685
686 vk::BufferImageCopy region {};
687 region.bufferOffset = 0;
688 region.bufferRowLength = 0;
689 region.bufferImageHeight = 0;
690 region.imageSubresource.aspectMask =
image->get_aspect_flags();
691 region.imageSubresource.mipLevel = 0;
692 region.imageSubresource.baseArrayLayer = 0;
693 region.imageSubresource.layerCount =
image->get_array_layers();
694 region.imageOffset = vk::Offset3D { 0, 0, 0 };
695 region.imageExtent = vk::Extent3D {
699 };
700
701 cmd.copyBufferToImage(
702 staging->get_buffer(),
704 vk::ImageLayout::eTransferDstOptimal,
705 1, ®ion);
706
707 barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
708 barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
709 barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
710 barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
711
713 vk::PipelineStageFlagBits::eTransfer,
714 vk::PipelineStageFlagBits::eFragmentShader,
715 vk::DependencyFlags {},
716 0, nullptr, 0, nullptr, 1, &barrier);
717 });
718
719 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
720
722 "Uploaded {} bytes to image {}x{}",
723 size,
image->get_width(),
image->get_height());
724}
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
@ STAGING
Host-visible staging buffer (CPU-writable, eTransferSrc|Dst)
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.