Vulkan: Allow for multiple frames in-flight.
This should give us the ability to send off more than one frame to
the presentation engine at once. Instead of using a single pair of
Semaphores to lock each surface, we make a Semaphore pair per
Swapchain image.
BUG=angleproject:1898
Change-Id: I9e833ed9969a79617d0a8968b0d5a25c27139e87
Reviewed-on: https://chromium-review.googlesource.com/672149
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
index 87f6ba8..cbac9c0 100644
--- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
@@ -37,7 +37,7 @@
ASSERT(!presentModes.empty());
// Use FIFO mode for v-sync, since it throttles you to the display rate. Mailbox is more
- // similar to triple-buffering. For now we hard-code Mailbox for perf tseting.
+ // similar to triple-buffering. For now we hard-code Mailbox for perf testing.
// TODO(jmadill): Properly select present mode and re-create display if changed.
VkPresentModeKHR bestChoice = VK_PRESENT_MODE_MAILBOX_KHR;
@@ -183,23 +183,17 @@
rendererVk->finish();
- mImageAvailableSemaphore.destroy(device);
- mRenderingCompleteSemaphore.destroy(device);
+ mAcquireNextImageSemaphore.destroy(device);
- for (auto &imageView : mSwapchainImageViews)
+ for (auto &swapchainImage : mSwapchainImages)
{
- imageView.destroy(device);
- }
+ // Although we don't own the swapchain image handles, we need to keep our shutdown clean.
+ swapchainImage.image.reset();
- // Although we don't own the swapchain image handles, we need to keep our shutdown clean.
- for (auto &image : mSwapchainImages)
- {
- image.reset();
- }
-
- for (auto &framebuffer : mSwapchainFramebuffers)
- {
- framebuffer.destroy(device);
+ swapchainImage.imageView.destroy(device);
+ swapchainImage.framebuffer.destroy(device);
+ swapchainImage.imageAcquiredSemaphore.destroy(device);
+ swapchainImage.commandsCompleteSemaphore.destroy(device);
}
if (mSwapchain)
@@ -365,7 +359,8 @@
transparentBlack.float32[3] = 0.0f;
mSwapchainImages.resize(imageCount);
- mSwapchainImageViews.resize(imageCount);
+
+ ANGLE_TRY(mAcquireNextImageSemaphore.init(device));
for (uint32_t imageIndex = 0; imageIndex < imageCount; ++imageIndex)
{
@@ -397,15 +392,16 @@
commandBuffer);
commandBuffer->clearSingleColorImage(image, transparentBlack);
- mSwapchainImages[imageIndex].retain(device, std::move(image));
- mSwapchainImageViews[imageIndex].retain(device, std::move(imageView));
+ auto &member = mSwapchainImages[imageIndex];
+
+ member.image.retain(device, std::move(image));
+ member.imageView.retain(device, std::move(imageView));
+ ANGLE_TRY(member.imageAcquiredSemaphore.init(device));
+ ANGLE_TRY(member.commandsCompleteSemaphore.init(device));
}
ANGLE_TRY(renderer->submitAndFinishCommandBuffer(commandBuffer));
- ANGLE_TRY(mImageAvailableSemaphore.init(device));
- ANGLE_TRY(mRenderingCompleteSemaphore.init(device));
-
// Get the first available swapchain iamge.
ANGLE_TRY(nextSwapchainImage(renderer));
@@ -429,20 +425,20 @@
FramebufferVk *framebufferVk = GetImplAs<FramebufferVk>(mState.defaultFramebuffer);
framebufferVk->endRenderPass(currentCB);
- auto *image = &mSwapchainImages[mCurrentSwapchainImageIndex];
+ auto &image = mSwapchainImages[mCurrentSwapchainImageIndex];
- image->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
- VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
- VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, currentCB);
+ image.image.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, currentCB);
- ANGLE_TRY(renderer->submitCommandsWithSync(currentCB, mImageAvailableSemaphore,
- mRenderingCompleteSemaphore));
+ ANGLE_TRY(renderer->submitCommandsWithSync(currentCB, image.imageAcquiredSemaphore,
+ image.commandsCompleteSemaphore));
VkPresentInfoKHR presentInfo;
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.pNext = nullptr;
presentInfo.waitSemaphoreCount = 1;
- presentInfo.pWaitSemaphores = mRenderingCompleteSemaphore.ptr();
+ presentInfo.pWaitSemaphores = image.commandsCompleteSemaphore.ptr();
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &mSwapchain;
presentInfo.pImageIndices = &mCurrentSwapchainImageIndex;
@@ -460,13 +456,20 @@
{
VkDevice device = renderer->getDevice();
- ANGLE_VK_TRY(vkAcquireNextImageKHR(device, mSwapchain, std::numeric_limits<uint64_t>::max(),
- mImageAvailableSemaphore.getHandle(), VK_NULL_HANDLE,
+ // Use a timeout of zero for AcquireNextImage so we don't actually block.
+ // TODO(jmadill): We should handle VK_NOT_READY and block until we can acquire the image.
+ ANGLE_VK_TRY(vkAcquireNextImageKHR(device, mSwapchain, 0,
+ mAcquireNextImageSemaphore.getHandle(), VK_NULL_HANDLE,
&mCurrentSwapchainImageIndex));
+ auto &image = mSwapchainImages[mCurrentSwapchainImageIndex];
+
+ // Swap the unused swapchain semaphore and the now active spare semaphore.
+ std::swap(image.imageAcquiredSemaphore, mAcquireNextImageSemaphore);
+
// Update RenderTarget pointers.
- mRenderTarget.image = &mSwapchainImages[mCurrentSwapchainImageIndex];
- mRenderTarget.imageView = &mSwapchainImageViews[mCurrentSwapchainImageIndex];
+ mRenderTarget.image = &image.image;
+ mRenderTarget.imageView = &image.imageView;
return vk::NoError();
}
@@ -544,10 +547,12 @@
VkDevice device,
const vk::RenderPass &compatibleRenderPass)
{
- if (!mSwapchainFramebuffers.empty())
+ auto ¤tFramebuffer = mSwapchainImages[mCurrentSwapchainImageIndex].framebuffer;
+
+ if (currentFramebuffer.valid())
{
// Validation layers should detect if the render pass is really compatible.
- return &mSwapchainFramebuffers[mCurrentSwapchainImageIndex];
+ return ¤tFramebuffer;
}
VkFramebufferCreateInfo framebufferInfo;
@@ -563,22 +568,18 @@
framebufferInfo.height = static_cast<uint32_t>(mRenderTarget.extents.height);
framebufferInfo.layers = 1;
- mSwapchainFramebuffers.resize(mSwapchainImageViews.size());
- for (size_t imageIndex = 0; imageIndex < mSwapchainFramebuffers.size(); ++imageIndex)
+ for (auto &swapchainImage : mSwapchainImages)
{
- const auto &imageView = mSwapchainImageViews[imageIndex];
- VkImageView imageViewHandle = imageView.getHandle();
- framebufferInfo.pAttachments = &imageViewHandle;
+ framebufferInfo.pAttachments = swapchainImage.imageView.ptr();
vk::Framebuffer framebuffer;
ANGLE_TRY(framebuffer.init(device, framebufferInfo));
- mSwapchainFramebuffers[imageIndex].retain(device, std::move(framebuffer));
+ swapchainImage.framebuffer.retain(device, std::move(framebuffer));
}
- // We should only initialize framebuffers on the first swap.
- ASSERT(mCurrentSwapchainImageIndex == 0u);
- return &mSwapchainFramebuffers[mCurrentSwapchainImageIndex];
+ ASSERT(currentFramebuffer.valid());
+ return ¤tFramebuffer;
}
} // namespace rx