diff --git a/shadowmappingomni/shadowmappingomni.cpp b/shadowmappingomni/shadowmappingomni.cpp index cdea83e8..6a79cf1c 100644 --- a/shadowmappingomni/shadowmappingomni.cpp +++ b/shadowmappingomni/shadowmappingomni.cpp @@ -121,6 +121,9 @@ public: VkCommandBuffer offScreenCmdBuffer = VK_NULL_HANDLE; VkFormat fbDepthFormat; + // Semaphore used to synchronize offscreen rendering before using it's texture target for sampling + VkSemaphore offscreenSemaphore = VK_NULL_HANDLE; + VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { zoom = -175.0f; @@ -177,6 +180,7 @@ public: vkTools::destroyUniformData(device, &uniformData.scene); vkFreeCommandBuffers(device, cmdPool, 1, &offScreenCmdBuffer); + vkDestroySemaphore(device, offscreenSemaphore, nullptr); } void prepareCubeMap() @@ -487,33 +491,23 @@ public: // Command buffer for rendering and copying all cube map faces void buildOffscreenCommandBuffer() { - // Create separate command buffer for offscreen - // rendering if (offScreenCmdBuffer == VK_NULL_HANDLE) { - VkCommandBufferAllocateInfo cmd = vkTools::initializers::commandBufferAllocateInfo( - cmdPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - 1); - VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmd, &offScreenCmdBuffer)); + 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(); VK_CHECK_RESULT(vkBeginCommandBuffer(offScreenCmdBuffer, &cmdBufInfo)); - VkViewport viewport = vkTools::initializers::viewport( - (float)offScreenFrameBuf.width, - (float)offScreenFrameBuf.height, - 0.0f, - 1.0f); + VkViewport viewport = vkTools::initializers::viewport((float)offScreenFrameBuf.width, (float)offScreenFrameBuf.height, 0.0f, 1.0f); vkCmdSetViewport(offScreenCmdBuffer, 0, 1, &viewport); - VkRect2D scissor = vkTools::initializers::rect2D( - offScreenFrameBuf.width, - offScreenFrameBuf.height, - 0, - 0); + VkRect2D scissor = vkTools::initializers::rect2D(offScreenFrameBuf.width, offScreenFrameBuf.height, 0, 0); vkCmdSetScissor(offScreenCmdBuffer, 0, 1, &scissor); VkImageSubresourceRange subresourceRange = {}; @@ -1003,16 +997,32 @@ 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 (and transfer) to be finished before using + // the shadow map, so we need to synchronize + // We use an additional semaphore for this + // 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();