From b1a07ddff8dbbfade393b3bb4797c9df61cf6952 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Sun, 15 May 2016 09:14:10 +0200 Subject: [PATCH] Put compute and render in one command buffer, narrowed scope of memory barriers --- computeparticles/computeparticles.cpp | 99 ++++++++++++--------------- 1 file changed, 44 insertions(+), 55 deletions(-) diff --git a/computeparticles/computeparticles.cpp b/computeparticles/computeparticles.cpp index 73378494..fa1e6acf 100644 --- a/computeparticles/computeparticles.cpp +++ b/computeparticles/computeparticles.cpp @@ -35,7 +35,7 @@ class VulkanExample : public VulkanExampleBase { public: - float timer = 0.f; + float timer = 0.0f; float animStart = 20.0f; bool animate = true; @@ -58,7 +58,7 @@ public: } pipelines; VkQueue computeQueue; - VkCommandBuffer computeCmdBuffer; + //VkCommandBuffer computeCmdBuffer; VkPipelineLayout computePipelineLayout; VkDescriptorSet computeDescriptorSet; VkDescriptorSetLayout computeDescriptorSetLayout; @@ -90,7 +90,6 @@ public: VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { - zoom = -2.0f; title = "Vulkan Example - Compute shader particle system"; } @@ -108,7 +107,6 @@ public: vkTools::destroyUniformData(device, &uniformData.computeShader.ubo); - vkFreeCommandBuffers(device, cmdPool, 1, &computeCmdBuffer); vkDestroyPipelineLayout(device, computePipelineLayout, nullptr); vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, nullptr); vkDestroyPipeline(device, pipelines.compute, nullptr); @@ -154,33 +152,60 @@ public: VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); - // Buffer memory barrier to make sure that compute shader - // writes are finished before using the storage buffer - // in the vertex shader + // Compute particle movement + + // Add memory barrier to ensure that the (rendering) vertex shader operations have finished + // Required as the compute shader will overwrite the vertex buffer data VkBufferMemoryBarrier bufferBarrier = vkTools::initializers::bufferMemoryBarrier(); - // Source access : Compute shader buffer write - bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - // Dest access : Vertex shader access (attribute binding) - bufferBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + // Vertex shader invocations have finished reading from the buffer + bufferBarrier.srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + // Compute shader buffer read and write + bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; bufferBarrier.buffer = computeStorageBuffer.buffer; - bufferBarrier.offset = 0; bufferBarrier.size = computeStorageBuffer.descriptor.range; bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkCmdPipelineBarrier( drawCmdBuffers[i], - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 1, &bufferBarrier, + 0, nullptr); + + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_COMPUTE, pipelines.compute); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 0, 1, &computeDescriptorSet, 0, 0); + + // Dispatch the compute job + vkCmdDispatch(drawCmdBuffers[i], PARTICLE_COUNT / 16, 1, 1); + + // Add memory barrier to ensure that compute shader has finished writing to the buffer + // Without this the (rendering) vertex shader may display incomplete results (partial data from last frame) + // Compute shader has finished writes to the buffer + bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + // Vertex shader access (attribute binding) + bufferBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + bufferBarrier.buffer = computeStorageBuffer.buffer; + bufferBarrier.size = computeStorageBuffer.descriptor.range; + bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + vkCmdPipelineBarrier( + drawCmdBuffers[i], + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_FLAGS_NONE, 0, nullptr, 1, &bufferBarrier, 0, nullptr); + // Draw the particle system using the update vertex buffer + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f - ); + VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); @@ -200,20 +225,6 @@ public: } - void buildComputeCommandBuffer() - { - VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo();; - - vkBeginCommandBuffer(computeCmdBuffer, &cmdBufInfo); - - vkCmdBindPipeline(computeCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelines.compute); - vkCmdBindDescriptorSets(computeCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 0, 1, &computeDescriptorSet, 0, 0); - - vkCmdDispatch(computeCmdBuffer, PARTICLE_COUNT / 16, 1, 1); - - vkEndCommandBuffer(computeCmdBuffer); - } - void draw() { // Get next image in the swap chain (back/front buffer) @@ -231,17 +242,6 @@ public: submitPrePresentBarrier(swapChain.buffers[currentBuffer].image); VK_CHECK_RESULT(swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete)); - - // Compute - VkSubmitInfo computeSubmitInfo = vkTools::initializers::submitInfo(); - computeSubmitInfo.commandBufferCount = 1; - computeSubmitInfo.pCommandBuffers = &computeCmdBuffer; - - VK_CHECK_RESULT(vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); - - VK_CHECK_RESULT(vkQueueWaitIdle(queue)); - - VK_CHECK_RESULT(vkQueueWaitIdle(computeQueue)); } // Setup and fill the compute shader storage buffers for @@ -302,6 +302,9 @@ public: VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true); + vkFreeMemory(device, stagingBuffer.memory, nullptr); + vkDestroyBuffer(device, stagingBuffer.buffer, nullptr); + computeStorageBuffer.descriptor.range = storageBufferSize; computeStorageBuffer.descriptor.buffer = computeStorageBuffer.buffer; computeStorageBuffer.descriptor.offset = 0; @@ -425,18 +428,6 @@ public: vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); } - // Create a separate command buffer for compute commands - void createComputeCommandBuffer() - { - VkCommandBufferAllocateInfo cmdBufAllocateInfo = - vkTools::initializers::commandBufferAllocateInfo( - cmdPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - 1); - - VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &computeCmdBuffer)); - } - void preparePipelines() { VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = @@ -662,7 +653,6 @@ public: VulkanExampleBase::prepare(); loadTextures(); getComputeQueue(); - createComputeCommandBuffer(); prepareStorageBuffers(); prepareUniformBuffers(); setupDescriptorSetLayout(); @@ -671,7 +661,6 @@ public: setupDescriptorSet(); prepareCompute(); buildCommandBuffers(); - buildComputeCommandBuffer(); prepared = true; }