From 121612857ca34c7f21894b6b0cfe8ab2546a8210 Mon Sep 17 00:00:00 2001 From: Stephen Saunders Date: Wed, 1 Jun 2022 13:02:33 -0400 Subject: [PATCH] Fixes in examples: support swapchain image count change on resize, fix multiple validation layer errors on resize and quit, multiview now supports resize/fullscreen, computecloth deltaT now based on frame time, multisampling recreates attachments on resize, P key now pauses computeparticles, descriptorsets, and pushdescriptors --- examples/computecloth/computecloth.cpp | 7 ++- examples/computenbody/computenbody.cpp | 44 ++++++------- .../computeparticles/computeparticles.cpp | 46 +++++++------- examples/descriptorsets/descriptorsets.cpp | 6 +- .../inputattachments/inputattachments.cpp | 16 ++++- examples/multisampling/multisampling.cpp | 17 +++++ examples/multiview/multiview.cpp | 62 ++++++++++++++++--- examples/pushdescriptors/pushdescriptors.cpp | 6 +- examples/textoverlay/textoverlay.cpp | 6 +- examples/triangle/triangle.cpp | 3 + 10 files changed, 148 insertions(+), 65 deletions(-) diff --git a/examples/computecloth/computecloth.cpp b/examples/computecloth/computecloth.cpp index b08fd55c..d81567d7 100644 --- a/examples/computecloth/computecloth.cpp +++ b/examples/computecloth/computecloth.cpp @@ -101,6 +101,7 @@ public: ~VulkanExample() { // Graphics + graphics.indices.destroy(); graphics.uniformBuffer.destroy(); vkDestroyPipeline(device, graphics.pipelines.cloth, nullptr); vkDestroyPipeline(device, graphics.pipelines.sphere, nullptr); @@ -670,13 +671,13 @@ public: void updateComputeUBO() { if (!paused) { - compute.ubo.deltaT = 0.000005f; + //compute.ubo.deltaT = 0.000005f; // todo: base on frametime - //compute.ubo.deltaT = frameTimer * 0.0075f; + compute.ubo.deltaT = frameTimer * 0.0015f; if (simulateWind) { std::default_random_engine rndEngine(benchmark.active ? 0 : (unsigned)time(nullptr)); - std::uniform_real_distribution rd(1.0f, 6.0f); + std::uniform_real_distribution rd(1.0f, 30.0f); compute.ubo.gravity.x = cos(glm::radians(-timer * 360.0f)) * (rd(rndEngine) - rd(rndEngine)); compute.ubo.gravity.z = sin(glm::radians(timer * 360.0f)) * (rd(rndEngine) - rd(rndEngine)); } diff --git a/examples/computenbody/computenbody.cpp b/examples/computenbody/computenbody.cpp index 0d9b2a32..9dd01594 100644 --- a/examples/computenbody/computenbody.cpp +++ b/examples/computenbody/computenbody.cpp @@ -620,6 +620,13 @@ public: // Semaphore for compute & graphics sync VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &graphics.semaphore)); + + // Signal the semaphore + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &graphics.semaphore; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VK_CHECK_RESULT(vkQueueWaitIdle(queue)); } void prepareCompute() @@ -736,13 +743,6 @@ public: VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &compute.semaphore)); - // Signal the semaphore - VkSubmitInfo submitInfo = vks::initializers::submitInfo(); - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &compute.semaphore; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - VK_CHECK_RESULT(vkQueueWaitIdle(queue)); - // Build a single command buffer containing the compute dispatch commands buildComputeCommandBuffer(); @@ -841,6 +841,20 @@ public: void draw() { + // Wait for rendering finished + VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + + // Submit compute commands + VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); + computeSubmitInfo.commandBufferCount = 1; + computeSubmitInfo.pCommandBuffers = &compute.commandBuffer; + computeSubmitInfo.waitSemaphoreCount = 1; + computeSubmitInfo.pWaitSemaphores = &graphics.semaphore; + computeSubmitInfo.pWaitDstStageMask = &waitStageMask; + computeSubmitInfo.signalSemaphoreCount = 1; + computeSubmitInfo.pSignalSemaphores = &compute.semaphore; + VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::prepareFrame(); VkPipelineStageFlags graphicsWaitStageMasks[] = { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; @@ -858,20 +872,6 @@ public: VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VulkanExampleBase::submitFrame(); - - // Wait for rendering finished - VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - - // Submit compute commands - VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); - computeSubmitInfo.commandBufferCount = 1; - computeSubmitInfo.pCommandBuffers = &compute.commandBuffer; - computeSubmitInfo.waitSemaphoreCount = 1; - computeSubmitInfo.pWaitSemaphores = &graphics.semaphore; - computeSubmitInfo.pWaitDstStageMask = &waitStageMask; - computeSubmitInfo.signalSemaphoreCount = 1; - computeSubmitInfo.pSignalSemaphores = &compute.semaphore; - VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); } void prepare() @@ -901,4 +901,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/computeparticles/computeparticles.cpp b/examples/computeparticles/computeparticles.cpp index 48bfe07e..7c5b79c8 100644 --- a/examples/computeparticles/computeparticles.cpp +++ b/examples/computeparticles/computeparticles.cpp @@ -86,6 +86,7 @@ public: vkDestroyPipeline(device, graphics.pipeline, nullptr); vkDestroyPipelineLayout(device, graphics.pipelineLayout, nullptr); vkDestroyDescriptorSetLayout(device, graphics.descriptorSetLayout, nullptr); + vkDestroySemaphore(device, graphics.semaphore, nullptr); // Compute compute.storageBuffer.destroy(); @@ -551,6 +552,13 @@ public: // Semaphore for compute & graphics sync VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &graphics.semaphore)); + + // Signal the semaphore + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &graphics.semaphore; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VK_CHECK_RESULT(vkQueueWaitIdle(queue)); } void prepareCompute() @@ -636,13 +644,6 @@ public: VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &compute.semaphore)); - // Signal the semaphore - VkSubmitInfo submitInfo = vks::initializers::submitInfo(); - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &compute.semaphore; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - VK_CHECK_RESULT(vkQueueWaitIdle(queue)); - // Build a single command buffer containing the compute dispatch commands buildComputeCommandBuffer(); @@ -716,7 +717,7 @@ public: void updateUniformBuffers() { - compute.ubo.deltaT = frameTimer * 2.5f; + compute.ubo.deltaT = paused ? 0.0f : frameTimer * 2.5f; if (!attachToCursor) { compute.ubo.destX = sin(glm::radians(timer * 360.0f)) * 0.75f; @@ -735,6 +736,20 @@ public: void draw() { + // Wait for rendering finished + VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + + // Submit compute commands + VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); + computeSubmitInfo.commandBufferCount = 1; + computeSubmitInfo.pCommandBuffers = &compute.commandBuffer; + computeSubmitInfo.waitSemaphoreCount = 1; + computeSubmitInfo.pWaitSemaphores = &graphics.semaphore; + computeSubmitInfo.pWaitDstStageMask = &waitStageMask; + computeSubmitInfo.signalSemaphoreCount = 1; + computeSubmitInfo.pSignalSemaphores = &compute.semaphore; + VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::prepareFrame(); VkPipelineStageFlags graphicsWaitStageMasks[] = { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; @@ -752,21 +767,6 @@ public: VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VulkanExampleBase::submitFrame(); - - // Wait for rendering finished - VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - - // Submit compute commands - VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); - computeSubmitInfo.commandBufferCount = 1; - computeSubmitInfo.pCommandBuffers = &compute.commandBuffer; - computeSubmitInfo.waitSemaphoreCount = 1; - computeSubmitInfo.pWaitSemaphores = &graphics.semaphore; - computeSubmitInfo.pWaitDstStageMask = &waitStageMask; - computeSubmitInfo.signalSemaphoreCount = 1; - computeSubmitInfo.pSignalSemaphores = &compute.semaphore; - VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); - } void prepare() diff --git a/examples/descriptorsets/descriptorsets.cpp b/examples/descriptorsets/descriptorsets.cpp index 5afbf6aa..b3955c82 100644 --- a/examples/descriptorsets/descriptorsets.cpp +++ b/examples/descriptorsets/descriptorsets.cpp @@ -362,7 +362,7 @@ public: if (!prepared) return; draw(); - if (animate) { + if (animate && !paused) { cubes[0].rotation.x += 2.5f * frameTimer; if (cubes[0].rotation.x > 360.0f) cubes[0].rotation.x -= 360.0f; @@ -370,7 +370,7 @@ public: if (cubes[1].rotation.x > 360.0f) cubes[1].rotation.x -= 360.0f; } - if ((camera.updated) || (animate)) { + if ((camera.updated) || (animate && !paused)) { updateUniformBuffers(); } } @@ -383,4 +383,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/inputattachments/inputattachments.cpp b/examples/inputattachments/inputattachments.cpp index 4b454b08..f0927815 100644 --- a/examples/inputattachments/inputattachments.cpp +++ b/examples/inputattachments/inputattachments.cpp @@ -180,11 +180,23 @@ public: for (auto i = 0; i < attachments.size(); i++) { clearAttachment(&attachments[i].color); clearAttachment(&attachments[i].depth); + } + + // SRS - Recreate attachments and descriptors in case number of swapchain images has changed on resize + attachments.resize(swapChain.imageCount); + for (auto i = 0; i < attachments.size(); i++) { createAttachment(colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, &attachments[i].color); createAttachment(depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, &attachments[i].depth); - // Since the framebuffers/attachments are referred in the descriptor sets, these need to be updated too - updateAttachmentReadDescriptors(i); } + + vkDestroyPipelineLayout(device, pipelineLayouts.attachmentWrite, nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.attachmentRead, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.attachmentWrite, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.attachmentRead, nullptr); + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + // Since the framebuffers/attachments are referred in the descriptor sets, these need to be updated on resize + setupDescriptors(); } VkImageView views[3]; diff --git a/examples/multisampling/multisampling.cpp b/examples/multisampling/multisampling.cpp index 408e18f7..f73cef79 100644 --- a/examples/multisampling/multisampling.cpp +++ b/examples/multisampling/multisampling.cpp @@ -48,6 +48,7 @@ public: VkPipelineLayout pipelineLayout; VkDescriptorSet descriptorSet; VkDescriptorSetLayout descriptorSetLayout; + VkExtent2D attachmentSize; VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { @@ -199,6 +200,8 @@ public: void setupRenderPass() { // Overrides the virtual function of the base class + + attachmentSize = { width, height }; std::array attachments = {}; @@ -290,6 +293,20 @@ public: { // Overrides the virtual function of the base class + // SRS - If the window is resized, the MSAA attachments need to be released and recreated + if (attachmentSize.width != width || attachmentSize.height != height) + { + attachmentSize = { width, height }; + + // Destroy MSAA target + vkDestroyImage(device, multisampleTarget.color.image, nullptr); + vkDestroyImageView(device, multisampleTarget.color.view, nullptr); + vkFreeMemory(device, multisampleTarget.color.memory, nullptr); + vkDestroyImage(device, multisampleTarget.depth.image, nullptr); + vkDestroyImageView(device, multisampleTarget.depth.view, nullptr); + vkFreeMemory(device, multisampleTarget.depth.memory, nullptr); + } + std::array attachments; setupMultisampleTarget(); diff --git a/examples/multiview/multiview.cpp b/examples/multiview/multiview.cpp index a73992f3..17a4a676 100644 --- a/examples/multiview/multiview.cpp +++ b/examples/multiview/multiview.cpp @@ -98,6 +98,7 @@ public: vkDestroySampler(device, multiviewPass.sampler, nullptr); vkDestroyFramebuffer(device, multiviewPass.frameBuffer, nullptr); + vkFreeCommandBuffers(device, cmdPool, static_cast(multiviewPass.commandBuffers.size()), multiviewPass.commandBuffers.data()); vkDestroySemaphore(device, multiviewPass.semaphore, nullptr); for (auto& fence : multiviewPass.waitFences) { vkDestroyFence(device, fence, nullptr); @@ -337,6 +338,9 @@ public: void buildCommandBuffers() { + if (resized) + return; + /* View display */ @@ -392,11 +396,6 @@ public: Multiview layered attachment scene rendering */ - multiviewPass.commandBuffers.resize(drawCmdBuffers.size()); - - VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(drawCmdBuffers.size())); - VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, multiviewPass.commandBuffers.data())); - { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); @@ -467,13 +466,18 @@ public: */ VkDescriptorSetAllocateInfo allocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocateInfo, &descriptorSet)); + updateDescriptors(); + } + + void updateDescriptors() + { std::vector writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &multiviewPass.descriptor), }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } - + void preparePipelines() { @@ -669,6 +673,11 @@ public: prepareUniformBuffers(); prepareDescriptors(); preparePipelines(); + + VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(drawCmdBuffers.size())); + multiviewPass.commandBuffers.resize(drawCmdBuffers.size()); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, multiviewPass.commandBuffers.data())); + buildCommandBuffers(); VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); @@ -680,6 +689,45 @@ public: prepared = true; } + // SRS - Recreate and update Multiview resources when window size has changed + virtual void windowResized() + { + vkDestroyImageView(device, multiviewPass.color.view, nullptr); + vkDestroyImage(device, multiviewPass.color.image, nullptr); + vkFreeMemory(device, multiviewPass.color.memory, nullptr); + vkDestroyImageView(device, multiviewPass.depth.view, nullptr); + vkDestroyImage(device, multiviewPass.depth.image, nullptr); + vkFreeMemory(device, multiviewPass.depth.memory, nullptr); + + vkDestroyRenderPass(device, multiviewPass.renderPass, nullptr); + vkDestroySampler(device, multiviewPass.sampler, nullptr); + vkDestroyFramebuffer(device, multiviewPass.frameBuffer, nullptr); + + prepareMultiview(); + updateDescriptors(); + + // SRS - Recreate Multiview command buffers in case number of swapchain images has changed on resize + vkFreeCommandBuffers(device, cmdPool, static_cast(multiviewPass.commandBuffers.size()), multiviewPass.commandBuffers.data()); + + VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(drawCmdBuffers.size())); + multiviewPass.commandBuffers.resize(drawCmdBuffers.size()); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, multiviewPass.commandBuffers.data())); + + resized = false; + buildCommandBuffers(); + + // SRS - Recreate Multiview fences in case number of swapchain images has changed on resize + for (auto& fence : multiviewPass.waitFences) { + vkDestroyFence(device, fence, nullptr); + } + + VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); + multiviewPass.waitFences.resize(multiviewPass.commandBuffers.size()); + for (auto& fence : multiviewPass.waitFences) { + VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence)); + } + } + virtual void render() { if (!prepared) @@ -704,4 +752,4 @@ public: }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/pushdescriptors/pushdescriptors.cpp b/examples/pushdescriptors/pushdescriptors.cpp index 080f5b41..b1979828 100644 --- a/examples/pushdescriptors/pushdescriptors.cpp +++ b/examples/pushdescriptors/pushdescriptors.cpp @@ -262,7 +262,7 @@ public: memcpy(cube.uniformBuffer.mapped, &cube.modelMat, sizeof(glm::mat4)); } - if (animate) { + if (animate && !paused) { cubes[0].rotation.x += 2.5f * frameTimer; if (cubes[0].rotation.x > 360.0f) cubes[0].rotation.x -= 360.0f; @@ -323,7 +323,7 @@ public: if (!prepared) return; draw(); - if (animate) { + if (animate && !paused) { cubes[0].rotation.x += 2.5f * frameTimer; if (cubes[0].rotation.x > 360.0f) cubes[0].rotation.x -= 360.0f; @@ -348,4 +348,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/textoverlay/textoverlay.cpp b/examples/textoverlay/textoverlay.cpp index 85b70727..7672b2b8 100644 --- a/examples/textoverlay/textoverlay.cpp +++ b/examples/textoverlay/textoverlay.cpp @@ -901,7 +901,9 @@ public: virtual void windowResized() { - updateTextOverlay(); + // SRS - Recreate text overlay resources in case number of swapchain images has changed on resize + delete textOverlay; + prepareTextOverlay(); } #if !defined(__ANDROID__) @@ -917,4 +919,4 @@ public: #endif }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/triangle/triangle.cpp b/examples/triangle/triangle.cpp index 4a6336f7..6b16b296 100644 --- a/examples/triangle/triangle.cpp +++ b/examples/triangle/triangle.cpp @@ -126,6 +126,9 @@ public: ~VulkanExample() { + // SRS - Ensure all operations on the device have finished before destroying resources + vkDeviceWaitIdle(device); + // Clean up used Vulkan resources // Note: Inherited destructor cleans up resources stored in base class vkDestroyPipeline(device, pipeline, nullptr);