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