Created
July 31, 2017 13:18
-
-
Save HansKristian-Work/b36e4568620b97d81612e916065a16d7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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