Flutter Impeller
impeller::DescriptorPoolRecyclerVK Class Referencefinal

Creates and manages the lifecycle of |vk::DescriptorPoolVK| objects. More...

#include <descriptor_pool_vk.h>

Inheritance diagram for impeller::DescriptorPoolRecyclerVK:

Public Member Functions

 ~DescriptorPoolRecyclerVK ()=default
 
 DescriptorPoolRecyclerVK (std::weak_ptr< ContextVK > context)
 Creates a recycler for the given |ContextVK|. More...
 
DescriptorPoolAndSize Get (uint32_t minimum_capacity)
 Gets a descriptor pool with at least [minimum_capacity] sampler and slots. More...
 
void Reclaim (vk::UniqueDescriptorPool &&pool, uint32_t allocated_capacity)
 Returns the descriptor pool to be reset on a background thread. More...
 

Static Public Attributes

static constexpr size_t kMaxRecycledPools = 32u
 The maximum number of descriptor pools this recycler will hold onto. More...
 

Detailed Description

Creates and manages the lifecycle of |vk::DescriptorPoolVK| objects.

To make descriptor pool recycling more effective, the number of requusted descriptor slots is rounded up the nearest power of two. This also makes determining whether a recycled pool has sufficient slots easier as only a single number comparison is required.

We round up to a minimum of 64 as the smallest power of two to reduce the range of potential allocations to approximately: 64, 128, 256, 512, 1024, 2048, 4096. Beyond this size applications will have far too many drawing commands to render correctly. We also limit the number of cached descriptor pools to 32, which is somewhat arbitrarily chosen, but given 2-ish frames in flight is about 16 descriptors pools per frame which is extremely generous.

Definition at line 67 of file descriptor_pool_vk.h.

Constructor & Destructor Documentation

◆ ~DescriptorPoolRecyclerVK()

impeller::DescriptorPoolRecyclerVK::~DescriptorPoolRecyclerVK ( )
default

◆ DescriptorPoolRecyclerVK()

impeller::DescriptorPoolRecyclerVK::DescriptorPoolRecyclerVK ( std::weak_ptr< ContextVK context)
inlineexplicit

Creates a recycler for the given |ContextVK|.

Parameters
[in]contextThe context to create the recycler for.

Definition at line 78 of file descriptor_pool_vk.h.

79  : context_(std::move(context)) {}

Member Function Documentation

◆ Get()

DescriptorPoolAndSize impeller::DescriptorPoolRecyclerVK::Get ( uint32_t  minimum_capacity)

Gets a descriptor pool with at least [minimum_capacity] sampler and slots.

This may create a new descriptor pool if no existing pools had the necessary capacity.

Definition at line 158 of file descriptor_pool_vk.cc.

158  {
159  // See note on DescriptorPoolRecyclerVK doc comment.
160  auto rounded_capacity =
161  std::max(Allocation::NextPowerOfTwoSize(minimum_capacity), 64u);
162 
163  // Recycle a pool with a matching minumum capcity if it is available.
164  auto recycled_pool = Reuse(rounded_capacity);
165  if (recycled_pool.has_value()) {
166  return std::move(recycled_pool.value());
167  }
168  return Create(rounded_capacity);
169 }

References impeller::Allocation::NextPowerOfTwoSize().

◆ Reclaim()

void impeller::DescriptorPoolRecyclerVK::Reclaim ( vk::UniqueDescriptorPool &&  pool,
uint32_t  allocated_capacity 
)

Returns the descriptor pool to be reset on a background thread.

Parameters
[in]poolThe pool to recycler.

Definition at line 117 of file descriptor_pool_vk.cc.

118  {
119  // Reset the pool on a background thread.
120  auto strong_context = context_.lock();
121  if (!strong_context) {
122  return;
123  }
124  auto device = strong_context->GetDevice();
125  device.resetDescriptorPool(pool.get());
126 
127  // Move the pool to the recycled list.
128  Lock recycled_lock(recycled_mutex_);
129 
130  if (recycled_.size() < kMaxRecycledPools) {
131  recycled_.push_back(std::make_pair(std::move(pool), allocated_capacity));
132  return;
133  }
134 
135  // If recycled has exceeded the max size of 32, then we need to remove a pool
136  // from the list. If we were to drop this pool, then there is a risk that
137  // the list of recycled descriptor pools could fill up with descriptors that
138  // are too small to reuse. This would lead to all subsequent descriptor
139  // allocations no longer being recycled. Instead, we pick the first
140  // descriptor pool with a smaller capacity than the reseting pool to drop.
141  // This may result in us dropping the current pool instead.
142  std::optional<size_t> selected_index = std::nullopt;
143  for (auto i = 0u; i < recycled_.size(); i++) {
144  const auto& [_, capacity] = recycled_[i];
145  if (capacity < allocated_capacity) {
146  selected_index = i;
147  break;
148  }
149  }
150  if (selected_index.has_value()) {
151  recycled_[selected_index.value()] =
152  std::make_pair(std::move(pool), allocated_capacity);
153  }
154  // If selected index has no value, then no pools had a smaller capacity than
155  // this one and we drop it instead.
156 }

References kMaxRecycledPools.

Member Data Documentation

◆ kMaxRecycledPools

constexpr size_t impeller::DescriptorPoolRecyclerVK::kMaxRecycledPools = 32u
staticconstexpr

The maximum number of descriptor pools this recycler will hold onto.

Definition at line 73 of file descriptor_pool_vk.h.

Referenced by Reclaim().


The documentation for this class was generated from the following files:
impeller::Allocation::NextPowerOfTwoSize
static uint32_t NextPowerOfTwoSize(uint32_t x)
Definition: allocation.cc:41
impeller::DescriptorPoolRecyclerVK::kMaxRecycledPools
static constexpr size_t kMaxRecycledPools
The maximum number of descriptor pools this recycler will hold onto.
Definition: descriptor_pool_vk.h:73