Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2f80d6b

Browse files
committed
[Impeller] Fix a race between SwapchainImplVK::Present and WaitForFence
The previous implementation used an fml::CountDownLatch to synchronize between FrameSynchronizer::WaitForFence and the task queued by SwapchainImplVK::Present. fml::CountDownLatch:Wait always waits, even if the count is already zero. So the raster thread would deadlock if the present task signals the latch before FrameSynchronizer::WaitForFence enters the wait. This PR instead uses a semaphore that is set each time SwapchainImplVK::Present is called. FrameSynchronizer::WaitForFence will check the semaphore to determine whether a present task is pending and if so wait for its completion.
1 parent 16bbb46 commit 2f80d6b

1 file changed

Lines changed: 14 additions & 6 deletions

File tree

impeller/renderer/backend/vulkan/swapchain_impl_vk.cc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#include "impeller/renderer/backend/vulkan/swapchain_impl_vk.h"
66

7-
#include "fml/synchronization/count_down_latch.h"
7+
#include "fml/synchronization/semaphore.h"
88
#include "impeller/base/validation.h"
99
#include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
1010
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
@@ -32,7 +32,7 @@ struct FrameSynchronizer {
3232
std::shared_ptr<CommandBuffer> final_cmd_buffer;
3333
/// @brief A latch that is signaled _after_ a given swapchain image is
3434
/// presented.
35-
std::shared_ptr<fml::CountDownLatch> present_latch;
35+
std::shared_ptr<fml::Semaphore> present_semaphore;
3636
bool is_valid = false;
3737

3838
explicit FrameSynchronizer(const vk::Device& device) {
@@ -49,14 +49,21 @@ struct FrameSynchronizer {
4949
acquire = std::move(acquire_res.value);
5050
render_ready = std::move(render_res.value);
5151
present_ready = std::move(present_res.value);
52-
present_latch = std::make_shared<fml::CountDownLatch>(0u);
5352
is_valid = true;
5453
}
5554

5655
~FrameSynchronizer() = default;
5756

5857
bool WaitForFence(const vk::Device& device) {
59-
present_latch->Wait();
58+
if (!present_semaphore) {
59+
return true;
60+
}
61+
62+
if (!present_semaphore->Wait()) {
63+
VALIDATION_LOG << "Present semaphore wait failed";
64+
return false;
65+
}
66+
present_semaphore.reset();
6067
if (auto result = device.waitForFences(
6168
*acquire, // fence
6269
true, // wait all
@@ -71,7 +78,6 @@ struct FrameSynchronizer {
7178
VALIDATION_LOG << "Could not reset fence: " << vk::to_string(result);
7279
return false;
7380
}
74-
present_latch = std::make_shared<fml::CountDownLatch>(1u);
7581
return true;
7682
}
7783
};
@@ -505,7 +511,7 @@ bool SwapchainImplVK::Present(const std::shared_ptr<SwapchainImageVK>& image,
505511
present_info.setWaitSemaphores(*sync->present_ready);
506512

507513
auto result = present_queue_.presentKHR(present_info);
508-
sync->present_latch->CountDown();
514+
sync->present_semaphore->Signal();
509515

510516
switch (result) {
511517
case vk::Result::eErrorOutOfDateKHR:
@@ -529,6 +535,8 @@ bool SwapchainImplVK::Present(const std::shared_ptr<SwapchainImageVK>& image,
529535
}
530536
FML_UNREACHABLE();
531537
};
538+
539+
sync->present_semaphore = std::make_shared<fml::Semaphore>(0u);
532540
if (context.GetSyncPresentation()) {
533541
task();
534542
} else {

0 commit comments

Comments
 (0)