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:
parent
17aaa7305b
commit
b2f501dc98
7 changed files with 306 additions and 80 deletions
|
|
@ -120,6 +120,7 @@ namespace vks
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the index of a queue family that supports the requested queue flags
|
* Get the index of a queue family that supports the requested queue flags
|
||||||
|
* SRS - support VkQueueFlags parameter for requesting multiple flags vs. VkQueueFlagBits for a single flag only
|
||||||
*
|
*
|
||||||
* @param queueFlags Queue flags to find a queue family index for
|
* @param queueFlags Queue flags to find a queue family index for
|
||||||
*
|
*
|
||||||
|
|
@ -127,15 +128,15 @@ namespace vks
|
||||||
*
|
*
|
||||||
* @throw Throws an exception if no queue family index could be found that supports the requested flags
|
* @throw Throws an exception if no queue family index could be found that supports the requested flags
|
||||||
*/
|
*/
|
||||||
uint32_t VulkanDevice::getQueueFamilyIndex(VkQueueFlagBits queueFlags) const
|
uint32_t VulkanDevice::getQueueFamilyIndex(VkQueueFlags queueFlags) const
|
||||||
{
|
{
|
||||||
// Dedicated queue for compute
|
// Dedicated queue for compute
|
||||||
// Try to find a queue family index that supports compute but not graphics
|
// Try to find a queue family index that supports compute but not graphics
|
||||||
if (queueFlags & VK_QUEUE_COMPUTE_BIT)
|
if ((queueFlags & VK_QUEUE_COMPUTE_BIT) == queueFlags)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++)
|
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++)
|
||||||
{
|
{
|
||||||
if ((queueFamilyProperties[i].queueFlags & queueFlags) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0))
|
if ((queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0))
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
@ -144,11 +145,11 @@ namespace vks
|
||||||
|
|
||||||
// Dedicated queue for transfer
|
// Dedicated queue for transfer
|
||||||
// Try to find a queue family index that supports transfer but not graphics and compute
|
// Try to find a queue family index that supports transfer but not graphics and compute
|
||||||
if (queueFlags & VK_QUEUE_TRANSFER_BIT)
|
if ((queueFlags & VK_QUEUE_TRANSFER_BIT) == queueFlags)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++)
|
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++)
|
||||||
{
|
{
|
||||||
if ((queueFamilyProperties[i].queueFlags & queueFlags) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0))
|
if ((queueFamilyProperties[i].queueFlags & VK_QUEUE_TRANSFER_BIT) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0))
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +159,7 @@ namespace vks
|
||||||
// For other queue types or if no separate compute queue is present, return the first one to support the requested flags
|
// For other queue types or if no separate compute queue is present, return the first one to support the requested flags
|
||||||
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++)
|
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++)
|
||||||
{
|
{
|
||||||
if (queueFamilyProperties[i].queueFlags & queueFlags)
|
if ((queueFamilyProperties[i].queueFlags & queueFlags) == queueFlags)
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
@ -233,7 +234,7 @@ namespace vks
|
||||||
queueFamilyIndices.transfer = getQueueFamilyIndex(VK_QUEUE_TRANSFER_BIT);
|
queueFamilyIndices.transfer = getQueueFamilyIndex(VK_QUEUE_TRANSFER_BIT);
|
||||||
if ((queueFamilyIndices.transfer != queueFamilyIndices.graphics) && (queueFamilyIndices.transfer != queueFamilyIndices.compute))
|
if ((queueFamilyIndices.transfer != queueFamilyIndices.graphics) && (queueFamilyIndices.transfer != queueFamilyIndices.compute))
|
||||||
{
|
{
|
||||||
// If compute family index differs, we need an additional queue create info for the compute queue
|
// If transfer family index differs, we need an additional queue create info for the transfer queue
|
||||||
VkDeviceQueueCreateInfo queueInfo{};
|
VkDeviceQueueCreateInfo queueInfo{};
|
||||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
queueInfo.queueFamilyIndex = queueFamilyIndices.transfer;
|
queueInfo.queueFamilyIndex = queueFamilyIndices.transfer;
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ struct VulkanDevice
|
||||||
explicit VulkanDevice(VkPhysicalDevice physicalDevice);
|
explicit VulkanDevice(VkPhysicalDevice physicalDevice);
|
||||||
~VulkanDevice();
|
~VulkanDevice();
|
||||||
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr) const;
|
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr) const;
|
||||||
uint32_t getQueueFamilyIndex(VkQueueFlagBits queueFlags) const;
|
uint32_t getQueueFamilyIndex(VkQueueFlags queueFlags) const;
|
||||||
VkResult createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char *> enabledExtensions, void *pNextChain, bool useSwapChain = true, VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
|
VkResult createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char *> enabledExtensions, void *pNextChain, bool useSwapChain = true, VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
|
||||||
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr);
|
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr);
|
||||||
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, vks::Buffer *buffer, VkDeviceSize size, void *data = nullptr);
|
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, vks::Buffer *buffer, VkDeviceSize size, void *data = nullptr);
|
||||||
|
|
|
||||||
|
|
@ -136,12 +136,12 @@ public:
|
||||||
textureCloth.loadFromFile(getAssetPath() + "textures/vulkan_cloth_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
|
textureCloth.loadFromFile(getAssetPath() + "textures/vulkan_cloth_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addGraphicsToComputeBarriers(VkCommandBuffer commandBuffer)
|
void addGraphicsToComputeBarriers(VkCommandBuffer commandBuffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask)
|
||||||
{
|
{
|
||||||
if (specializedComputeQueue) {
|
if (specializedComputeQueue) {
|
||||||
VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier();
|
VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier();
|
||||||
bufferBarrier.srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
bufferBarrier.srcAccessMask = srcAccessMask;
|
||||||
bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
bufferBarrier.dstAccessMask = dstAccessMask;
|
||||||
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
||||||
bufferBarrier.size = VK_WHOLE_SIZE;
|
bufferBarrier.size = VK_WHOLE_SIZE;
|
||||||
|
|
@ -152,8 +152,8 @@ public:
|
||||||
bufferBarrier.buffer = compute.storageBuffers.output.buffer;
|
bufferBarrier.buffer = compute.storageBuffers.output.buffer;
|
||||||
bufferBarriers.push_back(bufferBarrier);
|
bufferBarriers.push_back(bufferBarrier);
|
||||||
vkCmdPipelineBarrier(commandBuffer,
|
vkCmdPipelineBarrier(commandBuffer,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
srcStageMask,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
dstStageMask,
|
||||||
VK_FLAGS_NONE,
|
VK_FLAGS_NONE,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
static_cast<uint32_t>(bufferBarriers.size()), bufferBarriers.data(),
|
static_cast<uint32_t>(bufferBarriers.size()), bufferBarriers.data(),
|
||||||
|
|
@ -166,8 +166,8 @@ public:
|
||||||
VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier();
|
VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier();
|
||||||
bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
bufferBarrier.size = VK_WHOLE_SIZE;
|
bufferBarrier.size = VK_WHOLE_SIZE;
|
||||||
std::vector<VkBufferMemoryBarrier> bufferBarriers;
|
std::vector<VkBufferMemoryBarrier> bufferBarriers;
|
||||||
bufferBarrier.buffer = compute.storageBuffers.input.buffer;
|
bufferBarrier.buffer = compute.storageBuffers.input.buffer;
|
||||||
|
|
@ -184,12 +184,12 @@ public:
|
||||||
0, nullptr);
|
0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addComputeToGraphicsBarriers(VkCommandBuffer commandBuffer)
|
void addComputeToGraphicsBarriers(VkCommandBuffer commandBuffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask)
|
||||||
{
|
{
|
||||||
if (specializedComputeQueue) {
|
if (specializedComputeQueue) {
|
||||||
VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier();
|
VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier();
|
||||||
bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
bufferBarrier.srcAccessMask = srcAccessMask;
|
||||||
bufferBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
bufferBarrier.dstAccessMask = dstAccessMask;
|
||||||
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
||||||
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
bufferBarrier.size = VK_WHOLE_SIZE;
|
bufferBarrier.size = VK_WHOLE_SIZE;
|
||||||
|
|
@ -200,8 +200,8 @@ public:
|
||||||
bufferBarriers.push_back(bufferBarrier);
|
bufferBarriers.push_back(bufferBarrier);
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
srcStageMask,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
dstStageMask,
|
||||||
VK_FLAGS_NONE,
|
VK_FLAGS_NONE,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
static_cast<uint32_t>(bufferBarriers.size()), bufferBarriers.data(),
|
static_cast<uint32_t>(bufferBarriers.size()), bufferBarriers.data(),
|
||||||
|
|
@ -234,7 +234,7 @@ public:
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
||||||
|
|
||||||
// Acquire storage buffers from compute queue
|
// Acquire storage buffers from compute queue
|
||||||
addComputeToGraphicsBarriers(drawCmdBuffers[i]);
|
addComputeToGraphicsBarriers(drawCmdBuffers[i], 0, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT);
|
||||||
|
|
||||||
// Draw the particle system using the update vertex buffer
|
// Draw the particle system using the update vertex buffer
|
||||||
|
|
||||||
|
|
@ -267,7 +267,7 @@ public:
|
||||||
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
||||||
|
|
||||||
// release the storage buffers to the compute queue
|
// release the storage buffers to the compute queue
|
||||||
addGraphicsToComputeBarriers(drawCmdBuffers[i]);
|
addGraphicsToComputeBarriers(drawCmdBuffers[i], VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, 0, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||||
}
|
}
|
||||||
|
|
@ -285,7 +285,7 @@ public:
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffers[i], &cmdBufInfo));
|
VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffers[i], &cmdBufInfo));
|
||||||
|
|
||||||
// Acquire the storage buffers from the graphics queue
|
// Acquire the storage buffers from the graphics queue
|
||||||
addGraphicsToComputeBarriers(compute.commandBuffers[i]);
|
addGraphicsToComputeBarriers(compute.commandBuffers[i], 0, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||||
|
|
||||||
vkCmdBindPipeline(compute.commandBuffers[i], VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline);
|
vkCmdBindPipeline(compute.commandBuffers[i], VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline);
|
||||||
|
|
||||||
|
|
@ -313,7 +313,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// release the storage buffers back to the graphics queue
|
// release the storage buffers back to the graphics queue
|
||||||
addComputeToGraphicsBarriers(compute.commandBuffers[i]);
|
addComputeToGraphicsBarriers(compute.commandBuffers[i], VK_ACCESS_SHADER_WRITE_BIT, 0, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||||
vkEndCommandBuffer(compute.commandBuffers[i]);
|
vkEndCommandBuffer(compute.commandBuffers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -396,7 +396,7 @@ public:
|
||||||
// Add an initial release barrier to the graphics queue,
|
// Add an initial release barrier to the graphics queue,
|
||||||
// so that when the compute command buffer executes for the first time
|
// 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"
|
// it doesn't complain about a lack of a corresponding "release" to its "acquire"
|
||||||
addGraphicsToComputeBarriers(copyCmd);
|
addGraphicsToComputeBarriers(copyCmd, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, 0, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||||
vulkanDevice->flushCommandBuffer(copyCmd, queue, true);
|
vulkanDevice->flushCommandBuffer(copyCmd, queue, true);
|
||||||
|
|
||||||
stagingBuffer.destroy();
|
stagingBuffer.destroy();
|
||||||
|
|
@ -673,11 +673,12 @@ public:
|
||||||
if (!paused) {
|
if (!paused) {
|
||||||
//compute.ubo.deltaT = 0.000005f;
|
//compute.ubo.deltaT = 0.000005f;
|
||||||
// todo: base on frametime
|
// todo: base on frametime
|
||||||
compute.ubo.deltaT = frameTimer * 0.0015f;
|
// SRS - Clamp frameTimer to max 20ms refresh period (e.g. if blocked on resize), otherwise image breakup can occur
|
||||||
|
compute.ubo.deltaT = fmin(frameTimer, 0.02) * 0.0025f;
|
||||||
|
|
||||||
if (simulateWind) {
|
if (simulateWind) {
|
||||||
std::default_random_engine rndEngine(benchmark.active ? 0 : (unsigned)time(nullptr));
|
std::default_random_engine rndEngine(benchmark.active ? 0 : (unsigned)time(nullptr));
|
||||||
std::uniform_real_distribution<float> rd(1.0f, 30.0f);
|
std::uniform_real_distribution<float> rd(1.0f, 12.0f);
|
||||||
compute.ubo.gravity.x = cos(glm::radians(-timer * 360.0f)) * (rd(rndEngine) - rd(rndEngine));
|
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));
|
compute.ubo.gravity.z = sin(glm::radians(timer * 360.0f)) * (rd(rndEngine) - rd(rndEngine));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,32 @@ public:
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
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);
|
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
|
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
|
||||||
|
|
@ -169,7 +195,7 @@ public:
|
||||||
|
|
||||||
if (vulkanDevice->features.multiDrawIndirect)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -184,6 +210,32 @@ public:
|
||||||
|
|
||||||
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
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]));
|
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,23 +252,32 @@ public:
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffer, &cmdBufInfo));
|
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
|
// Add memory barrier to ensure that the indirect commands have been consumed before the compute shader updates them
|
||||||
VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier();
|
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
|
||||||
bufferBarrier.buffer = indirectCommandsBuffer.buffer;
|
{
|
||||||
bufferBarrier.size = indirectCommandsBuffer.descriptor.range;
|
VkBufferMemoryBarrier buffer_barrier =
|
||||||
bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
{
|
||||||
bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||||
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
nullptr,
|
||||||
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
0,
|
||||||
|
VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
|
vulkanDevice->queueFamilyIndices.graphics,
|
||||||
|
vulkanDevice->queueFamilyIndices.compute,
|
||||||
|
indirectCommandsBuffer.buffer,
|
||||||
|
0,
|
||||||
|
indirectCommandsBuffer.descriptor.range
|
||||||
|
};
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
compute.commandBuffer,
|
compute.commandBuffer,
|
||||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
VK_FLAGS_NONE,
|
VK_FLAGS_NONE,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &bufferBarrier,
|
1, &buffer_barrier,
|
||||||
0, nullptr);
|
0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
vkCmdBindPipeline(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline);
|
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);
|
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.
|
// It also determines the lod to use depending on distance to the viewer.
|
||||||
vkCmdDispatch(compute.commandBuffer, objectCount / 16, 1, 1);
|
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
|
// 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;
|
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
|
||||||
bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
{
|
||||||
bufferBarrier.buffer = indirectCommandsBuffer.buffer;
|
VkBufferMemoryBarrier buffer_barrier =
|
||||||
bufferBarrier.size = indirectCommandsBuffer.descriptor.range;
|
{
|
||||||
bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||||
bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
nullptr,
|
||||||
|
VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
|
0,
|
||||||
|
vulkanDevice->queueFamilyIndices.compute,
|
||||||
|
vulkanDevice->queueFamilyIndices.graphics,
|
||||||
|
indirectCommandsBuffer.buffer,
|
||||||
|
0,
|
||||||
|
indirectCommandsBuffer.descriptor.range
|
||||||
|
};
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
compute.commandBuffer,
|
compute.commandBuffer,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
VK_FLAGS_NONE,
|
VK_FLAGS_NONE,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &bufferBarrier,
|
1, &buffer_barrier,
|
||||||
0, nullptr);
|
0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// todo: barrier for indirect stats buffer?
|
// todo: barrier for indirect stats buffer?
|
||||||
|
|
||||||
|
|
@ -424,7 +495,38 @@ public:
|
||||||
&instanceBuffer,
|
&instanceBuffer,
|
||||||
stagingBuffer.size));
|
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, ©Region);
|
||||||
|
// 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();
|
stagingBuffer.destroy();
|
||||||
|
|
||||||
|
|
@ -710,6 +812,11 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void viewChanged()
|
||||||
|
{
|
||||||
|
updateUniformBuffer(true);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
|
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
|
||||||
{
|
{
|
||||||
if (overlay->header("Settings")) {
|
if (overlay->header("Settings")) {
|
||||||
|
|
@ -726,4 +833,4 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
VULKAN_EXAMPLE_MAIN()
|
VULKAN_EXAMPLE_MAIN()
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ public:
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
drawCmdBuffers[i],
|
drawCmdBuffers[i],
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
|
|
@ -207,7 +207,7 @@ public:
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
drawCmdBuffers[i],
|
drawCmdBuffers[i],
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &buffer_barrier,
|
1, &buffer_barrier,
|
||||||
|
|
@ -243,7 +243,7 @@ public:
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
compute.commandBuffer,
|
compute.commandBuffer,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
|
|
@ -300,7 +300,7 @@ public:
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
compute.commandBuffer,
|
compute.commandBuffer,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &buffer_barrier,
|
1, &buffer_barrier,
|
||||||
|
|
@ -417,7 +417,7 @@ public:
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
copyCmd,
|
copyCmd,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &buffer_barrier,
|
1, &buffer_barrier,
|
||||||
|
|
@ -746,7 +746,9 @@ public:
|
||||||
// Build a single command buffer containing the compute dispatch commands
|
// Build a single command buffer containing the compute dispatch commands
|
||||||
buildComputeCommandBuffer();
|
buildComputeCommandBuffer();
|
||||||
|
|
||||||
|
// SRS - By reordering compute and graphics within draw(), the following code is no longer needed:
|
||||||
// If graphics and compute queue family indices differ, acquire and immediately release the storage buffer, so that the initial acquire from the graphics command buffers are matched up properly
|
// If graphics and compute queue family indices differ, acquire and immediately release the storage buffer, so that the initial acquire from the graphics command buffers are matched up properly
|
||||||
|
/*
|
||||||
if (graphics.queueFamilyIndex != compute.queueFamilyIndex)
|
if (graphics.queueFamilyIndex != compute.queueFamilyIndex)
|
||||||
{
|
{
|
||||||
// Create a transient command buffer for setting up the initial buffer transfer state
|
// Create a transient command buffer for setting up the initial buffer transfer state
|
||||||
|
|
@ -796,6 +798,7 @@ public:
|
||||||
|
|
||||||
vulkanDevice->flushCommandBuffer(transferCmd, compute.queue, compute.commandPool);
|
vulkanDevice->flushCommandBuffer(transferCmd, compute.queue, compute.commandPool);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare and initialize uniform buffer containing shader uniforms
|
// Prepare and initialize uniform buffer containing shader uniforms
|
||||||
|
|
@ -899,6 +902,11 @@ public:
|
||||||
updateGraphicsUniformBuffers();
|
updateGraphicsUniformBuffers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void viewChanged()
|
||||||
|
{
|
||||||
|
updateGraphicsUniformBuffers();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
VULKAN_EXAMPLE_MAIN()
|
VULKAN_EXAMPLE_MAIN()
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ public:
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
drawCmdBuffers[i],
|
drawCmdBuffers[i],
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
|
|
@ -196,7 +196,7 @@ public:
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
drawCmdBuffers[i],
|
drawCmdBuffers[i],
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &buffer_barrier,
|
1, &buffer_barrier,
|
||||||
|
|
@ -234,7 +234,7 @@ public:
|
||||||
|
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
compute.commandBuffer,
|
compute.commandBuffer,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
|
|
@ -267,7 +267,7 @@ public:
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
compute.commandBuffer,
|
compute.commandBuffer,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &buffer_barrier,
|
1, &buffer_barrier,
|
||||||
|
|
@ -336,7 +336,7 @@ public:
|
||||||
vkCmdPipelineBarrier(
|
vkCmdPipelineBarrier(
|
||||||
copyCmd,
|
copyCmd,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
0,
|
0,
|
||||||
0, nullptr,
|
0, nullptr,
|
||||||
1, &buffer_barrier,
|
1, &buffer_barrier,
|
||||||
|
|
@ -647,7 +647,9 @@ public:
|
||||||
// Build a single command buffer containing the compute dispatch commands
|
// Build a single command buffer containing the compute dispatch commands
|
||||||
buildComputeCommandBuffer();
|
buildComputeCommandBuffer();
|
||||||
|
|
||||||
|
// SRS - By reordering compute and graphics within draw(), the following code is no longer needed:
|
||||||
// If graphics and compute queue family indices differ, acquire and immediately release the storage buffer, so that the initial acquire from the graphics command buffers are matched up properly
|
// If graphics and compute queue family indices differ, acquire and immediately release the storage buffer, so that the initial acquire from the graphics command buffers are matched up properly
|
||||||
|
/*
|
||||||
if (graphics.queueFamilyIndex != compute.queueFamilyIndex)
|
if (graphics.queueFamilyIndex != compute.queueFamilyIndex)
|
||||||
{
|
{
|
||||||
// Create a transient command buffer for setting up the initial buffer transfer state
|
// Create a transient command buffer for setting up the initial buffer transfer state
|
||||||
|
|
@ -697,6 +699,7 @@ public:
|
||||||
|
|
||||||
vulkanDevice->flushCommandBuffer(transferCmd, compute.queue, compute.commandPool);
|
vulkanDevice->flushCommandBuffer(transferCmd, compute.queue, compute.commandPool);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare and initialize uniform buffer containing shader uniforms
|
// Prepare and initialize uniform buffer containing shader uniforms
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,9 @@ public:
|
||||||
|
|
||||||
~VulkanExample()
|
~VulkanExample()
|
||||||
{
|
{
|
||||||
|
// SRS - Ensure all operations on the device have finished before destroying resources
|
||||||
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
vkDestroyPipeline(device, graphics.pipeline, nullptr);
|
vkDestroyPipeline(device, graphics.pipeline, nullptr);
|
||||||
vkDestroyPipelineLayout(device, graphics.pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(device, graphics.pipelineLayout, nullptr);
|
||||||
|
|
@ -223,16 +226,38 @@ public:
|
||||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
imageMemoryBarrier.image = textureComputeTarget.image;
|
imageMemoryBarrier.image = textureComputeTarget.image;
|
||||||
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
|
||||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
{
|
||||||
vkCmdPipelineBarrier(
|
// Acquire barrier for graphics queue
|
||||||
drawCmdBuffers[i],
|
imageMemoryBarrier.srcAccessMask = 0;
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
||||||
VK_FLAGS_NONE,
|
imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
0, nullptr,
|
vkCmdPipelineBarrier(
|
||||||
0, nullptr,
|
drawCmdBuffers[i],
|
||||||
1, &imageMemoryBarrier);
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
VK_FLAGS_NONE,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &imageMemoryBarrier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Combined barrier on single queue family
|
||||||
|
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
VK_FLAGS_NONE,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &imageMemoryBarrier);
|
||||||
|
}
|
||||||
|
|
||||||
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
|
@ -252,6 +277,23 @@ public:
|
||||||
|
|
||||||
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
||||||
|
|
||||||
|
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
|
||||||
|
{
|
||||||
|
// Release barrier from graphics queue
|
||||||
|
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
|
imageMemoryBarrier.dstAccessMask = 0;
|
||||||
|
imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
|
imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
|
VK_FLAGS_NONE,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &imageMemoryBarrier);
|
||||||
|
}
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,12 +304,52 @@ public:
|
||||||
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
|
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffer, &cmdBufInfo));
|
VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffer, &cmdBufInfo));
|
||||||
|
|
||||||
|
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||||
|
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
imageMemoryBarrier.image = textureComputeTarget.image;
|
||||||
|
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||||
|
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
|
||||||
|
{
|
||||||
|
// Acquire barrier for compute queue
|
||||||
|
imageMemoryBarrier.srcAccessMask = 0;
|
||||||
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
|
imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
|
imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
compute.commandBuffer,
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
|
VK_FLAGS_NONE,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &imageMemoryBarrier);
|
||||||
|
}
|
||||||
|
|
||||||
vkCmdBindPipeline(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline);
|
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);
|
vkCmdBindDescriptorSets(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipelineLayout, 0, 1, &compute.descriptorSet, 0, 0);
|
||||||
|
|
||||||
vkCmdDispatch(compute.commandBuffer, textureComputeTarget.width / 16, textureComputeTarget.height / 16, 1);
|
vkCmdDispatch(compute.commandBuffer, textureComputeTarget.width / 16, textureComputeTarget.height / 16, 1);
|
||||||
|
|
||||||
|
if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute)
|
||||||
|
{
|
||||||
|
// Release barrier from compute queue
|
||||||
|
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
|
imageMemoryBarrier.dstAccessMask = 0;
|
||||||
|
imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
||||||
|
imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
compute.commandBuffer,
|
||||||
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
|
VK_FLAGS_NONE,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &imageMemoryBarrier);
|
||||||
|
}
|
||||||
|
|
||||||
vkEndCommandBuffer(compute.commandBuffer);
|
vkEndCommandBuffer(compute.commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -361,6 +443,30 @@ public:
|
||||||
copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
copyRegion.size = storageBufferSize;
|
copyRegion.size = storageBufferSize;
|
||||||
vkCmdCopyBuffer(copyCmd, stagingBuffer.buffer, compute.storageBuffers.planes.buffer, 1, ©Region);
|
vkCmdCopyBuffer(copyCmd, stagingBuffer.buffer, compute.storageBuffers.planes.buffer, 1, ©Region);
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||||
|
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
imageMemoryBarrier.image = textureComputeTarget.image;
|
||||||
|
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||||
|
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
|
imageMemoryBarrier.dstAccessMask = 0;
|
||||||
|
imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
|
imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute;
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
copyCmd,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
|
VK_FLAGS_NONE,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &imageMemoryBarrier);
|
||||||
|
}
|
||||||
vulkanDevice->flushCommandBuffer(copyCmd, queue, true);
|
vulkanDevice->flushCommandBuffer(copyCmd, queue, true);
|
||||||
|
|
||||||
stagingBuffer.destroy();
|
stagingBuffer.destroy();
|
||||||
|
|
@ -689,9 +795,9 @@ public:
|
||||||
void prepare()
|
void prepare()
|
||||||
{
|
{
|
||||||
VulkanExampleBase::prepare();
|
VulkanExampleBase::prepare();
|
||||||
|
prepareTextureTarget(&textureComputeTarget, TEX_DIM, TEX_DIM, VK_FORMAT_R8G8B8A8_UNORM);
|
||||||
prepareStorageBuffers();
|
prepareStorageBuffers();
|
||||||
prepareUniformBuffers();
|
prepareUniformBuffers();
|
||||||
prepareTextureTarget(&textureComputeTarget, TEX_DIM, TEX_DIM, VK_FORMAT_R8G8B8A8_UNORM);
|
|
||||||
setupDescriptorSetLayout();
|
setupDescriptorSetLayout();
|
||||||
preparePipelines();
|
preparePipelines();
|
||||||
setupDescriptorPool();
|
setupDescriptorPool();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue