diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index d6e47d26e5c26dab7929ac5905938c2ac0c80125..c24d4c7cc435389c739bf47f7316586b5d6c676c 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 22c40d2937c69525c04ffd79f26107f829e42f4d..7ee335379603b3e21ab4d95f0738097bd954cf71 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/BufferManager.cpp b/src/vkcv/BufferManager.cpp index f22d56650654f66dd1fea4141a449004dcad88cc..84529dbd019e2bee6e6a2eaa142dbd25d064b06c 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -328,8 +328,8 @@ namespace vkcv { buffer.m_size); cmdBuffer.pipelineBarrier( - vk::PipelineStageFlagBits::eTopOfPipe, - vk::PipelineStageFlagBits::eBottomOfPipe, + vk::PipelineStageFlagBits::eAllCommands, + vk::PipelineStageFlagBits::eAllCommands, {}, nullptr, memoryBarrier, diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 21435c818451d1bea796b862cbb57ebeea8f0abd..00ea4a9fec2bbc49ef078074ca7e13927d146b9d 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/ImageLayoutTransitions.cpp b/src/vkcv/ImageLayoutTransitions.cpp index 8d31c64ccbcbf33e259714f8c581c920738190b4..14b226847a15b5e9cadffc28555e76b88b61e6a3 100644 --- a/src/vkcv/ImageLayoutTransitions.cpp +++ b/src/vkcv/ImageLayoutTransitions.cpp @@ -58,8 +58,8 @@ namespace vkcv { void recordImageBarrier(vk::CommandBuffer cmdBuffer, vk::ImageMemoryBarrier barrier) { cmdBuffer.pipelineBarrier( - vk::PipelineStageFlagBits::eTopOfPipe, - vk::PipelineStageFlagBits::eBottomOfPipe, + vk::PipelineStageFlagBits::eAllCommands, + vk::PipelineStageFlagBits::eAllCommands, {}, nullptr, nullptr, diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 4ddd7f8c44c6023a80831bc8b4b092692e84ec86..bde020498e19e3f9bf0667c7182ca13d11f9044f 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 4d99422118e8d464ea75d9f013b471f3dd40fd8c..124508d5e36711a13ad49ae289b9de98600e0d6e 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