// 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. 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