From 1fe7df45177e805f14f0c9665fd23cac7172769a Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 1 Jan 2020 16:44:06 -0300 Subject: [PATCH] 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. --- src/video_core/CMakeLists.txt | 2 + .../renderer_vulkan/vk_descriptor_pool.cpp | 89 +++++++++++++++++++ .../renderer_vulkan/vk_descriptor_pool.h | 56 ++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 src/video_core/renderer_vulkan/vk_descriptor_pool.cpp create mode 100644 src/video_core/renderer_vulkan/vk_descriptor_pool.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 2594cd0bd..13f9848bc 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -157,6 +157,8 @@ if (ENABLE_VULKAN) renderer_vulkan/maxwell_to_vk.h renderer_vulkan/vk_buffer_cache.cpp renderer_vulkan/vk_buffer_cache.h + renderer_vulkan/vk_descriptor_pool.cpp + renderer_vulkan/vk_descriptor_pool.h renderer_vulkan/vk_device.cpp renderer_vulkan/vk_device.h renderer_vulkan/vk_image.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 diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h new file mode 100644 index 000000000..a441dbc0f --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h @@ -0,0 +1,56 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "video_core/renderer_vulkan/declarations.h" +#include "video_core/renderer_vulkan/vk_resource_manager.h" + +namespace Vulkan { + +class VKDescriptorPool; + +class DescriptorAllocator final : public VKFencedPool { +public: + explicit DescriptorAllocator(VKDescriptorPool& descriptor_pool, vk::DescriptorSetLayout layout); + ~DescriptorAllocator() override; + + DescriptorAllocator(const DescriptorAllocator&) = delete; + + vk::DescriptorSet Commit(VKFence& fence); + +protected: + void Allocate(std::size_t begin, std::size_t end) override; + +private: + VKDescriptorPool& descriptor_pool; + const vk::DescriptorSetLayout layout; + + std::vector descriptors; +}; + +class VKDescriptorPool final { + friend DescriptorAllocator; + +public: + explicit VKDescriptorPool(const VKDevice& device); + ~VKDescriptorPool(); + +private: + vk::DescriptorPool AllocateNewPool(); + + std::vector AllocateDescriptors(vk::DescriptorSetLayout layout, + std::size_t count); + + const VKDevice& device; + + std::vector pools; + vk::DescriptorPool active_pool; +}; + +} // namespace Vulkan \ No newline at end of file