From f758c05a0af09c21144cc614b03e3c9813e633b7 Mon Sep 17 00:00:00 2001 From: Alex Laptop <alexander.gauggel@web.de> Date: Sat, 11 Sep 2021 21:47:46 +0200 Subject: [PATCH] [#113] Fix UI rendering initial image layout being set to undefined --- include/vkcv/Core.hpp | 10 ++++++++++ modules/gui/src/vkcv/gui/GUI.cpp | 20 ++++++++++++++++---- src/vkcv/Core.cpp | 8 ++++++++ src/vkcv/ImageManager.cpp | 16 ++++++++++++++++ src/vkcv/ImageManager.hpp | 4 ++++ 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index d6e47d26..c24d4c7c 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -391,6 +391,16 @@ namespace vkcv void prepareSwapchainImageForPresent(const CommandStreamHandle& handle); void prepareImageForSampling(const CommandStreamHandle& cmdStream, const ImageHandle& image); void prepareImageForStorage(const CommandStreamHandle& cmdStream, const ImageHandle& image); + + // normally layout transitions for attachments are handled by the core + // however for manual vulkan use, e.g. ImGui integration, this function is exposed + // this is also why the command buffer is passed directly, instead of the command stream handle + void prepareImageForAttachmentManually(const vk::CommandBuffer& cmdBuffer, const ImageHandle& image); + + // if manual vulkan work, e.g. ImGui integration, changes an image layout this function must be used + // to update the internal image state + void updateImageLayoutManual(const vkcv::ImageHandle& image, const vk::ImageLayout layout); + void recordImageMemoryBarrier(const CommandStreamHandle& cmdStream, const ImageHandle& image); void recordBufferMemoryBarrier(const CommandStreamHandle& cmdStream, const BufferHandle& buffer); void resolveMSAAImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst); diff --git a/modules/gui/src/vkcv/gui/GUI.cpp b/modules/gui/src/vkcv/gui/GUI.cpp index 22c40d29..7ee33537 100644 --- a/modules/gui/src/vkcv/gui/GUI.cpp +++ b/modules/gui/src/vkcv/gui/GUI.cpp @@ -6,6 +6,9 @@ namespace vkcv::gui { + const static vk::ImageLayout initialImageLayout = vk::ImageLayout::eColorAttachmentOptimal; + const static vk::ImageLayout finalImageLayout = vk::ImageLayout::ePresentSrcKHR; + static void checkVulkanResult(VkResult resultCode) { if (resultCode == 0) return; @@ -95,8 +98,8 @@ namespace vkcv::gui { vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, - vk::ImageLayout::eUndefined, - vk::ImageLayout::ePresentSrcKHR + initialImageLayout, + finalImageLayout ); const vk::AttachmentReference attachmentReference ( @@ -199,7 +202,7 @@ namespace vkcv::gui { const Swapchain& swapchain = m_core.getSwapchain(m_windowHandle); const auto extent = swapchain.getExtent(); - + const vk::ImageView swapchainImageView = m_core.getSwapchainImageView(); const vk::FramebufferCreateInfo framebufferCreateInfo ( @@ -218,6 +221,10 @@ namespace vkcv::gui { submitInfo.queueType = QueueType::Graphics; m_core.recordAndSubmitCommandsImmediate(submitInfo, [&](const vk::CommandBuffer& commandBuffer) { + + assert(initialImageLayout == vk::ImageLayout::eColorAttachmentOptimal); + m_core.prepareImageForAttachmentManually(commandBuffer, vkcv::ImageHandle::createSwapchainImageHandle()); + const vk::Rect2D renderArea ( vk::Offset2D(0, 0), extent @@ -230,12 +237,17 @@ namespace vkcv::gui { 0, nullptr ); - + commandBuffer.beginRenderPass(beginInfo, vk::SubpassContents::eInline); ImGui_ImplVulkan_RenderDrawData(drawData, static_cast<VkCommandBuffer>(commandBuffer)); commandBuffer.endRenderPass(); + + // executing the renderpass changed the image layout without going through the image manager + // therefore the layout must be updated manually + m_core.updateImageLayoutManual(vkcv::ImageHandle::createSwapchainImageHandle(), finalImageLayout); + }, [&]() { m_context.getDevice().destroyFramebuffer(framebuffer); }); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 21435c81..00ea4a9f 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -737,6 +737,14 @@ namespace vkcv }, nullptr); } + void Core::prepareImageForAttachmentManually(const vk::CommandBuffer& cmdBuffer, const ImageHandle& image) { + transitionRendertargetsToAttachmentLayout({ image }, *m_ImageManager, cmdBuffer); + } + + void Core::updateImageLayoutManual(const vkcv::ImageHandle& image, const vk::ImageLayout layout) { + m_ImageManager->updateImageLayoutManual(image, layout); + } + void Core::recordImageMemoryBarrier(const CommandStreamHandle& cmdStream, const ImageHandle& image) { recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { m_ImageManager->recordImageMemoryBarrier(image, cmdBuffer); diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 4ddd7f8c..bde02049 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -685,4 +685,20 @@ namespace vkcv { } } + void ImageManager::updateImageLayoutManual(const vkcv::ImageHandle& handle, const vk::ImageLayout layout) { + const uint64_t id = handle.getId(); + + if (handle.isSwapchainImage()) { + m_swapchainImages[m_currentSwapchainInputImage].m_layout = layout; + } + else { + if (id >= m_images.size()) { + vkcv_log(LogLevel::ERROR, "Invalid handle"); + return; + } + m_swapchainImages[id].m_layout = layout; + } + + } + } \ No newline at end of file diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index 4d994221..124508d5 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -120,5 +120,9 @@ namespace vkcv { void setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views, uint32_t width, uint32_t height, vk::Format format); + // if manual vulkan work, e.g. ImGui integration, changes an image layout this function must be used + // to update the internal image state + void updateImageLayoutManual(const vkcv::ImageHandle& handle, const vk::ImageLayout layout); + }; } \ No newline at end of file -- GitLab