514{
515 if (!image || !data) {
517 "Invalid parameters for upload_image_data");
518 return;
519 }
520
521 auto staging = std::make_shared<Buffers::VKBuffer>(
522 size,
525
527
528 void* mapped = staging->get_mapped_ptr();
529 if (!mapped) {
531 "Failed to map staging buffer for image upload");
533 return;
534 }
535
536 std::memcpy(mapped, data, size);
537 staging->mark_dirty_range(0, size);
538
539 auto& resources = staging->get_buffer_resources();
540 vk::MappedMemoryRange range { resources.memory, 0, VK_WHOLE_SIZE };
541
542 if (
auto result =
m_context.
get_device().flushMappedMemoryRanges(1, &range); result != vk::Result::eSuccess) {
544 "Failed to flush mapped memory range: {}", vk::to_string(result));
545 }
546
548 vk::ImageMemoryBarrier barrier {};
549 barrier.oldLayout = image->get_current_layout();
550 barrier.newLayout = vk::ImageLayout::eTransferDstOptimal;
551 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
552 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
553 barrier.image = image->get_image();
554 barrier.subresourceRange.aspectMask = image->get_aspect_flags();
555 barrier.subresourceRange.baseMipLevel = 0;
556 barrier.subresourceRange.levelCount = image->get_mip_levels();
557 barrier.subresourceRange.baseArrayLayer = 0;
558 barrier.subresourceRange.layerCount = image->get_array_layers();
559 barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead;
560 barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
561
562 cmd.pipelineBarrier(
563 vk::PipelineStageFlagBits::eFragmentShader,
564 vk::PipelineStageFlagBits::eTransfer,
565 vk::DependencyFlags {},
566 0, nullptr, 0, nullptr, 1, &barrier);
567
568 vk::BufferImageCopy region {};
569 region.bufferOffset = 0;
570 region.bufferRowLength = 0;
571 region.bufferImageHeight = 0;
572 region.imageSubresource.aspectMask = image->get_aspect_flags();
573 region.imageSubresource.mipLevel = 0;
574 region.imageSubresource.baseArrayLayer = 0;
575 region.imageSubresource.layerCount = image->get_array_layers();
576 region.imageOffset = vk::Offset3D { 0, 0, 0 };
577 region.imageExtent = vk::Extent3D {
578 image->get_width(),
579 image->get_height(),
580 image->get_depth()
581 };
582
583 cmd.copyBufferToImage(
584 staging->get_buffer(),
585 image->get_image(),
586 vk::ImageLayout::eTransferDstOptimal,
587 1, ®ion);
588
589 barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
590 barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
591 barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
592 barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
593
594 cmd.pipelineBarrier(
595 vk::PipelineStageFlagBits::eTransfer,
596 vk::PipelineStageFlagBits::eFragmentShader,
597 vk::DependencyFlags {},
598 0, nullptr, 0, nullptr, 1, &barrier);
599 });
600
601 image->set_current_layout(vk::ImageLayout::eShaderReadOnlyOptimal);
602
604 "Uploaded {} bytes to image {}x{}",
605 size, image->get_width(), image->get_height());
606}
#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