From 1fe7df45177e805f14f0c9665fd23cac7172769a Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 1 Jan 2020 16:44:06 -0300 Subject: vk_descriptor_pool: Initial implementation Create a large descriptor pool where we allocate all our descriptors from. It has to be wide enough to support any pipeline, hence its large numbers. If the descritor pool is filled, we allocate more memory at that moment. This way we can take advantage of permissive drivers like Nvidia's that allocate more descriptors than what the spec requires. --- .../renderer_vulkan/vk_descriptor_pool.cpp | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/video_core/renderer_vulkan/vk_descriptor_pool.cpp (limited to 'src/video_core/renderer_vulkan/vk_descriptor_pool.cpp') diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp new file mode 100644 index 000000000..7e6e4ccb7 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp @@ -0,0 +1,89 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/common_types.h" +#include "video_core/renderer_vulkan/declarations.h" +#include "video_core/renderer_vulkan/vk_descriptor_pool.h" +#include "video_core/renderer_vulkan/vk_device.h" +#include "video_core/renderer_vulkan/vk_resource_manager.h" + +namespace Vulkan { + +// Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines. +static constexpr std::size_t SETS_GROW_RATE = 0x20; + +DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool, + vk::DescriptorSetLayout layout) + : VKFencedPool{SETS_GROW_RATE}, descriptor_pool{descriptor_pool}, layout{layout} {} + +DescriptorAllocator::~DescriptorAllocator() = default; + +vk::DescriptorSet DescriptorAllocator::Commit(VKFence& fence) { + return *descriptors[CommitResource(fence)]; +} + +void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) { + auto new_sets = descriptor_pool.AllocateDescriptors(layout, end - begin); + descriptors.insert(descriptors.end(), std::make_move_iterator(new_sets.begin()), + std::make_move_iterator(new_sets.end())); +} + +VKDescriptorPool::VKDescriptorPool(const VKDevice& device) + : device{device}, active_pool{AllocateNewPool()} {} + +VKDescriptorPool::~VKDescriptorPool() = default; + +vk::DescriptorPool VKDescriptorPool::AllocateNewPool() { + static constexpr u32 num_sets = 0x20000; + static constexpr vk::DescriptorPoolSize pool_sizes[] = { + {vk::DescriptorType::eUniformBuffer, num_sets * 90}, + {vk::DescriptorType::eStorageBuffer, num_sets * 60}, + {vk::DescriptorType::eUniformTexelBuffer, num_sets * 64}, + {vk::DescriptorType::eCombinedImageSampler, num_sets * 64}, + {vk::DescriptorType::eStorageImage, num_sets * 40}}; + + const vk::DescriptorPoolCreateInfo create_info( + vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, num_sets, + static_cast(std::size(pool_sizes)), std::data(pool_sizes)); + const auto dev = device.GetLogical(); + return *pools.emplace_back( + dev.createDescriptorPoolUnique(create_info, nullptr, device.GetDispatchLoader())); +} + +std::vector VKDescriptorPool::AllocateDescriptors( + vk::DescriptorSetLayout layout, std::size_t count) { + std::vector layout_copies(count, layout); + vk::DescriptorSetAllocateInfo allocate_info(active_pool, static_cast(count), + layout_copies.data()); + + std::vector sets(count); + const auto dev = device.GetLogical(); + const auto& dld = device.GetDispatchLoader(); + switch (const auto result = dev.allocateDescriptorSets(&allocate_info, sets.data(), dld)) { + case vk::Result::eSuccess: + break; + case vk::Result::eErrorOutOfPoolMemory: + active_pool = AllocateNewPool(); + allocate_info.descriptorPool = active_pool; + if (dev.allocateDescriptorSets(&allocate_info, sets.data(), dld) == vk::Result::eSuccess) { + break; + } + [[fallthrough]]; + default: + vk::throwResultException(result, "vk::Device::allocateDescriptorSetsUnique"); + } + + vk::PoolFree deleter(dev, active_pool, dld); + std::vector unique_sets; + unique_sets.reserve(count); + for (const auto set : sets) { + unique_sets.push_back(UniqueDescriptorSet{set, deleter}); + } + return unique_sets; +} + +} // namespace Vulkan -- cgit v1.2.3