From b45d45048c861ebc8dcec8d3b40cb07cf6ed2464 Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Tue, 11 Aug 2020 16:12:49 -0700 Subject: [PATCH] Vulkan: fix Android after pause / resume. This fixes the visual hang that would occur after going to the task switcher and back. After recreating the swap chain, all of its associated fences and sync objects become invalid. Since we were not tracking this, FrameSkipper was going into an infinite wait after the swap chain was created. --- filament/backend/src/vulkan/VulkanContext.cpp | 7 +++++++ filament/backend/src/vulkan/VulkanContext.h | 1 + filament/backend/src/vulkan/VulkanDriver.cpp | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/filament/backend/src/vulkan/VulkanContext.cpp b/filament/backend/src/vulkan/VulkanContext.cpp index f92b277274..c239cfe6c3 100644 --- a/filament/backend/src/vulkan/VulkanContext.cpp +++ b/filament/backend/src/vulkan/VulkanContext.cpp @@ -448,7 +448,14 @@ void destroySwapChain(VulkanContext& context, VulkanSurfaceContext& surfaceConte disposer.release(swapContext.commands.resources); vkFreeCommandBuffers(context.device, context.commandPool, 1, &swapContext.commands.cmdbuffer); + + // The wrapper object for the submission fence has shared ownership semantics, so here + // we notify other owners that the swap chain (and its associated command buffers) have + // been destroyed. + swapContext.commands.fence->swapChainDestroyed = true; + swapContext.commands.fence.reset(); + vkDestroyImageView(context.device, swapContext.attachment.view, VKALLOC); swapContext.commands.fence = VK_NULL_HANDLE; swapContext.attachment.view = VK_NULL_HANDLE; diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index aaaa25a635..58a8a94bce 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -59,6 +59,7 @@ struct VulkanCmdFence { utils::Condition condition; utils::Mutex mutex; std::atomic status; + bool swapChainDestroyed = false; // TODO: for non-work buffers the following field indicates if the fence has EVER been // submitted, which is a bit misleading or un-useful. This needs to be refactored. diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 76c2021141..ce603ccbed 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -679,6 +679,9 @@ FenceStatus VulkanDriver::wait(Handle fh, uint64_t timeout) { } else { lock.unlock(); } + if (cmdfence->swapChainDestroyed) { + return FenceStatus::ERROR; + } VkResult result = vkWaitForFences(mContext.device, 1, &cmdfence->fence, VK_FALSE, timeout); return result == VK_SUCCESS ? FenceStatus::CONDITION_SATISFIED : FenceStatus::TIMEOUT_EXPIRED; } @@ -830,6 +833,9 @@ SyncStatus VulkanDriver::getSyncStatus(Handle sh) { if (sync->fence == nullptr) { return SyncStatus::NOT_SIGNALED; } + if (sync->fence->swapChainDestroyed) { + return SyncStatus::ERROR; + } VkResult status = sync->fence->status.load(std::memory_order_relaxed); switch (status) { case VK_SUCCESS: return SyncStatus::SIGNALED;