Replace dedicated offscreen command buffer and complicated synchronization with single command buffer and sync via sub pass dependencies

This commit is contained in:
Sascha Willems 2019-05-11 12:16:28 +02:00
parent 3ff0da9aa8
commit b9bf2bca85

View file

@ -1,9 +1,9 @@
/* /*
* Vulkan Example - HDR * Vulkan Example - High dynamic range rendering
* *
* Note: Requires the separate asset pack (see data/README.md) * 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) * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/ */
@ -112,8 +112,6 @@ public:
FrameBufferAttachment depth; FrameBufferAttachment depth;
VkRenderPass renderPass; VkRenderPass renderPass;
VkSampler sampler; VkSampler sampler;
VkCommandBuffer cmdBuffer = VK_NULL_HANDLE;
VkSemaphore semaphore = VK_NULL_HANDLE;
} offscreen; } offscreen;
struct { struct {
@ -152,8 +150,6 @@ public:
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.composition, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.composition, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.bloomFilter, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.bloomFilter, nullptr);
vkDestroySemaphore(device, offscreen.semaphore, nullptr);
vkDestroyRenderPass(device, offscreen.renderPass, nullptr); vkDestroyRenderPass(device, offscreen.renderPass, nullptr);
vkDestroyRenderPass(device, filterPass.renderPass, nullptr); vkDestroyRenderPass(device, filterPass.renderPass, nullptr);
@ -178,17 +174,6 @@ public:
textures.envmap.destroy(); textures.envmap.destroy();
} }
void reBuildCommandBuffers()
{
if (!checkCommandBuffers())
{
destroyCommandBuffers();
createCommandBuffers();
}
buildCommandBuffers();
buildDeferredCommandBuffer();
}
void buildCommandBuffers() void buildCommandBuffers()
{ {
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
@ -209,62 +194,134 @@ public:
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
{ {
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); 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<VkClearValue, 3> 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])); 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<VkClearValue, 3> 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() void loadAssets()
{ {
// Models // Models
@ -943,18 +935,9 @@ public:
void draw() void draw()
{ {
VulkanExampleBase::prepareFrame(); VulkanExampleBase::prepareFrame();
submitInfo.pWaitSemaphores = &semaphores.presentComplete;
submitInfo.pSignalSemaphores = &offscreen.semaphore;
submitInfo.commandBufferCount = 1; 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]; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame(); VulkanExampleBase::submitFrame();
} }
@ -969,7 +952,6 @@ public:
setupDescriptorPool(); setupDescriptorPool();
setupDescriptorSets(); setupDescriptorSets();
buildCommandBuffers(); buildCommandBuffers();
buildDeferredCommandBuffer();
prepared = true; prepared = true;
} }
@ -978,11 +960,8 @@ public:
if (!prepared) if (!prepared)
return; return;
draw(); draw();
} if (camera.updated)
updateUniformBuffers();
virtual void viewChanged()
{
updateUniformBuffers();
} }
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
@ -990,7 +969,7 @@ public:
if (overlay->header("Settings")) { if (overlay->header("Settings")) {
if (overlay->comboBox("Object type", &models.objectIndex, objectNames)) { if (overlay->comboBox("Object type", &models.objectIndex, objectNames)) {
updateUniformBuffers(); updateUniformBuffers();
buildDeferredCommandBuffer(); buildCommandBuffers();
} }
if (overlay->inputFloat("Exposure", &uboParams.exposure, 0.025f, 3)) { if (overlay->inputFloat("Exposure", &uboParams.exposure, 0.025f, 3)) {
updateParams(); updateParams();
@ -999,7 +978,7 @@ public:
buildCommandBuffers(); buildCommandBuffers();
} }
if (overlay->checkBox("Skybox", &displaySkybox)) { if (overlay->checkBox("Skybox", &displaySkybox)) {
buildDeferredCommandBuffer(); buildCommandBuffers();
} }
} }
} }