Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save HansKristian-Work/b36e4568620b97d81612e916065a16d7 to your computer and use it in GitHub Desktop.

Select an option

Save HansKristian-Work/b36e4568620b97d81612e916065a16d7 to your computer and use it in GitHub Desktop.
From b13c7f0090055f5c0277355fb86640b517841d5a Mon Sep 17 00:00:00 2001
From: Hans-Kristian Arntzen <[email protected]>
Date: Mon, 31 Jul 2017 15:19:26 +0200
Subject: [PATCH] Some fixes, clarifications and cleanups of the
synchronization page.
---
Synchronization-Examples.md | 105 +++++++++++++++++++++++---------------------
1 file changed, 56 insertions(+), 49 deletions(-)
diff --git a/Synchronization-Examples.md b/Synchronization-Examples.md
index 9e4df8b..e6495b9 100644
--- a/Synchronization-Examples.md
+++ b/Synchronization-Examples.md
@@ -275,7 +275,7 @@ vkCmdDispatch(...);
##### Draw writes to a depth attachment. Dispatch samples from that image.
-Note that depth attachment write is NOT in the fragment shader, it has its own dedicated pipeline stage!
+Note that depth attachment write is NOT in the fragment shader, it has its own dedicated pipeline stages!
```c
vkCmdDraw(...);
@@ -308,6 +308,8 @@ vkCmdDispatch(...);
Many graphics to graphics dependencies can be expressed as a subpass dependency within a render pass, which is usually more efficient than a pipeline barrier or event. Where this is possible in the below, the example is expressed in terms of a subpass dependency.
+The transition from DEPTH_ATTACHMENT_OPTIMAL to SHADER_READ_ONLY happens automatically as part of executing the render pass.
+
##### First draw writes to a depth attachment. Second draw reads from it as an input attachment in the fragment shader.
```c
@@ -347,8 +349,17 @@ VkSubpassDependency dependency = {
.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT};
+// If initialLayout does not match the layout of the attachment reference in the first subpass, there will be an implicit transition before starting the render pass.
+// If finalLayout does not match the layout of the attachment reference in the last subpass, there will be an implicit transition at the end.
+VkAttachmentDescription depthFramebufferAttachment = {
+ ...
+ .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY};
+
VkRenderPassCreateInfo renderPassCreateInfo = {
...
+ .attachmentCount = 1,
+ .pAttachments = &depthFramebufferAttachment,
.subpassCount = 2,
.pSubpasses = subpasses,
.dependencyCount = 1,
@@ -431,8 +442,17 @@ VkSubpassDependency dependency = {
.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT};
+// If initialLayout does not match the layout of the attachment reference in the first subpass, there will be an implicit transition before starting the render pass.
+// If finalLayout does not match the layout of the attachment reference in the last subpass, there will be an implicit transition at the end.
+VkAttachmentDescription colorFramebufferAttachment = {
+ ...
+ .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY};
+
VkRenderPassCreateInfo renderPassCreateInfo = {
...
+ .attachmentCount = 1,
+ .pAttachments = &colorFramebufferAttachment,
.subpassCount = 2,
.pSubpasses = subpasses,
.dependencyCount = 1,
@@ -542,6 +562,8 @@ If you have a dependency where the two commands being synchronized have a semaph
// Nothing to see here - semaphore alone is sufficient.
// No additional synchronization required - remove those barriers.
```
+Signalling a semaphore waits for all stages to complete, and all memory accesses are flushed automatically.
+Similarly, waiting for a semaphore does the other half of the barrier automatically.
##### Dependency between images where a layout transition is required, expressed before the semaphore signal
@@ -607,19 +629,28 @@ VkSubpassDescription subpass = {
VkSubpassDependency dependency = {
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
+ // .srcStageMask needs to be a part of pWaitDstStageMask in the WSI semaphore.
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dependencyFlags = 0};
+/* Normally, we would need an external dependency at the end as well since we are changing layout in finalLayout,
+ but since we are signalling a semaphore, we can rely on Vulkan's default behavior,
+ which injects an external dependency here with
+ dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ dstAccessMask = 0. */
+
VkAttachmentDescription attachmentDescription = {
...
.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
...
+ // The image will automatically be transitioned from UNDEFINED to COLOR_ATTACHMENT_OPTIMAL.
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
- .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
+ // Presenting images in Vulkan requires a special layout.
+ .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR};
VkRenderPassCreateInfo renderPassCreateInfo = {
...
@@ -703,38 +734,22 @@ VkRenderPassCreateInfo renderPassCreateInfo = {
vkCreateRenderPass(...);
```
-Post-Acquire commands - presentation queue
-```c
-VkImageMemoryBarrier imageMemoryBarrier = {
- ...
- .srcAccessMask = 0,
- .dstAccessMask = 0,
- .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
- .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- .srcQueueFamilyIndex = presentQueueFamilyIndex, // index of the present queue family
- .dstQueueFamilyIndex = graphicsQueueFamilyIndex, // index of the graphics queue family
- /* .image and .subresourceRange should identify image subresource accessed */};
-
-vkCmdPipelineBarrier(
- ...
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask
- VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // dstStageMask
- ...
- 1, // imageMemoryBarrierCount
- &imageMemoryBarrier, // pImageMemoryBarriers
- ...);
-```
-
Rendering command buffer - graphics queue
```c
+/* Queue ownership transfer is only required when we need the content to remain valid across queues.
+ Since we are transitioning from UNDEFINED -- and therefore discarding the image contents to begin with --
+ we are not required to perform an ownership transfer from the presentation queue to graphics.
+
+ This transition could also be made as an EXTERNAL -> subpass #0 render pass dependency as shown earlier. */
+
VkImageMemoryBarrier imageMemoryBarrier = {
...
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- .srcQueueFamilyIndex = presentQueueFamilyIndex, // index of the present queue family
- .dstQueueFamilyIndex = graphicsQueueFamilyIndex, // index of the graphics queue family
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
/* .image and .subresourceRange should identify image subresource accessed */};
vkCmdPipelineBarrier(
@@ -749,13 +764,13 @@ vkCmdPipelineBarrier(
... // Render pass submission.
-
+// Queue release operation. dstAccessMask should always be 0.
VkImageMemoryBarrier imageMemoryBarrier = {
...
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = 0,
.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.srcQueueFamilyIndex = graphicsQueueFamilyIndex, // index of the graphics queue family
.dstQueueFamilyIndex = presentQueueFamilyIndex, // index of the present queue family
/* .image and .subresourceRange should identify image subresource accessed */};
@@ -777,8 +792,11 @@ VkImageMemoryBarrier imageMemoryBarrier = {
...
.srcAccessMask = 0,
.dstAccessMask = 0,
+ // A layout transition which happens as part of an ownership transfer needs to be specified twice one for the release, and one for the acquire.
+ // No srcAccessMask is needed, waiting for a semaphore does that automatically.
+ // No dstAccessMask is needed, signalling a semaphore does that automatically.
.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.srcQueueFamilyIndex = graphicsQueueFamilyIndex, // index of the graphics queue family
.dstQueueFamilyIndex = presentQueueFamilyIndex, // index of the present queue family
/* .image and .subresourceRange should identify image subresource accessed */};
@@ -801,44 +819,33 @@ vkAcquireNextImageKHR(
...
&imageIndex); //image index
-VkPipelineStageFlags waitDstStageMask1 = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+vkQueueSubmit(presentQueue, &submitInfo1, ...);
+
+VkPipelineStageFlags waitDstStageMask1 = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submitInfo1 = {
...
.waitSemaphoreCount = 1,
.pWaitSemaphores = &acquireSemaphore,
.pWaitDstStageMask = &waitDstStageMask1,
.commandBufferCount = 1,
- .pCommandBuffers = &postAcquireCommandBuffer,
- .signalSemaphoreCount = 1,
- .pSignalSemaphores = &ownershipAcquireSemaphore};
-
-vkQueueSubmit(presentQueue, &submitInfo1, ...);
-
-VkPipelineStageFlags waitDstStageMask2 = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-VkSubmitInfo submitInfo2 = {
- ...
- .waitSemaphoreCount = 1,
- .pWaitSemaphores = &ownershipAcquireSemaphore,
- .pWaitDstStageMask = &waitDstStageMask2,
- .commandBufferCount = 1,
.pCommandBuffers = &renderingCommandBuffer,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &graphicsSemaphore};
-vkQueueSubmit(renderQueue, &submitInfo2, ...);
+vkQueueSubmit(renderQueue, &submitInfo1, ...);
-VkPipelineStageFlags waitDstStageMask3 = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
-VkSubmitInfo submitInfo3 = {
+VkPipelineStageFlags waitDstStageMask2 = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+VkSubmitInfo submitInfo2 = {
...
.waitSemaphoreCount = 1,
.pWaitSemaphores = &graphicsSemaphore,
- .pWaitDstStageMask = &waitDstStageMask3,
+ .pWaitDstStageMask = &waitDstStageMask2,
.commandBufferCount = 1,
.pCommandBuffers = &prePresentCommandBuffer,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &ownershipPresentSemaphore};
-vkQueueSubmit(presentQueue, &submitInfo3, ...);
+vkQueueSubmit(presentQueue, &submitInfo2, ...);
VkPresentInfoKHR presentInfo = {
.waitSemaphoreCount = 1,
@@ -854,4 +861,4 @@ vkQueuePresentKHR(..., &presentInfo);
* More external subpass examples?
* Event example?
* External dependencies
-* Safely aliasing resources
\ No newline at end of file
+* Safely aliasing resources
--
2.13.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment