diff --git a/lsfg-vk-backend/src/lsfgvk.cpp b/lsfg-vk-backend/src/lsfgvk.cpp index 79344a9..9a3f69a 100644 --- a/lsfg-vk-backend/src/lsfgvk.cpp +++ b/lsfg-vk-backend/src/lsfgvk.cpp @@ -7,6 +7,7 @@ #include "lsfg-vk-common/helpers/pointers.hpp" #include "lsfg-vk-common/vulkan/buffer.hpp" #include "lsfg-vk-common/vulkan/command_buffer.hpp" +#include "lsfg-vk-common/vulkan/fence.hpp" #include "lsfg-vk-common/vulkan/image.hpp" #include "lsfg-vk-common/vulkan/timeline_semaphore.hpp" #include "lsfg-vk-common/vulkan/vulkan.hpp" @@ -98,7 +99,7 @@ namespace lsfgvk { size_t fidx{0}; // real frame index std::vector cmdbufs; // TODO: ponder reuse - size_t cmdbuf_idx{0}; + vk::Fence cmdbufFence; ls::Ctx ctx; @@ -377,7 +378,8 @@ ContextImpl::ContextImpl(const InstanceImpl& instance, blackImage(createBlackImage(instance.getVulkan())), syncSemaphore(importTimelineSemaphore(instance.getVulkan(), syncFd)), prepassSemaphore(createPrepassSemaphore(instance.getVulkan())), - cmdbufs(createCommandBuffers(instance.getVulkan(), 16)), + cmdbufs(createCommandBuffers(instance.getVulkan(), destFds.size() + 1)), + cmdbufFence(instance.getVulkan()), ctx(createCtx(instance, extent, hdr, flow, perf, destFds.size())), mipmaps(ctx, sourceImages), alpha0{ @@ -517,8 +519,13 @@ void Instance::scheduleFrames(Context& context) { } void Context::scheduleFrames() { + // wait for previous pre-pass to complete + if (this->fidx && !this->cmdbufFence.wait(this->ctx.vk)) + throw lsfgvk::error("Timeout waiting for previous frame to complete"); + this->cmdbufFence.reset(this->ctx.vk); + // schedule pre-pass - vk::CommandBuffer& cmdbuf = this->cmdbufs.at(this->cmdbuf_idx++ % this->cmdbufs.size()); + vk::CommandBuffer& cmdbuf = this->cmdbufs.at(0); cmdbuf = vk::CommandBuffer(this->ctx.vk); this->mipmaps.render(ctx.vk, cmdbuf, this->fidx); @@ -538,7 +545,7 @@ void Context::scheduleFrames() { // schedule main passes for (size_t i = 0; i < this->destImages.size(); i++) { - vk::CommandBuffer& cmdbuf = this->cmdbufs.at(this->cmdbuf_idx++ % this->cmdbufs.size()); + vk::CommandBuffer& cmdbuf = this->cmdbufs.at(i + 1); cmdbuf = vk::CommandBuffer(this->ctx.vk); const auto& pass = this->passes.at(i); @@ -554,7 +561,8 @@ void Context::scheduleFrames() { cmdbuf.submit(this->ctx.vk, {}, this->prepassSemaphore.handle(), this->idx - 1, - {}, this->syncSemaphore.handle(), this->idx + i + {}, this->syncSemaphore.handle(), this->idx + i, + i == this->destImages.size() - 1 ? this->cmdbufFence.handle() : nullptr ); } diff --git a/lsfg-vk-common/include/lsfg-vk-common/helpers/pointers.hpp b/lsfg-vk-common/include/lsfg-vk-common/helpers/pointers.hpp index d62a456..5471f18 100644 --- a/lsfg-vk-common/include/lsfg-vk-common/helpers/pointers.hpp +++ b/lsfg-vk-common/include/lsfg-vk-common/helpers/pointers.hpp @@ -101,6 +101,11 @@ namespace ls { } owned_ptr& operator=(owned_ptr&& other) noexcept { if (this != &other) { + if (this->ptr) { + if (deleter) deleter(*this->ptr); + delete this->ptr; + } + ptr = other.ptr; other.ptr = nullptr; deleter = std::move(other.deleter); diff --git a/lsfg-vk-common/include/lsfg-vk-common/vulkan/command_buffer.hpp b/lsfg-vk-common/include/lsfg-vk-common/vulkan/command_buffer.hpp index 3b6211b..17a487d 100644 --- a/lsfg-vk-common/include/lsfg-vk-common/vulkan/command_buffer.hpp +++ b/lsfg-vk-common/include/lsfg-vk-common/vulkan/command_buffer.hpp @@ -73,12 +73,14 @@ namespace vk { /// @param signalSemaphores the semaphores to signal /// @param signalTimelineSemaphore the timeline semaphore to signal /// @param signalValue the value to signal + /// @param fence optional fence to signal on completion /// @throws ls::vulkan_error on failure void submit(const vk::Vulkan& vk, std::vector waitSemaphores, VkSemaphore waitTimelineSemaphore, uint64_t waitValue, std::vector signalSemaphores, - VkSemaphore signalTimelineSemaphore, uint64_t signalValue) const; + VkSemaphore signalTimelineSemaphore, uint64_t signalValue, + VkFence fence = nullptr) const; /// submit the command buffer instantly /// @param vk the vulkan instance diff --git a/lsfg-vk-common/src/vulkan/command_buffer.cpp b/lsfg-vk-common/src/vulkan/command_buffer.cpp index 79d1598..47607ad 100644 --- a/lsfg-vk-common/src/vulkan/command_buffer.cpp +++ b/lsfg-vk-common/src/vulkan/command_buffer.cpp @@ -215,7 +215,8 @@ void CommandBuffer::submit(const vk::Vulkan& vk, std::vector waitSemaphores, VkSemaphore waitTimelineSemaphore, uint64_t waitValue, std::vector signalSemaphores, - VkSemaphore signalTimelineSemaphore, uint64_t signalValue) const { + VkSemaphore signalTimelineSemaphore, uint64_t signalValue, + VkFence fence) const { auto res = vk.df().EndCommandBuffer(*this->commandBuffer); if (res != VK_SUCCESS) throw ls::vulkan_error(res, "vkEndCommandBuffer() failed"); @@ -254,7 +255,7 @@ void CommandBuffer::submit(const vk::Vulkan& vk, .signalSemaphoreCount = static_cast(signalSemaphores.size()), .pSignalSemaphores = signalSemaphores.data() }; - res = vk.df().QueueSubmit(vk.queue(), 1, &submitInfo, VK_NULL_HANDLE); + res = vk.df().QueueSubmit(vk.queue(), 1, &submitInfo, fence); if (res != VK_SUCCESS) throw ls::vulkan_error(res, "vkQueueSubmit() failed"); } diff --git a/lsfg-vk-common/src/vulkan/descriptor_set.cpp b/lsfg-vk-common/src/vulkan/descriptor_set.cpp index e787888..45e9f05 100644 --- a/lsfg-vk-common/src/vulkan/descriptor_set.cpp +++ b/lsfg-vk-common/src/vulkan/descriptor_set.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/lsfg-vk-layer/src/context/swapchain.cpp b/lsfg-vk-layer/src/context/swapchain.cpp index 2f3f71a..e9b547b 100644 --- a/lsfg-vk-layer/src/context/swapchain.cpp +++ b/lsfg-vk-layer/src/context/swapchain.cpp @@ -101,17 +101,19 @@ Swapchain::Swapchain(const vk::Vulkan& vk, lsfgvk::Instance& backend, ); this->renderCommandBuffer.emplace(vk); - this->renderSemaphore.emplace(vk, 0); + this->renderFence.emplace(vk); for (size_t i = 0; i < this->destinationImages.size(); i++) { this->passes.emplace_back(RenderPass { .commandBuffer = vk::CommandBuffer(vk), - .acquireSemaphore = vk::Semaphore(vk), - .postCopySemaphore = { - vk::Semaphore(vk), - vk::Semaphore(vk) - } + .acquireSemaphore = vk::Semaphore(vk) }); } + for (size_t i = 0; i < this->info.images.size(); i++) { + this->postCopySemaphores.emplace_back( + vk::Semaphore(vk), + vk::Semaphore(vk) + ); + } } VkResult Swapchain::present(const vk::Vulkan& vk, @@ -119,7 +121,7 @@ VkResult Swapchain::present(const vk::Vulkan& vk, void* next_chain, uint32_t imageIdx, const std::vector& semaphores) { const auto& swapchainImage = this->info.images.at(imageIdx); - const auto& sourceImage = this->sourceImages.at(this->fidx++ % 2); + const auto& sourceImage = this->sourceImages.at(this->fidx % 2); // schedule frame generation this->instance.get().scheduleFrames(this->ctx.get()); @@ -142,8 +144,9 @@ VkResult Swapchain::present(const vk::Vulkan& vk, } // wait for completion of previous frame - auto no_timeout = this->renderSemaphore->wait(vk, this->idx - 1, 150UL * 1000 * 1000); // 150ms - if (!no_timeout) throw ls::vulkan_error(VK_TIMEOUT, "vkWaitSemaphores() failed"); + if (this->fidx && !this->renderFence->wait(vk, 150UL * 1000 * 1000)) + throw ls::vulkan_error(VK_TIMEOUT, "vkWaitForFences() failed"); + this->renderFence->reset(vk); // copy swapchain image into backend source image auto& cmdbuf = this->renderCommandBuffer.emplace(vk); @@ -180,16 +183,13 @@ VkResult Swapchain::present(const vk::Vulkan& vk, {}, this->syncSemaphore->handle(), this->idx++ ); + uint32_t lastAqImageIdx{}; for (size_t i = 0; i < this->destinationImages.size(); i++) { auto& destinationImage = this->destinationImages.at(i); auto& pass = this->passes.at(i); pass = RenderPass { .commandBuffer = vk::CommandBuffer(vk), - .acquireSemaphore = vk::Semaphore(vk), - .postCopySemaphore = { - vk::Semaphore(vk), - vk::Semaphore(vk) - } + .acquireSemaphore = vk::Semaphore(vk) }; // acquire swapchain image @@ -204,6 +204,13 @@ VkResult Swapchain::present(const vk::Vulkan& vk, const auto& aquiredSwapchainImage = this->info.images.at(aqImageIdx); + // create post-copy semaphores + auto& postCopySemaphores = this->postCopySemaphores.at(aqImageIdx); + postCopySemaphores = { + vk::Semaphore(vk), + vk::Semaphore(vk) + }; + // copy backend destination image into swapchain image auto& cmdbuf = pass.commandBuffer; @@ -236,18 +243,19 @@ VkResult Swapchain::present(const vk::Vulkan& vk, std::vector waitSemaphores{ pass.acquireSemaphore.handle() }; if (i) { // non-first pass - const auto& prevPass = this->passes.at(i - 1); - waitSemaphores.push_back(prevPass.postCopySemaphore.second.handle()); + const auto& prevPCS = this->postCopySemaphores.at(lastAqImageIdx); + waitSemaphores.push_back(prevPCS.second.handle()); } const std::vector signalSemaphores{ - pass.postCopySemaphore.first.handle(), - pass.postCopySemaphore.second.handle() + postCopySemaphores.first.handle(), + postCopySemaphores.second.handle() }; cmdbuf.submit(vk, waitSemaphores, this->syncSemaphore->handle(), this->idx, - signalSemaphores, this->renderSemaphore->handle(), this->idx + signalSemaphores, nullptr, 0, + i == this->destinationImages.size() - 1 ? this->renderFence->handle() : nullptr ); // present swapchain image @@ -255,7 +263,7 @@ VkResult Swapchain::present(const vk::Vulkan& vk, .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = i ? nullptr : next_chain, .waitSemaphoreCount = 1, - .pWaitSemaphores = &pass.postCopySemaphore.first.handle(), + .pWaitSemaphores = &postCopySemaphores.first.handle(), .swapchainCount = 1, .pSwapchains = &swapchain, .pImageIndices = &aqImageIdx, @@ -265,15 +273,16 @@ VkResult Swapchain::present(const vk::Vulkan& vk, if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR) throw ls::vulkan_error(res, "vkQueuePresentKHR() failed"); + lastAqImageIdx = aqImageIdx; this->idx++; } // present original swapchain image - const auto& lastPass = this->passes.at(this->destinationImages.size() - 1); + auto& lastPCS = this->postCopySemaphores.at(lastAqImageIdx); const VkPresentInfoKHR presentInfo{ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .waitSemaphoreCount = 1, - .pWaitSemaphores = &lastPass.postCopySemaphore.second.handle(), + .pWaitSemaphores = &lastPCS.second.handle(), .swapchainCount = 1, .pSwapchains = &swapchain, .pImageIndices = &imageIdx, @@ -282,5 +291,8 @@ VkResult Swapchain::present(const vk::Vulkan& vk, if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR) throw ls::vulkan_error(res, "vkQueuePresentKHR() failed"); + this->postCopySemaphores.at(imageIdx).second = std::move(lastPCS.second); + + this->fidx++; return res; } diff --git a/lsfg-vk-layer/src/context/swapchain.hpp b/lsfg-vk-layer/src/context/swapchain.hpp index e9eaf51..82e7390 100644 --- a/lsfg-vk-layer/src/context/swapchain.hpp +++ b/lsfg-vk-layer/src/context/swapchain.hpp @@ -4,6 +4,7 @@ #include "lsfg-vk-backend/lsfgvk.hpp" #include "lsfg-vk-common/helpers/pointers.hpp" #include "lsfg-vk-common/vulkan/command_buffer.hpp" +#include "lsfg-vk-common/vulkan/fence.hpp" #include "lsfg-vk-common/vulkan/image.hpp" #include "lsfg-vk-common/vulkan/semaphore.hpp" #include "lsfg-vk-common/vulkan/timeline_semaphore.hpp" @@ -11,6 +12,7 @@ #include #include +#include #include #include @@ -61,13 +63,13 @@ namespace lsfgvk::layer { ls::lazy syncSemaphore; std::optional renderCommandBuffer; - ls::lazy renderSemaphore; + ls::lazy renderFence; struct RenderPass { vk::CommandBuffer commandBuffer; vk::Semaphore acquireSemaphore; - std::pair postCopySemaphore; }; std::vector passes; + std::vector> postCopySemaphores; ls::R instance; ls::owned_ptr> ctx;