| Flutter Impeller |

descriptor_pool_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 "flutter/testing/testing.h" // IWYU pragma: keep.
6 #include "fml/synchronization/waitable_event.h"
7 #include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h"
8 #include "impeller/renderer/backend/vulkan/resource_manager_vk.h"
9 #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
10
11 namespace impeller {
12 namespace testing {
13
14 TEST(DescriptorPoolRecyclerVKTest, GetDescriptorPoolRecyclerCreatesNewPools) {
15 auto const context = MockVulkanContextBuilder().Build();
16
17 auto const pool1 = context->GetDescriptorPoolRecycler()->Get();
18 auto const pool2 = context->GetDescriptorPoolRecycler()->Get();
19
20 // The two descriptor pools should be different.
21 EXPECT_NE(pool1.get(), pool2.get());
22
23 context->Shutdown();
24 }
25
26 namespace {
27
28 // Invokes the provided callback when the destructor is called.
29 //
30 // Can be moved, but not copied.
31 class DeathRattle final {
32 public:
33 explicit DeathRattle(std::function<void()> callback)
34 : callback_(std::move(callback)) {}
35
36 DeathRattle(DeathRattle&&) = default;
37 DeathRattle& operator=(DeathRattle&&) = default;
38
39 ~DeathRattle() { callback_(); }
40
41 private:
42 std::function<void()> callback_;
43 };
44
45 } // namespace
46
47 TEST(DescriptorPoolRecyclerVKTest, ReclaimMakesDescriptorPoolAvailable) {
48 auto const context = MockVulkanContextBuilder().Build();
49
50 {
51 // Fetch a pool (which will be created).
52 auto pool = DescriptorPoolVK(context);
53 pool.AllocateDescriptorSets({}, *context);
54 }
55
56 // There is a chance that the first death rattle item below is destroyed in
57 // the same reclaim cycle as the pool allocation above. These items are placed
58 // into a std::vector and free'd, which may free in reverse order. That would
59 // imply that the death rattle and subsequent waitable event fires before the
60 // pool is reset. To work around this, we can either manually remove items
61 // from the vector or use two death rattles.
62 for (auto i = 0u; i < 2; i++) {
63 // Add something to the resource manager and have it notify us when it's
64 // destroyed. That should give us a non-flaky signal that the pool has been
65 // reclaimed as well.
66 auto waiter = fml::AutoResetWaitableEvent();
67 auto rattle = DeathRattle([&waiter]() { waiter.Signal(); });
68 {
69 UniqueResourceVKT<DeathRattle> resource(context->GetResourceManager(),
70 std::move(rattle));
71 }
72 waiter.Wait();
73 }
74
75 auto const pool = context->GetDescriptorPoolRecycler()->Get();
76
77 // Now check that we only ever created one pool.
78 auto const called = GetMockVulkanFunctions(context->GetDevice());
79 EXPECT_EQ(
80 std::count(called->begin(), called->end(), "vkCreateDescriptorPool"), 1u);
81
82 context->Shutdown();
83 }
84
85 TEST(DescriptorPoolRecyclerVKTest, ReclaimDropsDescriptorPoolIfSizeIsExceeded) {
86 auto const context = MockVulkanContextBuilder().Build();
87
88 // Create 33 pools
89 {
90 std::vector<std::unique_ptr<DescriptorPoolVK>> pools;
91 for (auto i = 0u; i < 33; i++) {
92 auto pool = std::make_unique<DescriptorPoolVK>(context);
93 pool->AllocateDescriptorSets({}, *context);
94 pools.push_back(std::move(pool));
95 }
96 }
97
98 // See note above.
99 for (auto i = 0u; i < 2; i++) {
100 auto waiter = fml::AutoResetWaitableEvent();
101 auto rattle = DeathRattle([&waiter]() { waiter.Signal(); });
102 {
103 UniqueResourceVKT<DeathRattle> resource(context->GetResourceManager(),
104 std::move(rattle));
105 }
106 waiter.Wait();
107 }
108
109 auto const called = GetMockVulkanFunctions(context->GetDevice());
110 EXPECT_EQ(
111 std::count(called->begin(), called->end(), "vkCreateDescriptorPool"),
112 33u);
113 EXPECT_EQ(std::count(called->begin(), called->end(), "vkResetDescriptorPool"),
114 33u);
115
116 // Now create 33 more descriptor pools and observe that only one more is
117 // allocated.
118 {
119 std::vector<std::unique_ptr<DescriptorPoolVK>> pools;
120 for (auto i = 0u; i < 33; i++) {
121 auto pool = std::make_unique<DescriptorPoolVK>(context);
122 pool->AllocateDescriptorSets({}, *context);
123 pools.push_back(std::move(pool));
124 }
125 }
126
127 for (auto i = 0u; i < 2; i++) {
128 auto waiter = fml::AutoResetWaitableEvent();
129 auto rattle = DeathRattle([&waiter]() { waiter.Signal(); });
130 {
131 UniqueResourceVKT<DeathRattle> resource(context->GetResourceManager(),
132 std::move(rattle));
133 }
134 waiter.Wait();
135 }
136
137 auto const called_twice = GetMockVulkanFunctions(context->GetDevice());
138 // 32 of the descriptor pools were recycled, so only one more is created.
139 EXPECT_EQ(
140 std::count(called->begin(), called->end(), "vkCreateDescriptorPool"),
141 34u);
142
143 context->Shutdown();
144 }
145
146 } // namespace testing
147 } // namespace impeller
impeller::UniqueResourceVKT
A unique handle to a resource which will be reclaimed by the specified resource manager.
Definition: resource_manager_vk.h:145
impeller::DescriptorPoolVK
A per-frame descriptor pool. Descriptors from this pool don't need to be freed individually....
Definition: descriptor_pool_vk.h:27
impeller::testing::TEST
TEST(CanvasRecorder, Save)
Definition: canvas_recorder_unittests.cc:65
resource_manager_vk.h
std
Definition: comparable.h:95
descriptor_pool_vk.h
impeller
Definition: aiks_blur_unittests.cc:20