diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc index d75db4942bb..3220f7ec946 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -601,7 +601,7 @@ void ContextVK::Shutdown() { // pointers ensures that cleanup happens in a correct order. // // tl;dr: Without it, we get thread::join failures on shutdown. - fence_waiter_.reset(); + fence_waiter_->Terminate(); resource_manager_.reset(); raster_message_loop_->Terminate(); diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc index ddd617a5803..73755abbc7e 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc @@ -59,7 +59,6 @@ FenceWaiterVK::FenceWaiterVK(std::weak_ptr device_holder) FenceWaiterVK::~FenceWaiterVK() { Terminate(); - waiter_thread_->join(); } bool FenceWaiterVK::AddFence(vk::UniqueFence fence, @@ -207,9 +206,13 @@ bool FenceWaiterVK::Wait() { void FenceWaiterVK::Terminate() { { std::scoped_lock lock(wait_set_mutex_); + if (terminate_) { + return; + } terminate_ = true; } wait_set_cv_.notify_one(); + waiter_thread_->join(); } } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/fence_waiter_vk_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/fence_waiter_vk_unittests.cc index ef2ff5d40cb..6998dbc2da9 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/fence_waiter_vk_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/fence_waiter_vk_unittests.cc @@ -116,14 +116,20 @@ TEST(FenceWaiterVKTest, InProgressFencesStillWaitIfTerminated) { raw_fence = MockFence::GetRawPointer(fence); waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); }); - // Terminate the waiter. - waiter->Terminate(); + // Signal the fence after a delay. + std::thread thread([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds{100u}); + raw_fence->SetStatus(vk::Result::eSuccess); + }); - // Signal the fence. - raw_fence->SetStatus(vk::Result::eSuccess); + // Terminate the waiter. This will block until all pending fences are + // signalled. + waiter->Terminate(); // This will hang if the fence was not signalled. signal.Wait(); + + thread.join(); } } // namespace testing