diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index 79023df89..617584ffd 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -276,10 +276,6 @@ int main() Nz::UInt32 imageCount = vulkanWindow.GetFramebufferCount(); std::vector renderCmds = cmdPool.AllocateCommandBuffers(imageCount, VK_COMMAND_BUFFER_LEVEL_PRIMARY); - std::vector fences(imageCount); - for (auto& fence : fences) - fence.Create(vulkanDevice.shared_from_this()); - for (Nz::UInt32 i = 0; i < imageCount; ++i) { Nz::Vk::CommandBuffer& renderCmd = renderCmds[i]; @@ -325,8 +321,6 @@ int main() renderCmd.Begin(); - vulkanWindow.BuildPreRenderCommands(i, renderCmd); - renderCmd.BeginRenderPass(render_pass_begin_info); //renderCmd.ClearAttachment(clearAttachment, clearRect); //renderCmd.ClearAttachment(clearAttachmentDepth, clearRect); @@ -339,8 +333,6 @@ int main() renderCmd.DrawIndexed(drfreakIB->GetIndexCount()); renderCmd.EndRenderPass(); - vulkanWindow.BuildPostRenderCommands(i, renderCmd); - if (!renderCmd.End()) { NazaraError("Failed to specify render cmd"); @@ -355,6 +347,31 @@ int main() window.EnableEventPolling(true); + struct ImageSync + { + Nz::Vk::Fence inflightFence; + Nz::Vk::Semaphore imageAvailableSemaphore; + Nz::Vk::Semaphore renderFinishedSemaphore; + }; + + const std::size_t MaxConcurrentImage = imageCount; + + std::vector frameSync(MaxConcurrentImage); + for (ImageSync& syncData : frameSync) + { + syncData.imageAvailableSemaphore.Create(vulkanDevice.shared_from_this()); + syncData.renderFinishedSemaphore.Create(vulkanDevice.shared_from_this()); + + syncData.inflightFence.Create(vulkanDevice.shared_from_this(), VK_FENCE_CREATE_SIGNALED_BIT); + } + + /*std::vector> imageFences; + for (std::size_t i = 0; i < imageCount; ++i) + imageFences.emplace_back(sync[i % sync.size()].inflightFence);*/ + std::vector inflightFences(imageCount, nullptr); + + std::size_t currentFrame = 0; + Nz::Clock updateClock; Nz::Clock secondClock; unsigned int fps = 0; @@ -425,36 +442,26 @@ int main() } } + ImageSync& syncPrimitives = frameSync[currentFrame]; + syncPrimitives.inflightFence.Wait(); + Nz::UInt32 imageIndex; - if (!vulkanWindow.Acquire(&imageIndex)) + if (!vulkanWindow.Acquire(&imageIndex, syncPrimitives.imageAvailableSemaphore)) { std::cout << "Failed to acquire next image" << std::endl; return EXIT_FAILURE; } - fences[imageIndex].Wait(); - fences[imageIndex].Reset(); + if (inflightFences[imageIndex]) + inflightFences[imageIndex]->Wait(); - VkCommandBuffer renderCmdBuffer = renderCmds[imageIndex]; - VkSemaphore waitSemaphore = vulkanWindow.GetRenderSemaphore(); + inflightFences[imageIndex] = &syncPrimitives.inflightFence; + inflightFences[imageIndex]->Reset(); - VkPipelineStageFlags wait_dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkSubmitInfo submit_info = { - VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType - nullptr, // const void *pNext - 1U, // uint32_t waitSemaphoreCount - &waitSemaphore, // const VkSemaphore *pWaitSemaphores - &wait_dst_stage_mask, // const VkPipelineStageFlags *pWaitDstStageMask; - 1, // uint32_t commandBufferCount - &renderCmdBuffer, // const VkCommandBuffer *pCommandBuffers - 0, // uint32_t signalSemaphoreCount - nullptr // const VkSemaphore *pSignalSemaphores - }; - - if (!graphicsQueue.Submit(submit_info, fences[imageIndex])) + if (!graphicsQueue.Submit(renderCmds[imageIndex], syncPrimitives.imageAvailableSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, syncPrimitives.renderFinishedSemaphore, syncPrimitives.inflightFence)) return false; - vulkanWindow.Present(imageIndex); + vulkanWindow.Present(imageIndex, syncPrimitives.renderFinishedSemaphore); // On incrémente le compteur de FPS improvisé fps++; @@ -477,6 +484,8 @@ int main() // Et on relance l'horloge pour refaire ça dans une seconde secondClock.Restart(); } + + currentFrame = (currentFrame + 1) % imageCount; } instance.vkDestroyDebugReportCallbackEXT(instance, callback, nullptr); diff --git a/include/Nazara/VulkanRenderer/VkRenderTarget.hpp b/include/Nazara/VulkanRenderer/VkRenderTarget.hpp index f997dda00..c98580e67 100644 --- a/include/Nazara/VulkanRenderer/VkRenderTarget.hpp +++ b/include/Nazara/VulkanRenderer/VkRenderTarget.hpp @@ -26,19 +26,14 @@ namespace Nz VkRenderTarget(VkRenderTarget&&) = delete; ///TOOD? virtual ~VkRenderTarget(); - virtual bool Acquire(UInt32* imageIndex) const = 0; - - virtual void BuildPreRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer) = 0; - virtual void BuildPostRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer) = 0; + virtual bool Acquire(UInt32* imageIndex, VkSemaphore signalSemaphore = VK_NULL_HANDLE, VkFence signalFence = VK_NULL_HANDLE) const = 0; virtual const Vk::Framebuffer& GetFrameBuffer(UInt32 imageIndex) const = 0; virtual UInt32 GetFramebufferCount() const = 0; - const Vk::RenderPass& GetRenderPass() const { return m_renderPass; } + inline const Vk::RenderPass& GetRenderPass() const; - const Vk::Semaphore& GetRenderSemaphore() const { return m_imageReadySemaphore; } - - virtual void Present(UInt32 imageIndex) = 0; + virtual void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE) = 0; VkRenderTarget& operator=(const VkRenderTarget&) = delete; VkRenderTarget& operator=(VkRenderTarget&&) = delete; ///TOOD? @@ -51,8 +46,9 @@ namespace Nz void Destroy(); Vk::RenderPass m_renderPass; - Vk::Semaphore m_imageReadySemaphore; }; } +#include + #endif // NAZARA_VULKANRENDERER_RENDERTARGET_HPP diff --git a/include/Nazara/VulkanRenderer/VkRenderTarget.inl b/include/Nazara/VulkanRenderer/VkRenderTarget.inl new file mode 100644 index 000000000..1fd0550bc --- /dev/null +++ b/include/Nazara/VulkanRenderer/VkRenderTarget.inl @@ -0,0 +1,16 @@ +// Copyright (C) 2016 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline const Vk::RenderPass& VkRenderTarget::GetRenderPass() const + { + return m_renderPass; + } +} + +#include diff --git a/include/Nazara/VulkanRenderer/VkRenderWindow.hpp b/include/Nazara/VulkanRenderer/VkRenderWindow.hpp index 1ed643149..e972b2c86 100644 --- a/include/Nazara/VulkanRenderer/VkRenderWindow.hpp +++ b/include/Nazara/VulkanRenderer/VkRenderWindow.hpp @@ -37,10 +37,7 @@ namespace Nz VkRenderWindow(VkRenderWindow&&) = delete; ///TODO virtual ~VkRenderWindow(); - bool Acquire(UInt32* index) const override; - - void BuildPreRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer) override; - void BuildPostRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer) override; + bool Acquire(UInt32* index, VkSemaphore signalSemaphore = VK_NULL_HANDLE, VkFence signalFence = VK_NULL_HANDLE) const override; bool Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) override; @@ -53,7 +50,7 @@ namespace Nz std::shared_ptr GetRenderDevice() override; - void Present(UInt32 imageIndex) override; + void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE) override; VkRenderWindow& operator=(const VkRenderWindow&) = delete; VkRenderWindow& operator=(VkRenderWindow&&) = delete; ///TODO diff --git a/include/Nazara/VulkanRenderer/VkRenderWindow.inl b/include/Nazara/VulkanRenderer/VkRenderWindow.inl index 11310e89b..8c4737578 100644 --- a/include/Nazara/VulkanRenderer/VkRenderWindow.inl +++ b/include/Nazara/VulkanRenderer/VkRenderWindow.inl @@ -42,11 +42,11 @@ namespace Nz return m_device; } - inline void VkRenderWindow::Present(UInt32 imageIndex) + inline void VkRenderWindow::Present(UInt32 imageIndex, VkSemaphore waitSemaphore) { NazaraAssert(imageIndex < m_frameBuffers.size(), "Invalid image index"); - m_presentQueue.Present(m_swapchain, imageIndex); + m_presentQueue.Present(m_swapchain, imageIndex, waitSemaphore); } } diff --git a/include/Nazara/VulkanRenderer/Wrapper/Queue.hpp b/include/Nazara/VulkanRenderer/Wrapper/Queue.hpp index 7b3e0436b..a4129e4d0 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/Queue.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/Queue.hpp @@ -30,8 +30,10 @@ namespace Nz inline bool Present(const VkPresentInfoKHR& presentInfo) const; inline bool Present(VkSwapchainKHR swapchain, UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE) const; - inline bool Submit(const VkSubmitInfo& submit, VkFence fence = VK_NULL_HANDLE) const; - inline bool Submit(UInt32 submitCount, const VkSubmitInfo* submits, VkFence fence = VK_NULL_HANDLE) const; + inline bool Submit(VkCommandBuffer commandBuffer, VkSemaphore waitSemaphore, VkPipelineStageFlags waitStage, VkSemaphore signalSemaphore, VkFence signalFence = VK_NULL_HANDLE) const; + inline bool Submit(UInt32 commandBufferCount, const VkCommandBuffer* commandBuffers, VkSemaphore waitSemaphore, VkPipelineStageFlags waitStage, VkSemaphore signalSemaphore, VkFence signalFence = VK_NULL_HANDLE) const; + inline bool Submit(const VkSubmitInfo& submit, VkFence signalFence = VK_NULL_HANDLE) const; + inline bool Submit(UInt32 submitCount, const VkSubmitInfo* submits, VkFence signalFence = VK_NULL_HANDLE) const; inline bool WaitIdle() const; diff --git a/include/Nazara/VulkanRenderer/Wrapper/Queue.inl b/include/Nazara/VulkanRenderer/Wrapper/Queue.inl index 63583e66e..dc8603465 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/Queue.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/Queue.inl @@ -76,14 +76,36 @@ namespace Nz return Present(presentInfo); } - inline bool Queue::Submit(const VkSubmitInfo& submit, VkFence fence) const + inline bool Queue::Submit(VkCommandBuffer commandBuffer, VkSemaphore waitSemaphore, VkPipelineStageFlags waitStage, VkSemaphore signalSemaphore, VkFence signalFence) const { - return Submit(1, &submit, fence); + return Submit(1U, &commandBuffer, waitSemaphore, waitStage, signalSemaphore, signalFence); } - inline bool Queue::Submit(UInt32 submitCount, const VkSubmitInfo* submits, VkFence fence) const + inline bool Queue::Submit(UInt32 commandBufferCount, const VkCommandBuffer* commandBuffers, VkSemaphore waitSemaphore, VkPipelineStageFlags waitStage, VkSemaphore signalSemaphore, VkFence signalFence) const { - m_lastErrorCode = m_device->vkQueueSubmit(m_handle, submitCount, submits, fence); + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, + nullptr, + (waitSemaphore) ? 1U : 0U, + &waitSemaphore, + &waitStage, + commandBufferCount, + commandBuffers, + (signalSemaphore) ? 1U : 0U, + &signalSemaphore + }; + + return Submit(submitInfo, signalFence); + } + + inline bool Queue::Submit(const VkSubmitInfo& submit, VkFence signalFence) const + { + return Submit(1, &submit, signalFence); + } + + inline bool Queue::Submit(UInt32 submitCount, const VkSubmitInfo* submits, VkFence signalFence) const + { + m_lastErrorCode = m_device->vkQueueSubmit(m_handle, submitCount, submits, signalFence); if (m_lastErrorCode != VkResult::VK_SUCCESS) { NazaraError("Failed to submit queue: " + TranslateVulkanError(m_lastErrorCode)); diff --git a/src/Nazara/VulkanRenderer/VkRenderTarget.cpp b/src/Nazara/VulkanRenderer/VkRenderTarget.cpp index 27e1f5ff1..a553a2c1e 100644 --- a/src/Nazara/VulkanRenderer/VkRenderTarget.cpp +++ b/src/Nazara/VulkanRenderer/VkRenderTarget.cpp @@ -15,6 +15,5 @@ namespace Nz void VkRenderTarget::Destroy() { m_renderPass.Destroy(); - m_imageReadySemaphore.Destroy(); } } diff --git a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp index f1822b227..6edaa6649 100644 --- a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp +++ b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp @@ -32,9 +32,9 @@ namespace Nz VkRenderTarget::Destroy(); } - bool VkRenderWindow::Acquire(UInt32* imageIndex) const + bool VkRenderWindow::Acquire(UInt32* imageIndex, VkSemaphore signalSemaphore, VkFence signalFence) const { - if (!m_swapchain.AcquireNextImage(std::numeric_limits::max(), m_imageReadySemaphore, VK_NULL_HANDLE, imageIndex)) + if (!m_swapchain.AcquireNextImage(std::numeric_limits::max(), signalSemaphore, signalFence, imageIndex)) { NazaraError("Failed to acquire next image"); return false; @@ -43,30 +43,6 @@ namespace Nz return true; } - void VkRenderWindow::BuildPreRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer) - { - //commandBuffer.SetImageLayout(m_swapchain.GetBuffer(imageIndex).image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Temporary - /*if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) - { - VkImageSubresourceRange imageRange = { - VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags aspectMask - 0, // uint32_t baseMipLevel - 1, // uint32_t levelCount - 0, // uint32_t baseArrayLayer - 1 // uint32_t layerCount - }; - - commandBuffer.SetImageLayout(m_depthBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, imageRange); - }*/ - } - - void VkRenderWindow::BuildPostRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer) - { - //commandBuffer.SetImageLayout(m_swapchain.GetBuffer(imageIndex).image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - } - bool VkRenderWindow::Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) { m_physicalDevice = Vulkan::GetPhysicalDevices()[0].device; @@ -194,8 +170,6 @@ namespace Nz } } - m_imageReadySemaphore.Create(m_device); - m_clock.Restart(); return true;