From b9bf2bca85292188a8f27dfaab081ef1f28b23fe Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 11 May 2019 12:16:28 +0200 Subject: [PATCH] Replace dedicated offscreen command buffer and complicated synchronization with single command buffer and sync via sub pass dependencies --- examples/hdr/hdr.cpp | 277 ++++++++++++++++++++----------------------- 1 file changed, 128 insertions(+), 149 deletions(-) diff --git a/examples/hdr/hdr.cpp b/examples/hdr/hdr.cpp index 4b712a13..d1f10c0d 100644 --- a/examples/hdr/hdr.cpp +++ b/examples/hdr/hdr.cpp @@ -1,9 +1,9 @@ /* -* Vulkan Example - HDR +* Vulkan Example - High dynamic range rendering * * Note: Requires the separate asset pack (see data/README.md) * -* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de +* Copyright by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ @@ -112,8 +112,6 @@ public: FrameBufferAttachment depth; VkRenderPass renderPass; VkSampler sampler; - VkCommandBuffer cmdBuffer = VK_NULL_HANDLE; - VkSemaphore semaphore = VK_NULL_HANDLE; } offscreen; struct { @@ -152,8 +150,6 @@ public: vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.composition, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.bloomFilter, nullptr); - vkDestroySemaphore(device, offscreen.semaphore, nullptr); - vkDestroyRenderPass(device, offscreen.renderPass, nullptr); vkDestroyRenderPass(device, filterPass.renderPass, nullptr); @@ -178,17 +174,6 @@ public: textures.envmap.destroy(); } - void reBuildCommandBuffers() - { - if (!checkCommandBuffers()) - { - destroyCommandBuffers(); - createCommandBuffers(); - } - buildCommandBuffers(); - buildDeferredCommandBuffer(); - } - void buildCommandBuffers() { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); @@ -209,62 +194,134 @@ public: for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { - VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); - // Bloom filter - renderPassBeginInfo.framebuffer = filterPass.frameBuffer; - renderPassBeginInfo.renderPass = filterPass.renderPass; - renderPassBeginInfo.clearValueCount = 1; - renderPassBeginInfo.renderArea.extent.width = filterPass.width; - renderPassBeginInfo.renderArea.extent.height = filterPass.height; - - viewport = vks::initializers::viewport((float)filterPass.width, (float)filterPass.height, 0.0f, 1.0f); - scissor = vks::initializers::rect2D(filterPass.width, filterPass.height, 0, 0); - - vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); - vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); - - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.bloomFilter, 0, 1, &descriptorSets.bloomFilter, 0, NULL); - - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.bloom[1]); - vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); - - vkCmdEndRenderPass(drawCmdBuffers[i]); - - viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); - scissor = vks::initializers::rect2D(width, height, 0, 0); - - // Final composition - renderPassBeginInfo.framebuffer = frameBuffers[i]; - renderPassBeginInfo.renderPass = renderPass; - renderPassBeginInfo.clearValueCount = 2; - renderPassBeginInfo.renderArea.extent.width = width; - renderPassBeginInfo.renderArea.extent.height = height; - - vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); - vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); - - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.composition, 0, 1, &descriptorSets.composition, 0, NULL); - - // Scene - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.composition); - vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); - - // Bloom - if (bloom) { - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.bloom[0]); - vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); + /* + First pass: Render scene to offscreen framebuffer + */ + + std::array clearValues; + clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; + clearValues[1].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; + clearValues[2].depthStencil = { 1.0f, 0 }; + + VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); + renderPassBeginInfo.renderPass = offscreen.renderPass; + renderPassBeginInfo.framebuffer = offscreen.frameBuffer; + renderPassBeginInfo.renderArea.extent.width = offscreen.width; + renderPassBeginInfo.renderArea.extent.height = offscreen.height; + renderPassBeginInfo.clearValueCount = 3; + renderPassBeginInfo.pClearValues = clearValues.data(); + + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = vks::initializers::viewport((float)offscreen.width, (float)offscreen.height, 0.0f, 1.0f); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + + VkRect2D scissor = vks::initializers::rect2D(offscreen.width, offscreen.height, 0, 0); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + + VkDeviceSize offsets[1] = { 0 }; + + // Skybox + if (displaySkybox) + { + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.models, 0, 1, &descriptorSets.skybox, 0, NULL); + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.skybox.vertices.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], models.skybox.indices.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox); + vkCmdDrawIndexed(drawCmdBuffers[i], models.skybox.indexCount, 1, 0, 0, 0); + } + + // 3D object + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.models, 0, 1, &descriptorSets.object, 0, NULL); + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.objects[models.objectIndex].vertices.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], models.objects[models.objectIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.reflect); + vkCmdDrawIndexed(drawCmdBuffers[i], models.objects[models.objectIndex].indexCount, 1, 0, 0, 0); + + vkCmdEndRenderPass(drawCmdBuffers[i]); } - drawUI(drawCmdBuffers[i]); + /* + Second render pass: First bloom pass + */ + if (bloom) { + VkClearValue clearValues[2]; + clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; + clearValues[1].depthStencil = { 1.0f, 0 }; - vkCmdEndRenderPass(drawCmdBuffers[i]); + // Bloom filter + VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); + renderPassBeginInfo.framebuffer = filterPass.frameBuffer; + renderPassBeginInfo.renderPass = filterPass.renderPass; + renderPassBeginInfo.clearValueCount = 1; + renderPassBeginInfo.renderArea.extent.width = filterPass.width; + renderPassBeginInfo.renderArea.extent.height = filterPass.height; + renderPassBeginInfo.pClearValues = clearValues; + + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = vks::initializers::viewport((float)filterPass.width, (float)filterPass.height, 0.0f, 1.0f); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + + VkRect2D scissor = vks::initializers::rect2D(filterPass.width, filterPass.height, 0, 0); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.bloomFilter, 0, 1, &descriptorSets.bloomFilter, 0, NULL); + + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.bloom[1]); + vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); + + vkCmdEndRenderPass(drawCmdBuffers[i]); + } + + /* + Note: Explicit synchronization is not required between the render pass, as this is done implicit via sub pass dependencies + */ + + /* + Third render pass: Scene rendering with applied second bloom pass (when enabled) + */ + { + VkClearValue clearValues[2]; + clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; + clearValues[1].depthStencil = { 1.0f, 0 }; + + // Final composition + VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); + renderPassBeginInfo.framebuffer = frameBuffers[i]; + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.clearValueCount = 2; + renderPassBeginInfo.renderArea.extent.width = width; + renderPassBeginInfo.renderArea.extent.height = height; + renderPassBeginInfo.pClearValues = clearValues; + + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + + VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.composition, 0, 1, &descriptorSets.composition, 0, NULL); + + // Scene + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.composition); + vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); + + // Bloom + if (bloom) { + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.bloom[0]); + vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); + } + + drawUI(drawCmdBuffers[i]); + + vkCmdEndRenderPass(drawCmdBuffers[i]); + } VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } @@ -536,71 +593,6 @@ public: } } - // Build command buffer for rendering the scene to the offscreen frame buffer attachments - void buildDeferredCommandBuffer() - { - if (offscreen.cmdBuffer == VK_NULL_HANDLE) - { - offscreen.cmdBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); - } - - // Create a semaphore used to synchronize offscreen rendering and usage - if (offscreen.semaphore == VK_NULL_HANDLE) - { - VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); - VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &offscreen.semaphore)); - } - - VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); - - // Clear values for all attachments written in the fragment sahder - std::array clearValues; - clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; - clearValues[1].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; - clearValues[2].depthStencil = { 1.0f, 0 }; - - VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); - renderPassBeginInfo.renderPass = offscreen.renderPass; - renderPassBeginInfo.framebuffer = offscreen.frameBuffer; - renderPassBeginInfo.renderArea.extent.width = offscreen.width; - renderPassBeginInfo.renderArea.extent.height = offscreen.height; - renderPassBeginInfo.clearValueCount = 3; - renderPassBeginInfo.pClearValues = clearValues.data(); - - VK_CHECK_RESULT(vkBeginCommandBuffer(offscreen.cmdBuffer, &cmdBufInfo)); - - vkCmdBeginRenderPass(offscreen.cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - VkViewport viewport = vks::initializers::viewport((float)offscreen.width, (float)offscreen.height, 0.0f, 1.0f); - vkCmdSetViewport(offscreen.cmdBuffer, 0, 1, &viewport); - - VkRect2D scissor = vks::initializers::rect2D(offscreen.width, offscreen.height, 0, 0); - vkCmdSetScissor(offscreen.cmdBuffer, 0, 1, &scissor); - - VkDeviceSize offsets[1] = { 0 }; - - // Skybox - if (displaySkybox) - { - vkCmdBindDescriptorSets(offscreen.cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.models, 0, 1, &descriptorSets.skybox, 0, NULL); - vkCmdBindVertexBuffers(offscreen.cmdBuffer, 0, 1, &models.skybox.vertices.buffer, offsets); - vkCmdBindIndexBuffer(offscreen.cmdBuffer, models.skybox.indices.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdBindPipeline(offscreen.cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox); - vkCmdDrawIndexed(offscreen.cmdBuffer, models.skybox.indexCount, 1, 0, 0, 0); - } - - // 3D object - vkCmdBindDescriptorSets(offscreen.cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.models, 0, 1, &descriptorSets.object, 0, NULL); - vkCmdBindVertexBuffers(offscreen.cmdBuffer, 0, 1, &models.objects[models.objectIndex].vertices.buffer, offsets); - vkCmdBindIndexBuffer(offscreen.cmdBuffer, models.objects[models.objectIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdBindPipeline(offscreen.cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.reflect); - vkCmdDrawIndexed(offscreen.cmdBuffer, models.objects[models.objectIndex].indexCount, 1, 0, 0, 0); - - vkCmdEndRenderPass(offscreen.cmdBuffer); - - VK_CHECK_RESULT(vkEndCommandBuffer(offscreen.cmdBuffer)); - } - void loadAssets() { // Models @@ -943,18 +935,9 @@ public: void draw() { VulkanExampleBase::prepareFrame(); - - submitInfo.pWaitSemaphores = &semaphores.presentComplete; - submitInfo.pSignalSemaphores = &offscreen.semaphore; submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &offscreen.cmdBuffer; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - - submitInfo.pWaitSemaphores = &offscreen.semaphore; - submitInfo.pSignalSemaphores = &semaphores.renderComplete; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - VulkanExampleBase::submitFrame(); } @@ -969,7 +952,6 @@ public: setupDescriptorPool(); setupDescriptorSets(); buildCommandBuffers(); - buildDeferredCommandBuffer(); prepared = true; } @@ -978,11 +960,8 @@ public: if (!prepared) return; draw(); - } - - virtual void viewChanged() - { - updateUniformBuffers(); + if (camera.updated) + updateUniformBuffers(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) @@ -990,7 +969,7 @@ public: if (overlay->header("Settings")) { if (overlay->comboBox("Object type", &models.objectIndex, objectNames)) { updateUniformBuffers(); - buildDeferredCommandBuffer(); + buildCommandBuffers(); } if (overlay->inputFloat("Exposure", &uboParams.exposure, 0.025f, 3)) { updateParams(); @@ -999,7 +978,7 @@ public: buildCommandBuffers(); } if (overlay->checkBox("Skybox", &displaySkybox)) { - buildDeferredCommandBuffer(); + buildCommandBuffers(); } } }