Commit ab5acbd5 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: implement swapchain resizing

Vulkan allows a swapchain to be created based off of an older swapchain that's still presenting, to support seamless window resizing. The old swapchain will remain alive (though no image can be acquired from it) and automatically cleaned once no image is being presented from it. The retired swapchain can be destroyed once all operations on its images are completed. We store the old swapchain next to the serial of submission that's used for CPU throttling and defer the destroy call until after `finishToSerial` for that serial is called. Bug: angleproject:2942 Change-Id: Ic62a5a57b712ffa2b087f5fecde0dc8942194075 Reviewed-on: https://chromium-review.googlesource.com/c/1435634 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent 088e5217
...@@ -141,12 +141,25 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -141,12 +141,25 @@ class WindowSurfaceVk : public SurfaceImpl
private: private:
virtual angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) = 0; virtual angle::Result createSurfaceVk(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(DisplayVk *displayVk,
const gl::Extents &extents,
uint32_t swapHistoryIndex);
angle::Result checkForOutOfDateSwapchain(DisplayVk *displayVk,
uint32_t swapHistoryIndex,
bool presentOutOfDate);
void releaseSwapchainImages(RendererVk *renderer);
angle::Result nextSwapchainImage(DisplayVk *displayVk); angle::Result nextSwapchainImage(DisplayVk *displayVk);
angle::Result swapImpl(DisplayVk *displayVk, EGLint *rects, EGLint n_rects); angle::Result swapImpl(DisplayVk *displayVk, EGLint *rects, EGLint n_rects);
VkSwapchainKHR mSwapchain; VkSwapchainKHR mSwapchain;
// Cached information used to recreate swapchains.
VkPresentModeKHR mSwapchainPresentMode; VkPresentModeKHR mSwapchainPresentMode;
uint32_t mMinImageCount;
VkSurfaceTransformFlagBitsKHR mPreTransform;
VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
RenderTargetVk mColorRenderTarget; RenderTargetVk mColorRenderTarget;
RenderTargetVk mDepthStencilRenderTarget; RenderTargetVk mDepthStencilRenderTarget;
...@@ -167,10 +180,15 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -167,10 +180,15 @@ class WindowSurfaceVk : public SurfaceImpl
std::vector<SwapchainImage> mSwapchainImages; std::vector<SwapchainImage> mSwapchainImages;
// A circular buffer, with the same size as mSwapchainImages (N), that stores the serial of the // A circular buffer, with the same size as mSwapchainImages (N), that stores the serial of the
// renderer on every swap. In FIFO present modes, the CPU is throttled by waiting for the // renderer on every swap. The CPU is throttled by waiting for the Nth previous serial to
// Nth previous serial to finish. // finish. Old swapchains are scheduled to be destroyed at the same time.
std::vector<Serial> mSwapSerials; struct SwapHistory
size_t mCurrentSwapSerialIndex; {
Serial serial;
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
};
std::vector<SwapHistory> mSwapHistory;
size_t mCurrentSwapHistoryIndex;
vk::ImageHelper mDepthStencilImage; vk::ImageHelper mDepthStencilImage;
vk::ImageView mDepthStencilImageView; vk::ImageView mDepthStencilImageView;
......
...@@ -33,6 +33,12 @@ angle::Result WindowSurfaceVkAndroid::createSurfaceVk(vk::Context *context, gl:: ...@@ -33,6 +33,12 @@ angle::Result WindowSurfaceVkAndroid::createSurfaceVk(vk::Context *context, gl::
ANGLE_VK_TRY(context, vkCreateAndroidSurfaceKHR(context->getRenderer()->getInstance(), ANGLE_VK_TRY(context, vkCreateAndroidSurfaceKHR(context->getRenderer()->getInstance(),
&createInfo, nullptr, &mSurface)); &createInfo, nullptr, &mSurface));
return getCurrentWindowSize(context, extentsOut);
}
angle::Result WindowSurfaceVkAndroid::getCurrentWindowSize(vk::Context *context,
gl::Extents *extentsOut)
{
int32_t width = ANativeWindow_getWidth(mNativeWindowType); int32_t width = ANativeWindow_getWidth(mNativeWindowType);
int32_t height = ANativeWindow_getHeight(mNativeWindowType); int32_t height = ANativeWindow_getHeight(mNativeWindowType);
ANGLE_VK_CHECK(context, width > 0 && height > 0, VK_ERROR_INITIALIZATION_FAILED); ANGLE_VK_CHECK(context, width > 0 && height > 0, VK_ERROR_INITIALIZATION_FAILED);
......
...@@ -25,6 +25,7 @@ class WindowSurfaceVkAndroid : public WindowSurfaceVk ...@@ -25,6 +25,7 @@ class WindowSurfaceVkAndroid : public WindowSurfaceVk
private: private:
angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override; angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override;
angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override;
}; };
} // namespace rx } // namespace rx
......
...@@ -1403,6 +1403,7 @@ void ImageHelper::init2DWeakReference(VkImage handle, ...@@ -1403,6 +1403,7 @@ void ImageHelper::init2DWeakReference(VkImage handle,
mExtents = extents; mExtents = extents;
mFormat = &format; mFormat = &format;
mSamples = samples; mSamples = samples;
mCurrentLayout = ImageLayout::Undefined;
mLayerCount = 1; mLayerCount = 1;
mLevelCount = 1; mLevelCount = 1;
......
...@@ -32,6 +32,12 @@ angle::Result WindowSurfaceVkWin32::createSurfaceVk(vk::Context *context, gl::Ex ...@@ -32,6 +32,12 @@ angle::Result WindowSurfaceVkWin32::createSurfaceVk(vk::Context *context, gl::Ex
ANGLE_VK_TRY(context, vkCreateWin32SurfaceKHR(context->getRenderer()->getInstance(), ANGLE_VK_TRY(context, vkCreateWin32SurfaceKHR(context->getRenderer()->getInstance(),
&createInfo, nullptr, &mSurface)); &createInfo, nullptr, &mSurface));
return getCurrentWindowSize(context, extentsOut);
}
angle::Result WindowSurfaceVkWin32::getCurrentWindowSize(vk::Context *context,
gl::Extents *extentsOut)
{
RECT rect; RECT rect;
ANGLE_VK_CHECK(context, GetClientRect(mNativeWindowType, &rect) == TRUE, ANGLE_VK_CHECK(context, GetClientRect(mNativeWindowType, &rect) == TRUE,
VK_ERROR_INITIALIZATION_FAILED); VK_ERROR_INITIALIZATION_FAILED);
......
...@@ -25,6 +25,7 @@ class WindowSurfaceVkWin32 : public WindowSurfaceVk ...@@ -25,6 +25,7 @@ class WindowSurfaceVkWin32 : public WindowSurfaceVk
private: private:
angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override; angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override;
angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override;
}; };
} // namespace rx } // namespace rx
......
...@@ -33,6 +33,12 @@ angle::Result WindowSurfaceVkXcb::createSurfaceVk(vk::Context *context, gl::Exte ...@@ -33,6 +33,12 @@ angle::Result WindowSurfaceVkXcb::createSurfaceVk(vk::Context *context, gl::Exte
ANGLE_VK_TRY(context, vkCreateXcbSurfaceKHR(context->getRenderer()->getInstance(), &createInfo, ANGLE_VK_TRY(context, vkCreateXcbSurfaceKHR(context->getRenderer()->getInstance(), &createInfo,
nullptr, &mSurface)); nullptr, &mSurface));
return getCurrentWindowSize(context, extentsOut);
}
angle::Result WindowSurfaceVkXcb::getCurrentWindowSize(vk::Context *context,
gl::Extents *extentsOut)
{
xcb_get_geometry_cookie_t cookie = xcb_get_geometry(mXcbConnection, mNativeWindowType); xcb_get_geometry_cookie_t cookie = xcb_get_geometry(mXcbConnection, mNativeWindowType);
xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(mXcbConnection, cookie, nullptr); xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(mXcbConnection, cookie, nullptr);
ASSERT(reply); ASSERT(reply);
......
...@@ -28,6 +28,7 @@ class WindowSurfaceVkXcb : public WindowSurfaceVk ...@@ -28,6 +28,7 @@ class WindowSurfaceVkXcb : public WindowSurfaceVk
private: private:
angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override; angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override;
angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override;
xcb_connection_t *mXcbConnection; xcb_connection_t *mXcbConnection;
}; };
......
...@@ -178,7 +178,6 @@ ...@@ -178,7 +178,6 @@
2635 WIN VULKAN : dEQP-EGL.functional.resize.surface_size.stretch_width = FAIL 2635 WIN VULKAN : dEQP-EGL.functional.resize.surface_size.stretch_width = FAIL
2635 WIN VULKAN : dEQP-EGL.functional.wide_color.pbuffer_8888_colorspace_default = FAIL 2635 WIN VULKAN : dEQP-EGL.functional.wide_color.pbuffer_8888_colorspace_default = FAIL
2716 WIN VULKAN : dEQP-EGL.functional.preserve_swap.no_preserve.* = FAIL 2716 WIN VULKAN : dEQP-EGL.functional.preserve_swap.no_preserve.* = FAIL
2811 WIN VULKAN : dEQP-EGL.functional.swap_buffers_with_damage.resize* = SKIP
// Linux failures // Linux failures
2546 LINUX : dEQP-EGL.functional.color_clears.multi_context.gles1.rgba8888_pixmap = SKIP 2546 LINUX : dEQP-EGL.functional.color_clears.multi_context.gles1.rgba8888_pixmap = SKIP
......
...@@ -431,7 +431,7 @@ bool X11Window::resize(int width, int height) ...@@ -431,7 +431,7 @@ bool X11Window::resize(int width, int height)
// Wait until the window as actually been resized so that the code calling resize // Wait until the window as actually been resized so that the code calling resize
// can assume the window has been resized. // can assume the window has been resized.
const double kResizeWaitDelay = 0.2; const double kResizeWaitDelay = 0.2;
while (mHeight != height && mWidth != width && timer->getElapsedTime() < kResizeWaitDelay) while ((mHeight != height || mWidth != width) && timer->getElapsedTime() < kResizeWaitDelay)
{ {
messageLoop(); messageLoop();
angle::Sleep(10); angle::Sleep(10);
...@@ -478,6 +478,10 @@ void X11Window::signalTestEvent() ...@@ -478,6 +478,10 @@ void X11Window::signalTestEvent()
// Hijack StructureNotifyMask as we know we will be listening for it. // Hijack StructureNotifyMask as we know we will be listening for it.
XSendEvent(mDisplay, mWindow, False, StructureNotifyMask, &event); XSendEvent(mDisplay, mWindow, False, StructureNotifyMask, &event);
// For test events, the tests want to check that it really did arrive, and they don't wait
// long. XSync here makes sure the event is sent by the time the messageLoop() is called.
XSync(mDisplay, false);
} }
void X11Window::processEvent(const XEvent &xEvent) void X11Window::processEvent(const XEvent &xEvent)
......
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