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.
8 #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
9 
10 namespace impeller {
11 namespace testing {
12 
13 TEST(DescriptorPoolRecyclerVKTest, GetDescriptorPoolRecyclerCreatesNewPools) {
14  std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
15 
16  vk::UniqueDescriptorPool pool1 = context->GetDescriptorPoolRecycler()->Get();
17  vk::UniqueDescriptorPool pool2 = context->GetDescriptorPoolRecycler()->Get();
18 
19  // The two descriptor pools should be different.
20  EXPECT_NE(pool1.get(), pool2.get());
21 
22  context->Shutdown();
23 }
24 
25 TEST(DescriptorPoolRecyclerVKTest, ReclaimMakesDescriptorPoolAvailable) {
26  std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
27 
28  {
29  // Fetch a pool (which will be created).
30  DescriptorPoolVK pool = DescriptorPoolVK(context);
31  pool.AllocateDescriptorSets({}, /*pipeline_key=*/0, *context);
32  }
33 
34  std::shared_ptr<DescriptorPoolVK> pool =
35  context->GetDescriptorPoolRecycler()->GetDescriptorPool();
36 
37  // Now check that we only ever created one pool.
38  std::shared_ptr<std::vector<std::string>> called =
39  GetMockVulkanFunctions(context->GetDevice());
40  EXPECT_EQ(
41  std::count(called->begin(), called->end(), "vkCreateDescriptorPool"), 1u);
42 
43  context->Shutdown();
44 }
45 
46 TEST(DescriptorPoolRecyclerVKTest, ReclaimDropsDescriptorPoolIfSizeIsExceeded) {
47  std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
48 
49  // Create 33 pools
50  {
51  std::vector<std::unique_ptr<DescriptorPoolVK>> pools;
52  for (size_t i = 0u; i < 33; i++) {
53  std::unique_ptr<DescriptorPoolVK> pool =
54  std::make_unique<DescriptorPoolVK>(context);
55  pool->AllocateDescriptorSets({}, /*pipeline_key=*/0, *context);
56  pools.push_back(std::move(pool));
57  }
58  }
59 
60  std::shared_ptr<std::vector<std::string>> called =
61  GetMockVulkanFunctions(context->GetDevice());
62  EXPECT_EQ(
63  std::count(called->begin(), called->end(), "vkCreateDescriptorPool"),
64  33u);
65 
66  // Now create 33 more descriptor pools and observe that only one more is
67  // allocated.
68  {
69  std::vector<std::shared_ptr<DescriptorPoolVK>> pools;
70  for (size_t i = 0u; i < 33; i++) {
71  std::shared_ptr<DescriptorPoolVK> pool =
72  context->GetDescriptorPoolRecycler()->GetDescriptorPool();
73  pool->AllocateDescriptorSets({}, /*pipeline_key=*/0, *context);
74  pools.push_back(std::move(pool));
75  }
76  }
77 
78  std::shared_ptr<std::vector<std::string>> called_twice =
79  GetMockVulkanFunctions(context->GetDevice());
80  // 32 of the descriptor pools were recycled, so only one more is created.
81  EXPECT_EQ(
82  std::count(called->begin(), called->end(), "vkCreateDescriptorPool"),
83  34u);
84 
85  context->Shutdown();
86 }
87 
88 TEST(DescriptorPoolRecyclerVKTest, MultipleCommandBuffersShareDescriptorPool) {
89  std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
90 
91  std::shared_ptr<CommandBuffer> cmd_buffer_1 = context->CreateCommandBuffer();
92  std::shared_ptr<CommandBuffer> cmd_buffer_2 = context->CreateCommandBuffer();
93 
94  CommandBufferVK& vk_1 = CommandBufferVK::Cast(*cmd_buffer_1);
95  CommandBufferVK& vk_2 = CommandBufferVK::Cast(*cmd_buffer_2);
96 
97  EXPECT_EQ(&vk_1.GetDescriptorPool(), &vk_2.GetDescriptorPool());
98 
99  // Resetting resources creates a new pool.
100  context->DisposeThreadLocalCachedResources();
101 
102  std::shared_ptr<CommandBuffer> cmd_buffer_3 = context->CreateCommandBuffer();
103  CommandBufferVK& vk_3 = CommandBufferVK::Cast(*cmd_buffer_3);
104 
105  EXPECT_NE(&vk_1.GetDescriptorPool(), &vk_3.GetDescriptorPool());
106 
107  context->Shutdown();
108 }
109 
110 TEST(DescriptorPoolRecyclerVKTest, DescriptorsAreRecycled) {
111  std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
112 
113  {
114  DescriptorPoolVK pool = DescriptorPoolVK(context);
115  pool.AllocateDescriptorSets({}, /*pipeline_key=*/0, *context);
116  }
117 
118  // Should reuse the same descriptor set allocated above.
119  std::shared_ptr<DescriptorPoolVK> pool =
120  context->GetDescriptorPoolRecycler()->GetDescriptorPool();
121  pool->AllocateDescriptorSets({}, /*pipeline_key=*/0, *context);
122 
123  std::shared_ptr<std::vector<std::string>> called =
124  GetMockVulkanFunctions(context->GetDevice());
125  EXPECT_EQ(
126  std::count(called->begin(), called->end(), "vkAllocateDescriptorSets"),
127  1);
128 
129  // Should allocate a new descriptor set.
130  pool->AllocateDescriptorSets({}, /*pipeline_key=*/0, *context);
131  EXPECT_EQ(
132  std::count(called->begin(), called->end(), "vkAllocateDescriptorSets"),
133  2);
134 }
135 
136 } // namespace testing
137 } // namespace impeller
static CommandBufferVK & Cast(CommandBuffer &base)
Definition: backend_cast.h:13
DescriptorPoolVK & GetDescriptorPool() const
A per-frame descriptor pool. Descriptors from this pool don't need to be freed individually....
fml::StatusOr< vk::DescriptorSet > AllocateDescriptorSets(const vk::DescriptorSetLayout &layout, PipelineKey pipeline_key, const ContextVK &context_vk)
TEST(AllocationSizeTest, CanCreateTypedAllocations)