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.
This commit is contained in:
Philip Rideout
2020-08-11 16:12:49 -07:00
parent fb8c51c5e1
commit b45d45048c
3 changed files with 14 additions and 0 deletions

View File

@@ -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;

View File

@@ -59,6 +59,7 @@ struct VulkanCmdFence {
utils::Condition condition;
utils::Mutex mutex;
std::atomic<VkResult> 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.

View File

@@ -679,6 +679,9 @@ FenceStatus VulkanDriver::wait(Handle<HwFence> 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<HwSync> 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;