Put compute and render in one command buffer, narrowed scope of memory barriers
This commit is contained in:
parent
3ae4f26901
commit
b1a07ddff8
1 changed files with 44 additions and 55 deletions
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue