From e6afe5d1befffdb7077e316b575ad408b59c50b9 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Sun, 5 Jun 2016 17:19:24 +0200 Subject: [PATCH] Additional semaphore to synchronize offscreen and final render (Refs #70) --- offscreen/offscreen.cpp | 84 ++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/offscreen/offscreen.cpp b/offscreen/offscreen.cpp index b7121715..c52a3876 100644 --- a/offscreen/offscreen.cpp +++ b/offscreen/offscreen.cpp @@ -119,12 +119,17 @@ public: VkCommandBuffer offScreenCmdBuffer = VK_NULL_HANDLE; + // Semaphore used to synchronize between offscreen and final scene rendering + VkSemaphore offscreenSemaphore = VK_NULL_HANDLE; + glm::vec3 meshPos = glm::vec3(0.0f, -1.5f, 0.0f); + glm::vec3 meshRot = glm::vec3(0.0f); VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { - zoom = -6.5f; - rotation = { -11.25f, 45.0f, 0.0f }; + zoom = -6.0f; + rotation = { -2.5f, 0.0f, 0.0f }; + cameraPos = { 0.0f, 1.0f, 0.0f }; timerSpeed *= 0.25f; enableTextOverlay = true; title = "Vulkan Example - Offscreen rendering"; @@ -176,6 +181,7 @@ public: vkTools::destroyUniformData(device, &uniformData.vsDebugQuad); vkFreeCommandBuffers(device, cmdPool, 1, &offScreenCmdBuffer); + vkDestroySemaphore(device, offscreenSemaphore, nullptr); } // Preapre an empty texture as the blit target from @@ -374,21 +380,18 @@ public: VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offScreenFrameBuf.frameBuffer)); } - void createOffscreenCommandBuffer() - { - VkCommandBufferAllocateInfo cmd = vkTools::initializers::commandBufferAllocateInfo( - cmdPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - 1); - VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmd, &offScreenCmdBuffer)); - } - - // The command buffer to copy for rendering - // the offscreen scene and blitting it into - // the texture target is only build once - // and gets resubmitted + // Sets up the command buffer that renders the scene to the offscreen frame buffer void buildOffscreenCommandBuffer() { + if (offScreenCmdBuffer == VK_NULL_HANDLE) + { + offScreenCmdBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); + } + + // Create a semaphore used to synchronize offscreen rendering and usage + VkSemaphoreCreateInfo semaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo(); + VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &offscreenSemaphore)); + VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); VkClearValue clearValues[2]; @@ -983,7 +986,7 @@ public: ubos.vsShared.model = viewMatrix * glm::translate(glm::mat4(), cameraPos); ubos.vsShared.model = glm::rotate(ubos.vsShared.model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); - ubos.vsShared.model = glm::rotate(ubos.vsShared.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); + ubos.vsShared.model = glm::rotate(ubos.vsShared.model, glm::radians(rotation.y + meshRot.y), glm::vec3(0.0f, 1.0f, 0.0f)); ubos.vsShared.model = glm::rotate(ubos.vsShared.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); ubos.vsShared.model = glm::translate(ubos.vsShared.model, meshPos); @@ -1019,7 +1022,7 @@ public: ubos.vsShared.model = viewMatrix * glm::translate(glm::mat4(), cameraPos); ubos.vsShared.model = glm::rotate(ubos.vsShared.model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); - ubos.vsShared.model = glm::rotate(ubos.vsShared.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); + ubos.vsShared.model = glm::rotate(ubos.vsShared.model, glm::radians(rotation.y + meshRot.y), glm::vec3(0.0f, 1.0f, 0.0f)); ubos.vsShared.model = glm::rotate(ubos.vsShared.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); ubos.vsShared.model = glm::scale(ubos.vsShared.model, glm::vec3(1.0f, -1.0f, 1.0f)); @@ -1035,16 +1038,38 @@ public: { VulkanExampleBase::prepareFrame(); - // Submit offscreen rendering command buffer - // todo : use event to ensure that offscreen result is finished bfore render command buffer is started - std::vector submitCmdBuffers = { - offScreenCmdBuffer, - drawCmdBuffers[currentBuffer], - }; - submitCmdBuffers.push_back(drawCmdBuffers[currentBuffer]); - submitInfo.commandBufferCount = submitCmdBuffers.size(); - submitInfo.pCommandBuffers = submitCmdBuffers.data(); + // The scene render command buffer has to wait for the offscreen + // rendering to be finished before we can use the framebuffer + // color image for sampling during final rendering + // To ensure this we use a dedicated offscreen synchronization + // semaphore that will be signaled when offscreen renderin + // has been finished + // This is necessary as an implementation may start both + // command buffers at the same time, there is no guarantee + // that commnad buffers will be executed in the order they + // have been submitted by the application + // Offscreen rendering + + // Wait for swap chain presentation to finish + submitInfo.pWaitSemaphores = &semaphores.presentComplete; + // Signal ready with offscreen semaphore + submitInfo.pSignalSemaphores = &offscreenSemaphore; + + // Submit work + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &offScreenCmdBuffer; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + + // Scene rendering + + // Wait for offscreen semaphore + submitInfo.pWaitSemaphores = &offscreenSemaphore; + // Signal ready with render complete semaphpre + submitInfo.pSignalSemaphores = &semaphores.renderComplete; + + // Submit work + submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VulkanExampleBase::submitFrame(); @@ -1063,7 +1088,6 @@ public: preparePipelines(); setupDescriptorPool(); setupDescriptorSet(); - createOffscreenCommandBuffer(); prepareOffscreenFramebuffer(); buildCommandBuffers(); buildOffscreenCommandBuffer(); @@ -1075,6 +1099,12 @@ public: if (!prepared) return; draw(); + if (!paused) + { + meshRot.y += frameTimer * 10.0f; + updateUniformBuffers(); + updateUniformBufferOffscreen(); + } } virtual void viewChanged()