blob: 063def4e09ccac8fa72be83470c8285a17818430 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 "lib/escher/impl/descriptor_set_pool.h"
#include <map>
#include "lib/escher/impl/command_buffer.h"
#include "lib/escher/impl/vulkan_utils.h"
namespace escher {
namespace impl {
const ResourceTypeInfo DescriptorSetAllocation::kTypeInfo(
"DescriptorSetAllocation", ResourceType::kResource,
ResourceType::kImplDescriptorSetAllocation);
DescriptorSetAllocation::DescriptorSetAllocation(
DescriptorSetPool* pool, std::vector<vk::DescriptorSet> descriptor_sets)
: Resource(pool), sets_(std::move(descriptor_sets)) {}
DescriptorSetAllocation::~DescriptorSetAllocation() {
// We expect that any descriptor sets were recycled by our owner before our
// destructor is called.
FXL_DCHECK(sets_.empty());
}
DescriptorSetPool::DescriptorSetPool(
EscherWeakPtr escher, const vk::DescriptorSetLayoutCreateInfo& layout_info,
uint32_t initial_capacity)
: ResourceRecycler(std::move(escher)),
layout_(ESCHER_CHECKED_VK_RESULT(
vk_device().createDescriptorSetLayout(layout_info))) {
std::map<vk::DescriptorType, uint32_t> descriptor_type_counts;
for (uint32_t i = 0; i < layout_info.bindingCount; ++i) {
descriptor_type_counts[layout_info.pBindings[i].descriptorType] +=
layout_info.pBindings[i].descriptorCount;
}
descriptor_counts_.reserve(descriptor_type_counts.size());
for (auto& pair : descriptor_type_counts) {
vk::DescriptorPoolSize dps;
dps.type = pair.first;
dps.descriptorCount = pair.second;
descriptor_counts_.push_back(dps);
}
InternalAllocate(initial_capacity);
}
DescriptorSetPool::~DescriptorSetPool() {
for (auto pool : pools_) {
vk_device().resetDescriptorPool(pool);
vk_device().destroyDescriptorPool(pool);
}
vk_device().destroyDescriptorSetLayout(layout_);
}
DescriptorSetAllocationPtr DescriptorSetPool::Allocate(
uint32_t count, CommandBuffer* command_buffer) {
// Ensure that enough free sets are available.
if (free_sets_.size() < count) {
constexpr uint32_t kGrowthFactor = 2;
InternalAllocate(count * kGrowthFactor);
}
// Obtain the required number of free descriptor sets.
std::vector<vk::DescriptorSet> allocated_sets;
allocated_sets.reserve(count);
for (size_t i = free_sets_.size() - count; i < free_sets_.size(); ++i) {
allocated_sets.push_back(free_sets_[i]);
}
free_sets_.resize(free_sets_.size() - count);
auto allocation = fxl::AdoptRef(
new DescriptorSetAllocation(this, std::move(allocated_sets)));
if (command_buffer) {
command_buffer->KeepAlive(allocation);
}
return allocation;
}
void DescriptorSetPool::InternalAllocate(uint32_t descriptor_set_count) {
// Allocate a new pool large enough to allocate the desired number of sets.
vk::DescriptorPoolCreateInfo pool_info;
auto counts = descriptor_counts_;
for (auto& c : counts) {
c.descriptorCount *= descriptor_set_count;
}
pool_info.poolSizeCount = static_cast<uint32_t>(counts.size());
pool_info.pPoolSizes = counts.data();
pool_info.maxSets = descriptor_set_count;
auto pool =
ESCHER_CHECKED_VK_RESULT(vk_device().createDescriptorPool(pool_info));
pools_.push_back(pool);
// Allocate the new descriptor sets.
vk::DescriptorSetAllocateInfo allocate_info;
allocate_info.descriptorPool = pool;
allocate_info.descriptorSetCount = descriptor_set_count;
std::vector<vk::DescriptorSetLayout> layouts(descriptor_set_count, layout_);
allocate_info.pSetLayouts = layouts.data();
std::vector<vk::DescriptorSet> new_descriptor_sets(ESCHER_CHECKED_VK_RESULT(
vk_device().allocateDescriptorSets(allocate_info)));
// Add the newly-allocated descriptor sets to the free list.
free_sets_.reserve(free_sets_.capacity() + descriptor_set_count);
for (auto s : new_descriptor_sets) {
free_sets_.push_back(s);
}
}
void DescriptorSetPool::RecycleResource(std::unique_ptr<Resource> resource) {
FXL_DCHECK(resource->IsKindOf<DescriptorSetAllocation>());
auto& returned = static_cast<DescriptorSetAllocation*>(resource.get())->sets_;
free_sets_.insert(free_sets_.end(), returned.begin(), returned.end());
returned.clear();
}
} // namespace impl
} // namespace escher