зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
87b4f0fbb2
Коммит
ddedcdaff2
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче