| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/testing/testing.h" // IWYU pragma: keep. |
| #include "fml/closure.h" |
| #include "fml/synchronization/waitable_event.h" |
| #include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h" |
| #include "impeller/renderer/backend/vulkan/resource_manager_vk.h" |
| #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h" |
| |
| namespace impeller { |
| namespace testing { |
| |
| TEST(DescriptorPoolRecyclerVKTest, GetDescriptorPoolRecyclerCreatesNewPools) { |
| auto const context = MockVulkanContextBuilder().Build(); |
| |
| auto const pool1 = context->GetDescriptorPoolRecycler()->Get(); |
| auto const pool2 = context->GetDescriptorPoolRecycler()->Get(); |
| |
| // The two descriptor pools should be different. |
| EXPECT_NE(pool1.get(), pool2.get()); |
| |
| context->Shutdown(); |
| } |
| |
| TEST(DescriptorPoolRecyclerVKTest, ReclaimMakesDescriptorPoolAvailable) { |
| auto const context = MockVulkanContextBuilder().Build(); |
| |
| { |
| // Fetch a pool (which will be created). |
| auto pool = DescriptorPoolVK(context); |
| pool.AllocateDescriptorSets({}, *context); |
| } |
| |
| // There is a chance that the first death rattle item below is destroyed in |
| // the same reclaim cycle as the pool allocation above. These items are placed |
| // into a std::vector and free'd, which may free in reverse order. That would |
| // imply that the death rattle and subsequent waitable event fires before the |
| // pool is reset. To work around this, we can either manually remove items |
| // from the vector or use two death rattles. |
| for (auto i = 0u; i < 2; i++) { |
| // Add something to the resource manager and have it notify us when it's |
| // destroyed. That should give us a non-flaky signal that the pool has been |
| // reclaimed as well. |
| auto waiter = fml::AutoResetWaitableEvent(); |
| auto rattle = fml::ScopedCleanupClosure([&waiter]() { waiter.Signal(); }); |
| { |
| UniqueResourceVKT<fml::ScopedCleanupClosure> resource( |
| context->GetResourceManager(), std::move(rattle)); |
| } |
| waiter.Wait(); |
| } |
| |
| auto const pool = context->GetDescriptorPoolRecycler()->Get(); |
| |
| // Now check that we only ever created one pool. |
| auto const called = GetMockVulkanFunctions(context->GetDevice()); |
| EXPECT_EQ( |
| std::count(called->begin(), called->end(), "vkCreateDescriptorPool"), 1u); |
| |
| context->Shutdown(); |
| } |
| |
| TEST(DescriptorPoolRecyclerVKTest, ReclaimDropsDescriptorPoolIfSizeIsExceeded) { |
| auto const context = MockVulkanContextBuilder().Build(); |
| |
| // Create 33 pools |
| { |
| std::vector<std::unique_ptr<DescriptorPoolVK>> pools; |
| for (auto i = 0u; i < 33; i++) { |
| auto pool = std::make_unique<DescriptorPoolVK>(context); |
| pool->AllocateDescriptorSets({}, *context); |
| pools.push_back(std::move(pool)); |
| } |
| } |
| |
| // See note above. |
| for (auto i = 0u; i < 2; i++) { |
| auto waiter = fml::AutoResetWaitableEvent(); |
| auto rattle = fml::ScopedCleanupClosure([&waiter]() { waiter.Signal(); }); |
| { |
| UniqueResourceVKT<fml::ScopedCleanupClosure> resource( |
| context->GetResourceManager(), std::move(rattle)); |
| } |
| waiter.Wait(); |
| } |
| |
| auto const called = GetMockVulkanFunctions(context->GetDevice()); |
| EXPECT_EQ( |
| std::count(called->begin(), called->end(), "vkCreateDescriptorPool"), |
| 33u); |
| EXPECT_EQ(std::count(called->begin(), called->end(), "vkResetDescriptorPool"), |
| 33u); |
| |
| // Now create 33 more descriptor pools and observe that only one more is |
| // allocated. |
| { |
| std::vector<std::unique_ptr<DescriptorPoolVK>> pools; |
| for (auto i = 0u; i < 33; i++) { |
| auto pool = std::make_unique<DescriptorPoolVK>(context); |
| pool->AllocateDescriptorSets({}, *context); |
| pools.push_back(std::move(pool)); |
| } |
| } |
| |
| for (auto i = 0u; i < 2; i++) { |
| auto waiter = fml::AutoResetWaitableEvent(); |
| auto rattle = fml::ScopedCleanupClosure([&waiter]() { waiter.Signal(); }); |
| { |
| UniqueResourceVKT<fml::ScopedCleanupClosure> resource( |
| context->GetResourceManager(), std::move(rattle)); |
| } |
| waiter.Wait(); |
| } |
| |
| auto const called_twice = GetMockVulkanFunctions(context->GetDevice()); |
| // 32 of the descriptor pools were recycled, so only one more is created. |
| EXPECT_EQ( |
| std::count(called->begin(), called->end(), "vkCreateDescriptorPool"), |
| 34u); |
| |
| context->Shutdown(); |
| } |
| |
| } // namespace testing |
| } // namespace impeller |