Put compute and render in one command buffer, narrowed scope of memory barriers

This commit is contained in:
saschawillems 2016-05-15 09:14:10 +02:00
parent 3ae4f26901
commit b1a07ddff8

View file

@ -35,7 +35,7 @@
class VulkanExample : public VulkanExampleBase class VulkanExample : public VulkanExampleBase
{ {
public: public:
float timer = 0.f; float timer = 0.0f;
float animStart = 20.0f; float animStart = 20.0f;
bool animate = true; bool animate = true;
@ -58,7 +58,7 @@ public:
} pipelines; } pipelines;
VkQueue computeQueue; VkQueue computeQueue;
VkCommandBuffer computeCmdBuffer; //VkCommandBuffer computeCmdBuffer;
VkPipelineLayout computePipelineLayout; VkPipelineLayout computePipelineLayout;
VkDescriptorSet computeDescriptorSet; VkDescriptorSet computeDescriptorSet;
VkDescriptorSetLayout computeDescriptorSetLayout; VkDescriptorSetLayout computeDescriptorSetLayout;
@ -90,7 +90,6 @@ public:
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
{ {
zoom = -2.0f;
title = "Vulkan Example - Compute shader particle system"; title = "Vulkan Example - Compute shader particle system";
} }
@ -108,7 +107,6 @@ public:
vkTools::destroyUniformData(device, &uniformData.computeShader.ubo); vkTools::destroyUniformData(device, &uniformData.computeShader.ubo);
vkFreeCommandBuffers(device, cmdPool, 1, &computeCmdBuffer);
vkDestroyPipelineLayout(device, computePipelineLayout, nullptr); vkDestroyPipelineLayout(device, computePipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, nullptr);
vkDestroyPipeline(device, pipelines.compute, nullptr); vkDestroyPipeline(device, pipelines.compute, nullptr);
@ -154,33 +152,60 @@ public:
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
// Buffer memory barrier to make sure that compute shader // Compute particle movement
// writes are finished before using the storage buffer
// in the vertex shader // 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(); VkBufferMemoryBarrier bufferBarrier = vkTools::initializers::bufferMemoryBarrier();
// Source access : Compute shader buffer write // Vertex shader invocations have finished reading from the buffer
bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; bufferBarrier.srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
// Dest access : Vertex shader access (attribute binding) // Compute shader buffer read and write
bufferBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
bufferBarrier.buffer = computeStorageBuffer.buffer; bufferBarrier.buffer = computeStorageBuffer.buffer;
bufferBarrier.offset = 0;
bufferBarrier.size = computeStorageBuffer.descriptor.range; bufferBarrier.size = computeStorageBuffer.descriptor.range;
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier( vkCmdPipelineBarrier(
drawCmdBuffers[i], drawCmdBuffers[i],
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_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, VK_FLAGS_NONE,
0, nullptr, 0, nullptr,
1, &bufferBarrier, 1, &bufferBarrier,
0, nullptr); 0, nullptr);
// Draw the particle system using the update vertex buffer
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); 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); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); 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() void draw()
{ {
// Get next image in the swap chain (back/front buffer) // Get next image in the swap chain (back/front buffer)
@ -231,17 +242,6 @@ public:
submitPrePresentBarrier(swapChain.buffers[currentBuffer].image); submitPrePresentBarrier(swapChain.buffers[currentBuffer].image);
VK_CHECK_RESULT(swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete)); 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 // Setup and fill the compute shader storage buffers for
@ -302,6 +302,9 @@ public:
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true); VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
vkFreeMemory(device, stagingBuffer.memory, nullptr);
vkDestroyBuffer(device, stagingBuffer.buffer, nullptr);
computeStorageBuffer.descriptor.range = storageBufferSize; computeStorageBuffer.descriptor.range = storageBufferSize;
computeStorageBuffer.descriptor.buffer = computeStorageBuffer.buffer; computeStorageBuffer.descriptor.buffer = computeStorageBuffer.buffer;
computeStorageBuffer.descriptor.offset = 0; computeStorageBuffer.descriptor.offset = 0;
@ -425,18 +428,6 @@ public:
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); 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() void preparePipelines()
{ {
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
@ -662,7 +653,6 @@ public:
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadTextures(); loadTextures();
getComputeQueue(); getComputeQueue();
createComputeCommandBuffer();
prepareStorageBuffers(); prepareStorageBuffers();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptorSetLayout(); setupDescriptorSetLayout();
@ -671,7 +661,6 @@ public:
setupDescriptorSet(); setupDescriptorSet();
prepareCompute(); prepareCompute();
buildCommandBuffers(); buildCommandBuffers();
buildComputeCommandBuffer();
prepared = true; prepared = true;
} }