Skip to content

Commit 31dadbe

Browse files
committed
Fix and optimize synchronization
Use a fence to fully ensure a RenderProcess is done before re- using it. Optimize by removing the GPU-to-CPU synchronization with the previously used fence that was waited upon right after submitting draw calls to the draw queue. Use proper subpass dependencies instead.
1 parent 1d29f9b commit 31dadbe

File tree

4 files changed

+50
-17
lines changed

4 files changed

+50
-17
lines changed

src/Headset.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,33 @@ Headset::Headset(const Context* context) : context(context)
8080
resolveAttachmentReference.attachment = 2u;
8181
resolveAttachmentReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
8282

83+
// This subpass dependency waits with the transition to the color attachment optimal layout that takes place when
84+
// calling vkCmdBeginRenderPass() until the draw calls in the render pass are in the appropriate pipeline stages
85+
VkSubpassDependency subpassDependencyRenderPassBegin;
86+
subpassDependencyRenderPassBegin.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
87+
subpassDependencyRenderPassBegin.srcSubpass = VK_SUBPASS_EXTERNAL;
88+
subpassDependencyRenderPassBegin.dstSubpass = 0;
89+
subpassDependencyRenderPassBegin.srcAccessMask = VK_ACCESS_NONE;
90+
subpassDependencyRenderPassBegin.dstAccessMask =
91+
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
92+
subpassDependencyRenderPassBegin.srcStageMask =
93+
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
94+
subpassDependencyRenderPassBegin.dstStageMask =
95+
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
96+
97+
// This subpass dependency ensures that all color and depth/stencil attachment writes in the color attachment output
98+
// and late fragment tests stages have finished before any draw calls after vkCmdEndRenderPass() begin
99+
VkSubpassDependency subpassDependencyRenderPassEnd;
100+
subpassDependencyRenderPassEnd.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
101+
subpassDependencyRenderPassEnd.srcSubpass = 0;
102+
subpassDependencyRenderPassEnd.dstSubpass = VK_SUBPASS_EXTERNAL;
103+
subpassDependencyRenderPassEnd.srcAccessMask =
104+
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
105+
subpassDependencyRenderPassEnd.dstAccessMask = VK_ACCESS_NONE;
106+
subpassDependencyRenderPassEnd.srcStageMask =
107+
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
108+
subpassDependencyRenderPassEnd.dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
109+
83110
VkSubpassDescription subpassDescription{};
84111
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
85112
subpassDescription.colorAttachmentCount = 1u;
@@ -90,12 +117,16 @@ Headset::Headset(const Context* context) : context(context)
90117
const std::array attachments = { colorAttachmentDescription, depthAttachmentDescription,
91118
resolveAttachmentDescription };
92119

120+
const std::array subpassDependencies = { subpassDependencyRenderPassBegin, subpassDependencyRenderPassEnd };
121+
93122
VkRenderPassCreateInfo renderPassCreateInfo{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
94123
renderPassCreateInfo.pNext = &renderPassMultiviewCreateInfo;
95124
renderPassCreateInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
96125
renderPassCreateInfo.pAttachments = attachments.data();
97126
renderPassCreateInfo.subpassCount = 1u;
98127
renderPassCreateInfo.pSubpasses = &subpassDescription;
128+
renderPassCreateInfo.dependencyCount = static_cast<uint32_t>(subpassDependencies.size());
129+
renderPassCreateInfo.pDependencies = subpassDependencies.data();
99130
if (vkCreateRenderPass(device, &renderPassCreateInfo, nullptr, &renderPass) != VK_SUCCESS)
100131
{
101132
util::error(Error::GenericVulkan);

src/MirrorView.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ MirrorView::RenderResult MirrorView::render(uint32_t swapchainImageIndex)
179179
sourceImageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
180180
sourceImageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
181181
sourceImageMemoryBarrier.subresourceRange.layerCount = 1u;
182-
sourceImageMemoryBarrier.subresourceRange.baseArrayLayer = mirrorEyeIndex;
182+
sourceImageMemoryBarrier.subresourceRange.baseArrayLayer = static_cast<uint32_t>(mirrorEyeIndex);
183183
sourceImageMemoryBarrier.subresourceRange.levelCount = 1u;
184184
sourceImageMemoryBarrier.subresourceRange.baseMipLevel = 0u;
185185

@@ -229,7 +229,7 @@ MirrorView::RenderResult MirrorView::render(uint32_t swapchainImageIndex)
229229
static_cast<int32_t>(cropOffset.y + cropResolution.y), 1 };
230230
imageBlit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
231231
imageBlit.srcSubresource.mipLevel = 0u;
232-
imageBlit.srcSubresource.baseArrayLayer = mirrorEyeIndex;
232+
imageBlit.srcSubresource.baseArrayLayer = static_cast<uint32_t>(mirrorEyeIndex);
233233
imageBlit.srcSubresource.layerCount = 1u;
234234

235235
imageBlit.dstOffsets[0] = { 0, 0, 0 };
@@ -253,10 +253,10 @@ MirrorView::RenderResult MirrorView::render(uint32_t swapchainImageIndex)
253253
sourceImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
254254
sourceImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
255255
sourceImageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
256-
sourceImageMemoryBarrier.dstAccessMask = VK_ACCESS_NONE;
256+
sourceImageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
257257
sourceImageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
258258
sourceImageMemoryBarrier.subresourceRange.layerCount = 1u;
259-
sourceImageMemoryBarrier.subresourceRange.baseArrayLayer = mirrorEyeIndex;
259+
sourceImageMemoryBarrier.subresourceRange.baseArrayLayer = static_cast<uint32_t>(mirrorEyeIndex);
260260
sourceImageMemoryBarrier.subresourceRange.levelCount = 1u;
261261
sourceImageMemoryBarrier.subresourceRange.baseMipLevel = 0u;
262262

src/RenderProcess.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ RenderProcess::RenderProcess(const Context* context,
6969

7070
// Create a fence
7171
VkFenceCreateInfo fenceCreateInfo{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
72+
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; // Make sure the fence starts off signaled
7273
if (vkCreateFence(device, &fenceCreateInfo, nullptr, &busyFence) != VK_SUCCESS)
7374
{
7475
util::error(Error::GenericVulkan);

src/Renderer.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,20 @@ void Renderer::render(const glm::mat4& cameraMatrix, size_t swapchainImageIndex,
246246

247247
RenderProcess* renderProcess = renderProcesses.at(currentRenderProcessIndex);
248248

249+
const VkDevice device = context->getVkDevice();
250+
const VkFence busyFence = renderProcess->getBusyFence();
251+
252+
// Wait until the render process is free to use again
253+
if (vkWaitForFences(device, 1u, &busyFence, VK_TRUE, UINT64_MAX) != VK_SUCCESS)
254+
{
255+
return;
256+
}
257+
258+
if (vkResetFences(device, 1u, &busyFence) != VK_SUCCESS)
259+
{
260+
return;
261+
}
262+
249263
const VkCommandBuffer commandBuffer = renderProcess->getCommandBuffer();
250264
if (vkResetCommandBuffer(commandBuffer, 0u) != VK_SUCCESS)
251265
{
@@ -375,19 +389,6 @@ void Renderer::submit(bool useSemaphores) const
375389
{
376390
return;
377391
}
378-
379-
// Now that all draw calls have been submitted to the draw queue, we use a fence to ensure that they are all finished
380-
// executing before moving on and giving control back to the OpenXR runtime by calling xrReleaseSwapchainImage()
381-
const VkDevice device = context->getVkDevice();
382-
if (vkWaitForFences(device, 1u, &busyFence, VK_TRUE, UINT64_MAX) != VK_SUCCESS)
383-
{
384-
return;
385-
}
386-
387-
if (vkResetFences(device, 1u, &busyFence) != VK_SUCCESS)
388-
{
389-
return;
390-
}
391392
}
392393

393394
bool Renderer::isValid() const

0 commit comments

Comments
 (0)