forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommand_pool_vk_unittests.cc
More file actions
116 lines (88 loc) · 3.43 KB
/
command_pool_vk_unittests.cc
File metadata and controls
116 lines (88 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// 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/synchronization/waitable_event.h"
#include "impeller/renderer/backend/vulkan/command_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(CommandPoolRecyclerVKTest, GetsACommandPoolPerThread) {
auto const context = MockVulkanContextBuilder().Build();
{
// Record the memory location of each pointer to a command pool.
//
// These pools have to be held at this context, otherwise they will be
// dropped and recycled and potentially reused by another thread, causing
// flaky tests.
std::shared_ptr<CommandPoolVK> pool1;
std::shared_ptr<CommandPoolVK> pool2;
// Create a command pool in two threads and record the memory location.
std::thread thread1(
[&]() { pool1 = context->GetCommandPoolRecycler()->Get(); });
std::thread thread2(
[&]() { pool2 = context->GetCommandPoolRecycler()->Get(); });
thread1.join();
thread2.join();
// The two command pools should be different.
EXPECT_NE(pool1, pool2);
}
context->Shutdown();
}
TEST(CommandPoolRecyclerVKTest, GetsTheSameCommandPoolOnSameThread) {
auto const context = MockVulkanContextBuilder().Build();
auto const pool1 = context->GetCommandPoolRecycler()->Get();
auto const pool2 = context->GetCommandPoolRecycler()->Get();
// The two command pools should be the same.
EXPECT_EQ(pool1.get(), pool2.get());
context->Shutdown();
}
namespace {
// Invokes the provided callback when the destructor is called.
//
// Can be moved, but not copied.
class DeathRattle final {
public:
explicit DeathRattle(std::function<void()> callback)
: callback_(std::move(callback)) {}
DeathRattle(DeathRattle&&) = default;
DeathRattle& operator=(DeathRattle&&) = default;
~DeathRattle() { callback_(); }
private:
std::function<void()> callback_;
};
} // namespace
TEST(CommandPoolRecyclerVKTest, ReclaimMakesCommandPoolAvailable) {
auto const context = MockVulkanContextBuilder().Build();
{
// Fetch a pool (which will be created).
auto const recycler = context->GetCommandPoolRecycler();
auto const pool = recycler->Get();
// This normally is called at the end of a frame.
recycler->Dispose();
}
// 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 = DeathRattle([&waiter]() { waiter.Signal(); });
{
UniqueResourceVKT<DeathRattle> resource(context->GetResourceManager(),
std::move(rattle));
}
waiter.Wait();
// On another thread explicitly, request a new pool.
std::thread thread([&]() {
auto const pool = context->GetCommandPoolRecycler()->Get();
EXPECT_NE(pool.get(), nullptr);
});
thread.join();
// Now check that we only ever created one pool.
auto const called = GetMockVulkanFunctions(context->GetDevice());
EXPECT_EQ(std::count(called->begin(), called->end(), "vkCreateCommandPool"),
1u);
context->Shutdown();
}
} // namespace testing
} // namespace impeller