| Flutter Impeller |

fence_waiter_vk_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "fml/synchronization/waitable_event.h"
6 #include "gtest/gtest.h" // IWYU pragma: keep
7 #include "impeller/renderer/backend/vulkan/fence_waiter_vk.h" // IWYU pragma: keep
8 #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
9
10 namespace impeller {
11 namespace testing {
12
13 TEST(FenceWaiterVKTest, IgnoresNullFence) {
14 auto const context = MockVulkanContextBuilder().Build();
15 auto const waiter = context->GetFenceWaiter();
16 EXPECT_FALSE(waiter->AddFence(vk::UniqueFence(), []() {}));
17 }
18
19 TEST(FenceWaiterVKTest, IgnoresNullCallback) {
20 auto const context = MockVulkanContextBuilder().Build();
21 auto const device = context->GetDevice();
22 auto const waiter = context->GetFenceWaiter();
23
24 auto fence = device.createFenceUnique({}).value;
25 EXPECT_FALSE(waiter->AddFence(std::move(fence), nullptr));
26 }
27
28 TEST(FenceWaiterVKTest, ExecutesFenceCallback) {
29 auto const context = MockVulkanContextBuilder().Build();
30 auto const device = context->GetDevice();
31 auto const waiter = context->GetFenceWaiter();
32
33 auto signal = fml::ManualResetWaitableEvent();
34 auto fence = device.createFenceUnique({}).value;
35 waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); });
36
37 signal.Wait();
38 }
39
40 TEST(FenceWaiterVKTest, ExecutesFenceCallbackX2) {
41 auto const context = MockVulkanContextBuilder().Build();
42 auto const device = context->GetDevice();
43 auto const waiter = context->GetFenceWaiter();
44
45 auto signal = fml::ManualResetWaitableEvent();
46 auto fence = device.createFenceUnique({}).value;
47 waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); });
48
49 auto signal2 = fml::ManualResetWaitableEvent();
50 auto fence2 = device.createFenceUnique({}).value;
51 waiter->AddFence(std::move(fence2), [&signal2]() { signal2.Signal(); });
52
53 signal.Wait();
54 signal2.Wait();
55 }
56
57 TEST(FenceWaiterVKTest, ExecutesNewFenceThenOldFence) {
58 auto const context = MockVulkanContextBuilder().Build();
59 auto const device = context->GetDevice();
60 auto const waiter = context->GetFenceWaiter();
61
62 auto signal = fml::ManualResetWaitableEvent();
63 auto fence = device.createFenceUnique({}).value;
64 MockFence::SetStatus(fence, vk::Result::eNotReady);
65 auto raw_fence = MockFence::GetRawPointer(fence);
66 waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); });
67
68 // The easiest way to verify that the callback was _not_ called is to wait
69 // for a timeout, but that could introduce flakiness. Instead, we'll add a
70 // second fence that will signal immediately, and wait for that one instead.
71 {
72 auto signal2 = fml::ManualResetWaitableEvent();
73 auto fence2 = device.createFenceUnique({}).value;
74 MockFence::SetStatus(fence2, vk::Result::eSuccess);
75 waiter->AddFence(std::move(fence2), [&signal2]() { signal2.Signal(); });
76 signal2.Wait();
77 }
78
79 // Now, we'll signal the first fence, and wait for the callback to be called.
80 raw_fence->SetStatus(vk::Result::eSuccess);
81
82 // Now, we'll signal the first fence, and wait for the callback to be called.
83 signal.Wait();
84 }
85
86 TEST(FenceWaiterVKTest, AddFenceDoesNothingIfTerminating) {
87 auto signal = fml::ManualResetWaitableEvent();
88
89 {
90 auto const context = MockVulkanContextBuilder().Build();
91 auto const device = context->GetDevice();
92 auto const waiter = context->GetFenceWaiter();
93 waiter->Terminate();
94
95 auto fence = device.createFenceUnique({}).value;
96 waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); });
97 }
98
99 // Ensure the fence did _not_ signal.
100 EXPECT_TRUE(signal.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(100)));
101 }
102
103 TEST(FenceWaiterVKTest, InProgressFencesStillWaitIfTerminated) {
104 MockFence* raw_fence = nullptr;
105 auto signal = fml::ManualResetWaitableEvent();
106
107 auto const context = MockVulkanContextBuilder().Build();
108 auto const device = context->GetDevice();
109 auto const waiter = context->GetFenceWaiter();
110
111 // Add a fence that isn't signalled yet.
112 auto fence = device.createFenceUnique({}).value;
113
114 // Even if the fence is eSuccess, it's not guaranteed to be called in time.
115 MockFence::SetStatus(fence, vk::Result::eNotReady);
116 raw_fence = MockFence::GetRawPointer(fence);
117 waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); });
118
119 // Signal the fence after a delay.
120 std::thread thread([&]() {
121 std::this_thread::sleep_for(std::chrono::milliseconds{100u});
122 raw_fence->SetStatus(vk::Result::eSuccess);
123 });
124
125 // Terminate the waiter. This will block until all pending fences are
126 // signalled.
127 waiter->Terminate();
128
129 // This will hang if the fence was not signalled.
130 signal.Wait();
131
132 thread.join();
133 }
134
135 } // namespace testing
136 } // namespace impeller
value
int32_t value
Definition: dl_golden_unittests.cc:459
fence_waiter_vk.h
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller
Definition: allocation.cc:12