From 68c424fe42405e8459aae786f4f57930f6af0ca8 Mon Sep 17 00:00:00 2001 From: Shahbaz Youssefi Date: Thu, 17 Sep 2020 10:34:07 -0400 Subject: [PATCH] Vulkan: Workaround oldSwapchin bug on Android When vkCreateSwapchainKHR is called with a valid oldSwapchain, the Android framework destroys the images in oldSwapchain. This is not correct, as it should be deferred to the actual vkDestroySwapchainKHR call performed later by ANGLE. This is because rendering to the oldSwapchain could still be in progress. While this issue affects all of Android, currently only ARM shows any symptoms. A workaround is added for ARM to vkDeviceWaitIdle before recreating the swapchain if oldSwapchain is valid. Bug: angleproject:5061 Change-Id: I308e4798c6418d7891d880218b0ebcfd7a795643 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2416238 Reviewed-by: Sunny Sun Reviewed-by: Ian Elliott Commit-Queue: Shahbaz Youssefi --- include/platform/FeaturesVk.h | 8 ++++++++ src/libANGLE/renderer/vulkan/RendererVk.cpp | 3 +++ src/libANGLE/renderer/vulkan/SurfaceVk.cpp | 7 +++++++ 3 files changed, 18 insertions(+) diff --git a/include/platform/FeaturesVk.h b/include/platform/FeaturesVk.h index 3051cef3b..68efdbf4e 100644 --- a/include/platform/FeaturesVk.h +++ b/include/platform/FeaturesVk.h @@ -370,6 +370,14 @@ struct FeaturesVk : FeatureSetBase "defer_flush_until_endrenderpass", FeatureCategory::VulkanWorkarounds, "Allow glFlush to be deferred until renderpass ends", &members, "https://issuetracker.google.com/issues/166475273"}; + + // Android mistakenly destroys oldSwapchain passed to vkCreateSwapchainKHR, causing crashes on + // certain drivers. http://anglebug.com/5061 + Feature waitIdleBeforeSwapchainRecreation = { + "wait_idle_before_swapchain_recreation", FeatureCategory::VulkanWorkarounds, + "Before passing an oldSwapchain to VkSwapchainCreateInfoKHR, wait for queue to be idle. " + "Works around a bug on platforms which destroy oldSwapchain in vkCreateSwapchainKHR.", + &members, "http://anglebug.com/5061"}; }; inline FeaturesVk::FeaturesVk() = default; diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp index c076e831f..ed676eb2d 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.cpp +++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp @@ -1868,6 +1868,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev ANGLE_FEATURE_CONDITION(&mFeatures, deferFlushUntilEndRenderPass, true); + // Android mistakenly destroys the old swapchain when creating a new one. + ANGLE_FEATURE_CONDITION(&mFeatures, waitIdleBeforeSwapchainRecreation, IsAndroid() && isARM); + angle::PlatformMethods *platform = ANGLEPlatformCurrent(); platform->overrideFeaturesVk(platform, &mFeatures); diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp index 7ab666096..ff8057a8e 100644 --- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp +++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp @@ -927,6 +927,13 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context, swapchainInfo.clipped = VK_TRUE; swapchainInfo.oldSwapchain = lastSwapchain; + // On Android, vkCreateSwapchainKHR destroys lastSwapchain, which is incorrect. Wait idle in + // that case as a workaround. + if (lastSwapchain && renderer->getFeatures().waitIdleBeforeSwapchainRecreation.enabled) + { + ANGLE_TRY(renderer->deviceWaitIdle(context)); + } + // TODO(syoussefi): Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old // swapchain need to carry over to the new one. http://anglebug.com/2942 VkSwapchainKHR newSwapChain = VK_NULL_HANDLE;