Flutter Impeller
command_pool_vk.h
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 #ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_COMMAND_POOL_VK_H_
6 #define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_COMMAND_POOL_VK_H_
7 
8 #include <memory>
9 #include <optional>
10 #include <utility>
11 
12 #include "impeller/base/thread.h"
13 #include "impeller/renderer/backend/vulkan/vk.h" // IWYU pragma: keep.
14 #include "vulkan/vulkan_handles.hpp"
15 
16 namespace impeller {
17 
18 class ContextVK;
19 class CommandPoolRecyclerVK;
20 
21 //------------------------------------------------------------------------------
22 /// @brief Manages the lifecycle of a single |vk::CommandPool|.
23 ///
24 /// A |vk::CommandPool| is expensive to create and reset. This class manages
25 /// the lifecycle of a single |vk::CommandPool| by returning to the origin
26 /// (|CommandPoolRecyclerVK|) when it is destroyed to be reused.
27 ///
28 /// @warning This class is not thread-safe.
29 ///
30 /// @see |CommandPoolRecyclerVK|
31 class CommandPoolVK final {
32  public:
34 
35  /// @brief Creates a resource that manages the life of a command pool.
36  ///
37  /// @param[in] pool The command pool to manage.
38  /// @param[in] buffers Zero or more command buffers in an initial state.
39  /// @param[in] recycler The context that will be notified on destruction.
40  CommandPoolVK(vk::UniqueCommandPool pool,
41  std::vector<vk::UniqueCommandBuffer>&& buffers,
42  std::weak_ptr<ContextVK>& context)
43  : pool_(std::move(pool)),
44  unused_command_buffers_(std::move(buffers)),
45  context_(context) {}
46 
47  /// @brief Creates and returns a new |vk::CommandBuffer|.
48  ///
49  /// @return Always returns a new |vk::CommandBuffer|, but if for any
50  /// reason a valid command buffer could not be created, it will be
51  /// a `{}` default instance (i.e. while being torn down).
52  vk::UniqueCommandBuffer CreateCommandBuffer();
53 
54  /// @brief Collects the given |vk::CommandBuffer| to be retained.
55  ///
56  /// @param[in] buffer The |vk::CommandBuffer| to collect.
57  ///
58  /// @see |GarbageCollectBuffersIfAble|
59  void CollectCommandBuffer(vk::UniqueCommandBuffer&& buffer);
60 
61  /// @brief Delete all Vulkan objects in this command pool.
62  void Destroy();
63 
64  private:
65  CommandPoolVK(const CommandPoolVK&) = delete;
66 
67  CommandPoolVK& operator=(const CommandPoolVK&) = delete;
68 
69  Mutex pool_mutex_;
70  vk::UniqueCommandPool pool_ IPLR_GUARDED_BY(pool_mutex_);
71  std::vector<vk::UniqueCommandBuffer> unused_command_buffers_;
72  std::weak_ptr<ContextVK>& context_;
73 
74  // Used to retain a reference on these until the pool is reset.
75  std::vector<vk::UniqueCommandBuffer> collected_buffers_ IPLR_GUARDED_BY(
76  pool_mutex_);
77 };
78 
79 //------------------------------------------------------------------------------
80 /// @brief Creates and manages the lifecycle of |vk::CommandPool| objects.
81 ///
82 /// A |vk::CommandPool| is expensive to create and reset. This class manages
83 /// the lifecycle of |vk::CommandPool| objects by creating and recycling them;
84 /// or in other words, a pool for command pools.
85 ///
86 /// A single instance should be created per |ContextVK|.
87 ///
88 /// Every "frame", a single |CommandPoolResourceVk| is made available for each
89 /// thread that calls |Get|. After calling |Dispose|, the current thread's pool
90 /// is moved to a background thread, reset, and made available for the next time
91 /// |Get| is called and needs to create a command pool.
92 ///
93 /// Commands in the command pool are not necessarily done executing when the
94 /// pool is recycled, when all references are dropped to the pool, they are
95 /// reset and returned to the pool of available pools.
96 ///
97 /// @note This class is thread-safe.
98 ///
99 /// @see |vk::CommandPoolResourceVk|
100 /// @see |ContextVK|
101 /// @see
102 /// https://arm-software.github.io/vulkan_best_practice_for_mobile_developers/samples/performance/command_buffer_usage/command_buffer_usage_tutorial.html
104  : public std::enable_shared_from_this<CommandPoolRecyclerVK> {
105  public:
107 
108  /// A unique command pool and zero or more recycled command buffers.
109  struct RecycledData {
110  vk::UniqueCommandPool pool;
111  std::vector<vk::UniqueCommandBuffer> buffers;
112  };
113 
114  /// @brief Clean up resources held by all per-thread command pools
115  /// associated with the given context.
116  ///
117  /// @param[in] context The context.
118  static void DestroyThreadLocalPools(const ContextVK* context);
119 
120  /// @brief Creates a recycler for the given |ContextVK|.
121  ///
122  /// @param[in] context The context to create the recycler for.
123  explicit CommandPoolRecyclerVK(std::weak_ptr<ContextVK> context)
124  : context_(std::move(context)) {}
125 
126  /// @brief Gets a command pool for the current thread.
127  ///
128  /// @warning Returns a |nullptr| if a pool could not be created.
129  std::shared_ptr<CommandPoolVK> Get();
130 
131  /// @brief Returns a command pool to be reset on a background thread.
132  ///
133  /// @param[in] pool The pool to recycler.
134  void Reclaim(vk::UniqueCommandPool&& pool,
135  std::vector<vk::UniqueCommandBuffer>&& buffers);
136 
137  /// @brief Clears all recycled command pools to let them be reclaimed.
138  void Dispose();
139 
140  private:
141  std::weak_ptr<ContextVK> context_;
142 
143  Mutex recycled_mutex_;
144  std::vector<RecycledData> recycled_ IPLR_GUARDED_BY(recycled_mutex_);
145 
146  /// @brief Creates a new |vk::CommandPool|.
147  ///
148  /// @returns Returns a |std::nullopt| if a pool could not be created.
149  std::optional<CommandPoolRecyclerVK::RecycledData> Create();
150 
151  /// @brief Reuses a recycled |RecycledData|, if available.
152  ///
153  /// @returns Returns a |std::nullopt| if a pool was not available.
154  std::optional<RecycledData> Reuse();
155 
157 
158  CommandPoolRecyclerVK& operator=(const CommandPoolRecyclerVK&) = delete;
159 };
160 
161 } // namespace impeller
162 
163 #endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_COMMAND_POOL_VK_H_
impeller::CommandPoolVK::~CommandPoolVK
~CommandPoolVK()
Definition: command_pool_vk.cc:74
impeller::CommandPoolRecyclerVK::DestroyThreadLocalPools
static void DestroyThreadLocalPools(const ContextVK *context)
Clean up resources held by all per-thread command pools associated with the given context.
Definition: command_pool_vk.cc:285
impeller::CommandPoolRecyclerVK::CommandPoolRecyclerVK
CommandPoolRecyclerVK(std::weak_ptr< ContextVK > context)
Creates a recycler for the given |ContextVK|.
Definition: command_pool_vk.h:123
vk.h
impeller::CommandPoolVK::CollectCommandBuffer
void CollectCommandBuffer(vk::UniqueCommandBuffer &&buffer)
Collects the given |vk::CommandBuffer| to be retained.
Definition: command_pool_vk.cc:131
impeller::CommandPoolRecyclerVK::RecycledData::pool
vk::UniqueCommandPool pool
Definition: command_pool_vk.h:110
impeller::CommandPoolVK
Manages the lifecycle of a single |vk::CommandPool|.
Definition: command_pool_vk.h:31
impeller::CommandPoolRecyclerVK::RecycledData::buffers
std::vector< vk::UniqueCommandBuffer > buffers
Definition: command_pool_vk.h:111
impeller::CommandPoolRecyclerVK::Get
std::shared_ptr< CommandPoolVK > Get()
Gets a command pool for the current thread.
Definition: command_pool_vk.cc:181
impeller::CommandPoolVK::Destroy
void Destroy()
Delete all Vulkan objects in this command pool.
Definition: command_pool_vk.cc:142
impeller::CommandPoolRecyclerVK::~CommandPoolRecyclerVK
~CommandPoolRecyclerVK()
Definition: command_pool_vk.cc:273
impeller::CommandPoolRecyclerVK::Dispose
void Dispose()
Clears all recycled command pools to let them be reclaimed.
Definition: command_pool_vk.cc:278
impeller::CommandPoolVK::CreateCommandBuffer
vk::UniqueCommandBuffer CreateCommandBuffer()
Creates and returns a new |vk::CommandBuffer|.
Definition: command_pool_vk.cc:103
impeller::ContextVK
Definition: context_vk.h:42
std
Definition: comparable.h:95
impeller::CommandPoolVK::CommandPoolVK
CommandPoolVK(vk::UniqueCommandPool pool, std::vector< vk::UniqueCommandBuffer > &&buffers, std::weak_ptr< ContextVK > &context)
Creates a resource that manages the life of a command pool.
Definition: command_pool_vk.h:40
impeller::CommandPoolRecyclerVK::RecycledData
A unique command pool and zero or more recycled command buffers.
Definition: command_pool_vk.h:109
impeller::CommandPoolRecyclerVK::Reclaim
void Reclaim(vk::UniqueCommandPool &&pool, std::vector< vk::UniqueCommandBuffer > &&buffers)
Returns a command pool to be reset on a background thread.
Definition: command_pool_vk.cc:256
impeller::CommandPoolRecyclerVK
Creates and manages the lifecycle of |vk::CommandPool| objects.
Definition: command_pool_vk.h:103
thread.h
impeller
Definition: aiks_blur_unittests.cc:20