Fix queue family transfer operations between graphics <-> compute queues, generalize getQueueFamilyIndex() to support VkQueueFlags vs. VkQueueFlagBits, computecloth deltaT now based on frameTimer

This commit is contained in:
Stephen Saunders 2022-06-13 22:53:48 -04:00
parent 17aaa7305b
commit b2f501dc98
7 changed files with 306 additions and 80 deletions

View file

@ -149,6 +149,32 @@ public:
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
// Acquire barrier
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
nullptr,
0,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
vulkanDevice->queueFamilyIndices.compute,
vulkanDevice->queueFamilyIndices.graphics,
indirectCommandsBuffer.buffer,
0,
indirectCommandsBuffer.descriptor.range
};
vkCmdPipelineBarrier(
drawCmdBuffers[i],
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
0,
0, nullptr,
1, &buffer_barrier,
0, nullptr);
}
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
@ -169,7 +195,7 @@ public:
if (vulkanDevice->features.multiDrawIndirect)
{
vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, indirectCommands.size(), sizeof(VkDrawIndexedIndirectCommand));
vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, static_cast<uint32_t>(indirectCommands.size()), sizeof(VkDrawIndexedIndirectCommand));
}
else
{
@ -184,6 +210,32 @@ public:
vkCmdEndRenderPass(drawCmdBuffers[i]);
// Release barrier
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
nullptr,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
0,
vulkanDevice->queueFamilyIndices.graphics,
vulkanDevice->queueFamilyIndices.compute,
indirectCommandsBuffer.buffer,
0,
indirectCommandsBuffer.descriptor.range
};
vkCmdPipelineBarrier(
drawCmdBuffers[i],
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0,
0, nullptr,
1, &buffer_barrier,
0, nullptr);
}
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
}
}
@ -200,23 +252,32 @@ public:
VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffer, &cmdBufInfo));
// Acquire barrier
// Add memory barrier to ensure that the indirect commands have been consumed before the compute shader updates them
VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier();
bufferBarrier.buffer = indirectCommandsBuffer.buffer;
bufferBarrier.size = indirectCommandsBuffer.descriptor.range;
bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
nullptr,
0,
VK_ACCESS_SHADER_WRITE_BIT,
vulkanDevice->queueFamilyIndices.graphics,
vulkanDevice->queueFamilyIndices.compute,
indirectCommandsBuffer.buffer,
0,
indirectCommandsBuffer.descriptor.range
};
vkCmdPipelineBarrier(
compute.commandBuffer,
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_FLAGS_NONE,
0, nullptr,
1, &bufferBarrier,
0, nullptr);
vkCmdPipelineBarrier(
compute.commandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_FLAGS_NONE,
0, nullptr,
1, &buffer_barrier,
0, nullptr);
}
vkCmdBindPipeline(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline);
vkCmdBindDescriptorSets(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipelineLayout, 0, 1, &compute.descriptorSet, 0, 0);
@ -226,22 +287,32 @@ public:
// It also determines the lod to use depending on distance to the viewer.
vkCmdDispatch(compute.commandBuffer, objectCount / 16, 1, 1);
// Release barrier
// Add memory barrier to ensure that the compute shader has finished writing the indirect command buffer before it's consumed
bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
bufferBarrier.buffer = indirectCommandsBuffer.buffer;
bufferBarrier.size = indirectCommandsBuffer.descriptor.range;
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
{
VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
nullptr,
VK_ACCESS_SHADER_WRITE_BIT,
0,
vulkanDevice->queueFamilyIndices.compute,
vulkanDevice->queueFamilyIndices.graphics,
indirectCommandsBuffer.buffer,
0,
indirectCommandsBuffer.descriptor.range
};
vkCmdPipelineBarrier(
compute.commandBuffer,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
VK_FLAGS_NONE,
0, nullptr,
1, &bufferBarrier,
0, nullptr);
vkCmdPipelineBarrier(
compute.commandBuffer,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_FLAGS_NONE,
0, nullptr,
1, &buffer_barrier,
0, nullptr);
}
// todo: barrier for indirect stats buffer?
@ -424,7 +495,38 @@ public:
&instanceBuffer,
stagingBuffer.size));
vulkanDevice->copyBuffer(&stagingBuffer, &instanceBuffer, queue);
// Copy from staging buffer to instance buffer
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
VkBufferCopy copyRegion = {};
copyRegion.size = stagingBuffer.size;
vkCmdCopyBuffer(copyCmd, stagingBuffer.buffer, instanceBuffer.buffer, 1, &copyRegion);
// Add an initial release barrier to the graphics queue,
// so that when the compute command buffer executes for the first time
// it doesn't complain about a lack of a corresponding "release" to its "acquire"
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
{ VkBufferMemoryBarrier buffer_barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
nullptr,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
0,
vulkanDevice->queueFamilyIndices.graphics,
vulkanDevice->queueFamilyIndices.compute,
indirectCommandsBuffer.buffer,
0,
indirectCommandsBuffer.descriptor.range
};
vkCmdPipelineBarrier(
copyCmd,
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0,
0, nullptr,
1, &buffer_barrier,
0, nullptr);
}
vulkanDevice->flushCommandBuffer(copyCmd, queue, true);
stagingBuffer.destroy();
@ -710,6 +812,11 @@ public:
}
}
virtual void viewChanged()
{
updateUniformBuffer(true);
}
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
{
if (overlay->header("Settings")) {
@ -726,4 +833,4 @@ public:
}
};
VULKAN_EXAMPLE_MAIN()
VULKAN_EXAMPLE_MAIN()