Vulkan: Recycle vkAcquireNextImageKHR semaphores

This change optimizes CPU performance by recycling semaphores used for
ANI instead of creating and deleting them every frame.

Bug: angleproject:6580
Change-Id: I151ea227870ed7b8bd123cbf629a65723c4696d2
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3225085
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Ian Elliott <ianelliott@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Shahbaz Youssefi 2021-10-14 23:35:45 -04:00 коммит произвёл Angle LUCI CQ
Родитель 87b4f0fbb2
Коммит ddedcdaff2
3 изменённых файлов: 56 добавлений и 20 удалений

Просмотреть файл

@ -2152,12 +2152,12 @@ angle::Result ContextVk::submitFrame(const vk::Semaphore *signalSemaphore, Seria
{
if (mCurrentWindowSurface)
{
vk::Semaphore waitSemaphore = mCurrentWindowSurface->getAcquireImageSemaphore();
if (waitSemaphore.valid())
const vk::Semaphore *waitSemaphore =
mCurrentWindowSurface->getAndResetAcquireImageSemaphore();
if (waitSemaphore != nullptr)
{
addWaitSemaphore(waitSemaphore.getHandle(),
addWaitSemaphore(waitSemaphore->getHandle(),
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
addGarbage(&waitSemaphore);
}
}

Просмотреть файл

@ -503,6 +503,7 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ
mEmulatedPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR),
mCompositeAlpha(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR),
mCurrentSwapchainImageIndex(0),
mAcquireImageSemaphore(nullptr),
mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex),
mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex),
mNeedToAcquireNextSwapchainImage(false),
@ -542,6 +543,10 @@ void WindowSurfaceVk::destroy(const egl::Display *display)
mSwapchain = VK_NULL_HANDLE;
}
for (vk::Semaphore &semaphore : mAcquireImageSemaphores)
{
semaphore.destroy(device);
}
for (SwapchainCleanupData &oldSwapchain : mOldSwapchains)
{
oldSwapchain.destroy(device, &mPresentSemaphoreRecycler);
@ -554,7 +559,6 @@ void WindowSurfaceVk::destroy(const egl::Display *display)
mSurface = VK_NULL_HANDLE;
}
mAcquireImageSemaphore.destroy(device);
mPresentSemaphoreRecycler.destroy(device);
}
@ -802,6 +806,12 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
ANGLE_TRY(createSwapChain(displayVk, extents, VK_NULL_HANDLE));
// Create the semaphores that will be used for vkAcquireNextImageKHR.
for (vk::Semaphore &semaphore : mAcquireImageSemaphores)
{
ANGLE_VK_TRY(displayVk, semaphore.init(displayVk->getDevice()));
}
VkResult vkResult = acquireNextSwapchainImage(displayVk);
ASSERT(vkResult != VK_SUBOPTIMAL_KHR);
ANGLE_VK_TRY(displayVk, vkResult);
@ -1499,7 +1509,7 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
presentInfo.pNext = &presentRegions;
}
ASSERT(!mAcquireImageSemaphore.valid());
ASSERT(mAcquireImageSemaphore == nullptr);
VkResult result = renderer->queuePresent(contextVk, contextVk->getPriority(), presentInfo);
@ -1610,16 +1620,12 @@ VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context)
{
VkDevice device = context->getDevice();
vk::DeviceScoped<vk::Semaphore> acquireImageSemaphore(device);
VkResult result = acquireImageSemaphore.get().init(device);
if (ANGLE_UNLIKELY(result != VK_SUCCESS))
{
return result;
}
const vk::Semaphore *acquireImageSemaphore = &mAcquireImageSemaphores.front();
ASSERT(acquireImageSemaphore->valid());
result = vkAcquireNextImageKHR(device, mSwapchain, UINT64_MAX,
acquireImageSemaphore.get().getHandle(), VK_NULL_HANDLE,
&mCurrentSwapchainImageIndex);
VkResult result =
vkAcquireNextImageKHR(device, mSwapchain, UINT64_MAX, acquireImageSemaphore->getHandle(),
VK_NULL_HANDLE, &mCurrentSwapchainImageIndex);
// VK_SUBOPTIMAL_KHR is ok since we still have an Image that can be presented successfully
if (ANGLE_UNLIKELY(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR))
{
@ -1627,7 +1633,8 @@ VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context)
}
// The semaphore will be waited on in the next flush.
mAcquireImageSemaphore = acquireImageSemaphore.release();
mAcquireImageSemaphores.next();
mAcquireImageSemaphore = acquireImageSemaphore;
SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
@ -1887,9 +1894,11 @@ angle::Result WindowSurfaceVk::getCurrentFramebuffer(ContextVk *contextVk,
return angle::Result::Continue;
}
vk::Semaphore WindowSurfaceVk::getAcquireImageSemaphore()
const vk::Semaphore *WindowSurfaceVk::getAndResetAcquireImageSemaphore()
{
return std::move(mAcquireImageSemaphore);
const vk::Semaphore *acquireSemaphore = mAcquireImageSemaphore;
mAcquireImageSemaphore = nullptr;
return acquireSemaphore;
}
angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context,

Просмотреть файл

@ -236,7 +236,7 @@ class WindowSurfaceVk : public SurfaceVk
const vk::RenderPass &compatibleRenderPass,
vk::Framebuffer **framebufferOut);
vk::Semaphore getAcquireImageSemaphore();
const vk::Semaphore *getAndResetAcquireImageSemaphore();
VkSurfaceTransformFlagBitsKHR getPreTransform() const
{
@ -328,9 +328,36 @@ class WindowSurfaceVk : public SurfaceVk
std::vector<impl::SwapchainImage> mSwapchainImages;
std::vector<angle::ObserverBinding> mSwapchainImageBindings;
vk::Semaphore mAcquireImageSemaphore;
uint32_t mCurrentSwapchainImageIndex;
// Given that the CPU is throttled after a number of swaps, there is an upper bound to the
// number of semaphores that are used to acquire swapchain images, and that is
// kSwapHistorySize+1:
//
// Unrelated submission in Submission as part of
// the middle of frame buffer swap
// | |
// V V
// Frame i: ... ANI ... QS (fence Fa) ... Wait(..) QS (Fence Fb) QP
// Frame i+1: ... ANI ... QS (fence Fc) ... Wait(..) QS (Fence Fd) QP
// Frame i+2: ... ANI ... QS (fence Fe) ... Wait(Fb) QS (Fence Ff) QP
// ^
// |
// CPU throttling
//
// In frame i+2 (2 is kSwapHistorySize), ANGLE waits on fence Fb which means that the semaphore
// used for Frame i's ANI can be reused (because Fb-is-signalled implies Fa-is-signalled).
// Before this wait, there were three acquire semaphores in use corresponding to frames i, i+1
// and i+2. Frame i+3 can reuse the semaphore of frame i.
angle::CircularBuffer<vk::Semaphore, impl::kSwapHistorySize + 1> mAcquireImageSemaphores;
// A pointer to mAcquireImageSemaphores. This is set when an image is acquired and is waited on
// by the next submission (which uses this image), at which point it is reset so future
// submissions don't wait on it until the next acquire.
const vk::Semaphore *mAcquireImageSemaphore;
// There is no direct signal from Vulkan regarding when a Present semaphore can be be reused.
// During window resizing when swapchains are recreated every frame, the number of in-flight
// present semaphores can grow indefinitely. See doc/PresentSemaphores.md.
vk::Recycler<vk::Semaphore> mPresentSemaphoreRecycler;
// Depth/stencil image. Possibly multisampled.