Commit 1c79e9ea by Ian Elliott Committed by Commit Bot

Vulkan: Delay vkAcquireNextImageKHR till later

Currently, ANGLE calls vkAcquireNextImageKHR() immediately after calling vkQueuePresentKHR(), which can cause the process to stall (even with multi-threading). Delay it until it is absoluately needed. Test: angle_end2end_tests --gtest_filter=*EGLPreRotationSurfaceTest*/* Test: angle_white_box_tests --gtest_filter=VulkanPerformanceCounterTest.*Invalidate*/* Test: angle_deqp_egl_tests --gtest_filter=dEQP.EGL/functional_query_context_get_current_display_rgba8888_window* --use-angle=vulkan Test: angle_perftests --gtest_filter=GenerateMipmapBenchmark.Run/vulkan_webgl Bug: angleproject:5064 Bug: b/162082698 Change-Id: I466df9237136dd59a9556faa8cf2dbad94e076fe Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2399509Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Ian Elliott <ianelliott@google.com>
parent 37457d08
...@@ -1705,7 +1705,12 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -1705,7 +1705,12 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0); dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
} }
ASSERT(!previousDeferredClears.test(colorIndexGL)); // TODO: uncomment the following ASSERT once deferred clears don't exist if
// Context::prepareForDraw() returns an error (and the draw doesn't process the
// deferred clear). http://anglebug.com/5064
//
// ASSERT(!previousDeferredClears.test(colorIndexGL));
ANGLE_TRY(updateColorAttachment(context, deferClears, colorIndexGL)); ANGLE_TRY(updateColorAttachment(context, deferClears, colorIndexGL));
shouldUpdateColorMask = true; shouldUpdateColorMask = true;
break; break;
......
...@@ -477,7 +477,8 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ ...@@ -477,7 +477,8 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ
mCurrentSwapHistoryIndex(0), mCurrentSwapHistoryIndex(0),
mCurrentSwapchainImageIndex(0), mCurrentSwapchainImageIndex(0),
mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex), mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex),
mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex) mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex),
mNeedToAcquireNextSwapchainImage(false)
{ {
// Initialize the color render target with the multisampled targets. If not multisampled, the // Initialize the color render target with the multisampled targets. If not multisampled, the
// render target will be updated to refer to a swapchain image on every acquire. // render target will be updated to refer to a swapchain image on every acquire.
...@@ -672,7 +673,7 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) ...@@ -672,7 +673,7 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
ANGLE_TRY(createSwapChain(displayVk, extents, VK_NULL_HANDLE)); ANGLE_TRY(createSwapChain(displayVk, extents, VK_NULL_HANDLE));
VkResult vkResult = nextSwapchainImage(displayVk); VkResult vkResult = acquireNextSwapchainImage(displayVk);
// VK_SUBOPTIMAL_KHR is ok since we still have an Image that can be presented successfully // VK_SUBOPTIMAL_KHR is ok since we still have an Image that can be presented successfully
if (ANGLE_UNLIKELY((vkResult != VK_SUCCESS) && (vkResult != VK_SUBOPTIMAL_KHR))) if (ANGLE_UNLIKELY((vkResult != VK_SUCCESS) && (vkResult != VK_SUBOPTIMAL_KHR)))
{ {
...@@ -682,9 +683,21 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) ...@@ -682,9 +683,21 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result WindowSurfaceVk::recreateSwapchain(ContextVk *contextVk, angle::Result WindowSurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
const gl::Extents &extents, GLenum binding,
uint32_t swapHistoryIndex) const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut)
{
if (mNeedToAcquireNextSwapchainImage)
{
// Acquire the next image (previously deferred) before it is drawn to or read from.
ANGLE_TRY(doDeferredAcquireNextImage(context, false));
}
return SurfaceVk::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
}
angle::Result WindowSurfaceVk::recreateSwapchain(ContextVk *contextVk, const gl::Extents &extents)
{ {
// If mOldSwapchains is not empty, it means that a new swapchain was created, but before // If mOldSwapchains is not empty, it means that a new swapchain was created, but before
// any of its images were presented, it's asked to be recreated. In this case, we can destroy // any of its images were presented, it's asked to be recreated. In this case, we can destroy
...@@ -989,7 +1002,6 @@ bool WindowSurfaceVk::isMultiSampled() const ...@@ -989,7 +1002,6 @@ bool WindowSurfaceVk::isMultiSampled() const
} }
angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk, angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk,
uint32_t swapHistoryIndex,
bool presentOutOfDate) bool presentOutOfDate)
{ {
bool swapIntervalChanged = mSwapchainPresentMode != mDesiredSwapchainPresentMode; bool swapIntervalChanged = mSwapchainPresentMode != mDesiredSwapchainPresentMode;
...@@ -1032,7 +1044,7 @@ angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk, ...@@ -1032,7 +1044,7 @@ angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk,
// Work-around for some device which does not return OUT_OF_DATE after window resizing // Work-around for some device which does not return OUT_OF_DATE after window resizing
if (swapIntervalChanged || presentOutOfDate || currentExtents != swapchainExtents) if (swapIntervalChanged || presentOutOfDate || currentExtents != swapchainExtents)
{ {
ANGLE_TRY(recreateSwapchain(contextVk, currentExtents, swapHistoryIndex)); ANGLE_TRY(recreateSwapchain(contextVk, currentExtents));
} }
} }
...@@ -1317,30 +1329,69 @@ angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context, ...@@ -1317,30 +1329,69 @@ angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context,
ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::swapImpl"); ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::swapImpl");
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
bool presentOutOfDate = false; if (mNeedToAcquireNextSwapchainImage)
// Save this now, since present() will increment the value. {
uint32_t currentSwapHistoryIndex = static_cast<uint32_t>(mCurrentSwapHistoryIndex); // Acquire the next image (previously deferred). The image may not have been already
// acquired if there was no rendering done at all to the default framebuffer in this frame,
// for example if all rendering was done to FBOs.
ANGLE_TRY(doDeferredAcquireNextImage(context, false));
}
bool presentOutOfDate = false;
ANGLE_TRY(present(contextVk, rects, n_rects, pNextChain, &presentOutOfDate)); ANGLE_TRY(present(contextVk, rects, n_rects, pNextChain, &presentOutOfDate));
ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, currentSwapHistoryIndex, presentOutOfDate)); if (!presentOutOfDate)
{
// Defer acquiring the next swapchain image since the swapchain is not out-of-date.
deferAcquireNextImage(context);
}
else
{
// Immediately try to acquire the next image, which will recognize the out-of-date
// swapchain (potentially because of a rotation change), and recreate it.
ANGLE_TRY(doDeferredAcquireNextImage(context, presentOutOfDate));
}
return angle::Result::Continue;
}
void WindowSurfaceVk::deferAcquireNextImage(const gl::Context *context)
{
mNeedToAcquireNextSwapchainImage = true;
// Set gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 via subject-observer message-passing
// to the front-end Surface, Framebuffer, and Context classes. The DIRTY_BIT_COLOR_ATTACHMENT_0
// is processed before all other dirty bits. However, since the attachments of the default
// framebuffer cannot change, this bit will be processed before all others. It will cause
// WindowSurfaceVk::getAttachmentRenderTarget() to be called (which will acquire the next image)
// before any RenderTargetVk accesses. The processing of other dirty bits as well as other
// setup for draws and reads will then access a properly-updated RenderTargetVk.
onStateChange(angle::SubjectMessage::SubjectChanged);
}
angle::Result WindowSurfaceVk::doDeferredAcquireNextImage(const gl::Context *context,
bool presentOutOfDate)
{
ContextVk *contextVk = vk::GetImpl(context);
DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, presentOutOfDate));
{ {
// Note: TRACE_EVENT0 is put here instead of inside the function to workaround this issue: // Note: TRACE_EVENT0 is put here instead of inside the function to workaround this issue:
// http://anglebug.com/2927 // http://anglebug.com/2927
ANGLE_TRACE_EVENT0("gpu.angle", "nextSwapchainImage"); ANGLE_TRACE_EVENT0("gpu.angle", "acquireNextSwapchainImage");
// Get the next available swapchain image. // Get the next available swapchain image.
VkResult result = nextSwapchainImage(contextVk); VkResult result = acquireNextSwapchainImage(contextVk);
// If SUBOPTIMAL/OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain // If SUBOPTIMAL/OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain
// before continuing. // before continuing.
if (ANGLE_UNLIKELY((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR))) if (ANGLE_UNLIKELY((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR)))
{ {
ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, currentSwapHistoryIndex, true)); ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, true));
// Try one more time and bail if we fail // Try one more time and bail if we fail
result = nextSwapchainImage(contextVk); result = acquireNextSwapchainImage(contextVk);
} }
ANGLE_VK_TRY(contextVk, result); ANGLE_VK_TRY(contextVk, result);
} }
...@@ -1351,7 +1402,7 @@ angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context, ...@@ -1351,7 +1402,7 @@ angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
VkResult WindowSurfaceVk::nextSwapchainImage(vk::Context *context) VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context)
{ {
VkDevice device = context->getDevice(); VkDevice device = context->getDevice();
...@@ -1389,6 +1440,9 @@ VkResult WindowSurfaceVk::nextSwapchainImage(vk::Context *context) ...@@ -1389,6 +1440,9 @@ VkResult WindowSurfaceVk::nextSwapchainImage(vk::Context *context)
onStateChange(angle::SubjectMessage::SubjectChanged); onStateChange(angle::SubjectMessage::SubjectChanged);
} }
// Note that an acquire is no longer needed.
mNeedToAcquireNextSwapchainImage = false;
return VK_SUCCESS; return VK_SUCCESS;
} }
...@@ -1548,6 +1602,9 @@ angle::Result WindowSurfaceVk::getCurrentFramebuffer(ContextVk *contextVk, ...@@ -1548,6 +1602,9 @@ angle::Result WindowSurfaceVk::getCurrentFramebuffer(ContextVk *contextVk,
const vk::RenderPass &compatibleRenderPass, const vk::RenderPass &compatibleRenderPass,
vk::Framebuffer **framebufferOut) vk::Framebuffer **framebufferOut)
{ {
// FramebufferVk dirty-bit processing should ensure that a new image was acquired.
ASSERT(!mNeedToAcquireNextSwapchainImage);
vk::Framebuffer &currentFramebuffer = vk::Framebuffer &currentFramebuffer =
isMultiSampled() ? mFramebufferMS isMultiSampled() ? mFramebufferMS
: mSwapchainImages[mCurrentSwapchainImageIndex].framebuffer; : mSwapchainImages[mCurrentSwapchainImageIndex].framebuffer;
...@@ -1621,6 +1678,14 @@ angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context, ...@@ -1621,6 +1678,14 @@ angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context,
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
if (mNeedToAcquireNextSwapchainImage)
{
// Acquire the next image (previously deferred). Some tests (e.g.
// GenerateMipmapWithRedefineBenchmark.Run/vulkan_webgl) cause this path to be taken,
// because of dirty-object processing.
ANGLE_TRY(doDeferredAcquireNextImage(context, false));
}
ASSERT(mSwapchainImages.size() > 0); ASSERT(mSwapchainImages.size() > 0);
ASSERT(mCurrentSwapchainImageIndex < mSwapchainImages.size()); ASSERT(mCurrentSwapchainImageIndex < mSwapchainImages.size());
......
...@@ -193,6 +193,11 @@ class WindowSurfaceVk : public SurfaceVk ...@@ -193,6 +193,11 @@ class WindowSurfaceVk : public SurfaceVk
void destroy(const egl::Display *display) override; void destroy(const egl::Display *display) override;
egl::Error initialize(const egl::Display *display) override; egl::Error initialize(const egl::Display *display) override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
FramebufferImpl *createDefaultFramebuffer(const gl::Context *context, FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) override; const gl::FramebufferState &state) override;
egl::Error swap(const gl::Context *context) override; egl::Error swap(const gl::Context *context) override;
...@@ -255,19 +260,24 @@ class WindowSurfaceVk : public SurfaceVk ...@@ -255,19 +260,24 @@ class WindowSurfaceVk : public SurfaceVk
virtual angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) = 0; virtual angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) = 0;
angle::Result initializeImpl(DisplayVk *displayVk); angle::Result initializeImpl(DisplayVk *displayVk);
angle::Result recreateSwapchain(ContextVk *contextVk, angle::Result recreateSwapchain(ContextVk *contextVk, const gl::Extents &extents);
const gl::Extents &extents,
uint32_t swapHistoryIndex);
angle::Result createSwapChain(vk::Context *context, angle::Result createSwapChain(vk::Context *context,
const gl::Extents &extents, const gl::Extents &extents,
VkSwapchainKHR oldSwapchain); VkSwapchainKHR oldSwapchain);
angle::Result checkForOutOfDateSwapchain(ContextVk *contextVk, angle::Result checkForOutOfDateSwapchain(ContextVk *contextVk, bool presentOutOfDate);
uint32_t swapHistoryIndex,
bool presentOutOfDate);
angle::Result resizeSwapchainImages(vk::Context *context, uint32_t imageCount); angle::Result resizeSwapchainImages(vk::Context *context, uint32_t imageCount);
void releaseSwapchainImages(ContextVk *contextVk); void releaseSwapchainImages(ContextVk *contextVk);
void destroySwapChainImages(DisplayVk *displayVk); void destroySwapChainImages(DisplayVk *displayVk);
VkResult nextSwapchainImage(vk::Context *context); // This method calls vkAcquireNextImageKHR() to acquire the next swapchain image. It is called
// when the swapchain is initially created and when present() finds the swapchain out of date.
// Otherwise, it is scheduled to be called later by deferAcquireNextImage().
VkResult acquireNextSwapchainImage(vk::Context *context);
// This method is called when a swapchain image is presented. It schedules
// acquireNextSwapchainImage() to be called later.
void deferAcquireNextImage(const gl::Context *context);
// Called when a swapchain image whose acquisition was deferred must be acquired. This method
// will recreate the swapchain (if needed) and call the acquireNextSwapchainImage() method.
angle::Result doDeferredAcquireNextImage(const gl::Context *context, bool presentOutOfDate);
angle::Result present(ContextVk *contextVk, angle::Result present(ContextVk *contextVk,
EGLint *rects, EGLint *rects,
EGLint n_rects, EGLint n_rects,
...@@ -323,6 +333,9 @@ class WindowSurfaceVk : public SurfaceVk ...@@ -323,6 +333,9 @@ class WindowSurfaceVk : public SurfaceVk
vk::ImageViewHelper mColorImageMSViews; vk::ImageViewHelper mColorImageMSViews;
angle::ObserverBinding mColorImageMSBinding; angle::ObserverBinding mColorImageMSBinding;
vk::Framebuffer mFramebufferMS; vk::Framebuffer mFramebufferMS;
// True when acquiring the next image is deferred.
bool mNeedToAcquireNextSwapchainImage;
}; };
} // namespace rx } // namespace rx
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment