12
12
#include " impeller/renderer/backend/vulkan/resource_manager_vk.h"
13
13
14
14
#include " impeller/renderer/backend/vulkan/vk.h" // IWYU pragma: keep.
15
+ #include " vulkan/vulkan_handles.hpp"
15
16
#include " vulkan/vulkan_structs.hpp"
16
17
17
18
namespace impeller {
@@ -21,12 +22,18 @@ class BackgroundCommandPoolVK final {
21
22
public:
22
23
BackgroundCommandPoolVK (BackgroundCommandPoolVK&&) = default ;
23
24
25
+ // The recycler also recycles command buffers that were never used, up to a
26
+ // limit of 16 per frame. This number was somewhat arbitrarily chosen.
27
+ static constexpr size_t kUnusedCommandBufferLimit = 16u ;
28
+
24
29
explicit BackgroundCommandPoolVK (
25
30
vk::UniqueCommandPool&& pool,
26
31
std::vector<vk::UniqueCommandBuffer>&& buffers,
32
+ size_t unused_count,
27
33
std::weak_ptr<CommandPoolRecyclerVK> recycler)
28
34
: pool_(std::move(pool)),
29
35
buffers_(std::move(buffers)),
36
+ unused_count_(unused_count),
30
37
recycler_(std::move(recycler)) {}
31
38
32
39
~BackgroundCommandPoolVK () {
@@ -39,9 +46,14 @@ class BackgroundCommandPoolVK final {
39
46
if (!recycler) {
40
47
return ;
41
48
}
42
- buffers_.clear ();
49
+ // If there are many unused command buffers, release some of them.
50
+ if (unused_count_ > kUnusedCommandBufferLimit ) {
51
+ for (auto i = 0u ; i < unused_count_; i++) {
52
+ buffers_.pop_back ();
53
+ }
54
+ }
43
55
44
- recycler->Reclaim (std::move (pool_));
56
+ recycler->Reclaim (std::move (pool_), std::move (buffers_) );
45
57
}
46
58
47
59
private:
@@ -55,6 +67,7 @@ class BackgroundCommandPoolVK final {
55
67
// wrapper type will attempt to reset the cmd buffer, and doing so may be a
56
68
// thread safety violation as this may happen on the fence waiter thread.
57
69
std::vector<vk::UniqueCommandBuffer> buffers_;
70
+ const size_t unused_count_;
58
71
std::weak_ptr<CommandPoolRecyclerVK> recycler_;
59
72
};
60
73
@@ -71,9 +84,16 @@ CommandPoolVK::~CommandPoolVK() {
71
84
if (!recycler) {
72
85
return ;
73
86
}
87
+ // Any unused command buffers are added to the set of used command buffers.
88
+ // both will be reset to the initial state when the pool is reset.
89
+ size_t unused_count = unused_command_buffers_.size ();
90
+ for (auto i = 0u ; i < unused_command_buffers_.size (); i++) {
91
+ collected_buffers_.push_back (std::move (unused_command_buffers_[i]));
92
+ }
93
+ unused_command_buffers_.clear ();
74
94
75
95
auto reset_pool_when_dropped = BackgroundCommandPoolVK (
76
- std::move (pool_), std::move (collected_buffers_), recycler);
96
+ std::move (pool_), std::move (collected_buffers_), unused_count, recycler);
77
97
78
98
UniqueResourceVKT<BackgroundCommandPoolVK> pool (
79
99
context->GetResourceManager (), std::move (reset_pool_when_dropped));
@@ -90,6 +110,11 @@ vk::UniqueCommandBuffer CommandPoolVK::CreateCommandBuffer() {
90
110
if (!pool_) {
91
111
return {};
92
112
}
113
+ if (!unused_command_buffers_.empty ()) {
114
+ vk::UniqueCommandBuffer buffer = std::move (unused_command_buffers_.back ());
115
+ unused_command_buffers_.pop_back ();
116
+ return buffer;
117
+ }
93
118
94
119
auto const device = context->GetDevice ();
95
120
vk::CommandBufferAllocateInfo info;
@@ -123,6 +148,10 @@ void CommandPoolVK::Destroy() {
123
148
for (auto & buffer : collected_buffers_) {
124
149
buffer.release ();
125
150
}
151
+ for (auto & buffer : unused_command_buffers_) {
152
+ buffer.release ();
153
+ }
154
+ unused_command_buffers_.clear ();
126
155
collected_buffers_.clear ();
127
156
}
128
157
@@ -158,13 +187,13 @@ std::shared_ptr<CommandPoolVK> CommandPoolRecyclerVK::Get() {
158
187
}
159
188
160
189
// Otherwise, create a new resource and return it.
161
- auto pool = Create ();
162
- if (!pool) {
190
+ auto data = Create ();
191
+ if (!data || !data-> pool ) {
163
192
return nullptr ;
164
193
}
165
194
166
- auto const resource =
167
- std::make_shared<CommandPoolVK>( std::move (*pool ), context_);
195
+ auto const resource = std::make_shared<CommandPoolVK>(
196
+ std::move (data-> pool ), std::move (data-> buffers ), context_);
168
197
pool_map.emplace (hash, resource);
169
198
170
199
{
@@ -176,10 +205,11 @@ std::shared_ptr<CommandPoolVK> CommandPoolRecyclerVK::Get() {
176
205
}
177
206
178
207
// TODO(matanlurey): Return a status_or<> instead of nullopt when we have one.
179
- std::optional<vk::UniqueCommandPool> CommandPoolRecyclerVK::Create () {
180
- // If we can reuse a command pool, do so.
181
- if (auto pool = Reuse ()) {
182
- return pool;
208
+ std::optional<CommandPoolRecyclerVK::RecycledData>
209
+ CommandPoolRecyclerVK::Create () {
210
+ // If we can reuse a command pool and its buffers, do so.
211
+ if (auto data = Reuse ()) {
212
+ return data;
183
213
}
184
214
185
215
// Otherwise, create a new one.
@@ -196,23 +226,27 @@ std::optional<vk::UniqueCommandPool> CommandPoolRecyclerVK::Create() {
196
226
if (result != vk::Result::eSuccess) {
197
227
return std::nullopt;
198
228
}
199
- return std::move (pool);
229
+ return CommandPoolRecyclerVK::RecycledData{.pool = std::move (pool),
230
+ .buffers = {}};
200
231
}
201
232
202
- std::optional<vk::UniqueCommandPool> CommandPoolRecyclerVK::Reuse () {
233
+ std::optional<CommandPoolRecyclerVK::RecycledData>
234
+ CommandPoolRecyclerVK::Reuse () {
203
235
// If there are no recycled pools, return nullopt.
204
236
Lock recycled_lock (recycled_mutex_);
205
237
if (recycled_.empty ()) {
206
238
return std::nullopt;
207
239
}
208
240
209
241
// Otherwise, remove and return a recycled pool.
210
- auto pool = std::move (recycled_.back ());
242
+ auto data = std::move (recycled_.back ());
211
243
recycled_.pop_back ();
212
- return std::move (pool );
244
+ return std::move (data );
213
245
}
214
246
215
- void CommandPoolRecyclerVK::Reclaim (vk::UniqueCommandPool&& pool) {
247
+ void CommandPoolRecyclerVK::Reclaim (
248
+ vk::UniqueCommandPool&& pool,
249
+ std::vector<vk::UniqueCommandBuffer>&& buffers) {
216
250
// Reset the pool on a background thread.
217
251
auto strong_context = context_.lock ();
218
252
if (!strong_context) {
@@ -223,7 +257,8 @@ void CommandPoolRecyclerVK::Reclaim(vk::UniqueCommandPool&& pool) {
223
257
224
258
// Move the pool to the recycled list.
225
259
Lock recycled_lock (recycled_mutex_);
226
- recycled_.push_back (std::move (pool));
260
+ recycled_.push_back (
261
+ RecycledData{.pool = std::move (pool), .buffers = std::move (buffers)});
227
262
}
228
263
229
264
CommandPoolRecyclerVK::~CommandPoolRecyclerVK () {
0 commit comments