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