LCOV - code coverage report
Current view: top level - source/renderer/backend/vulkan - DescriptorManager.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 200 0.5 %
Date: 2023-01-19 00:18:29 Functions: 2 11 18.2 %

          Line data    Source code
       1             : /* Copyright (C) 2023 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "DescriptorManager.h"
      21             : 
      22             : #include "lib/hash.h"
      23             : #include "ps/containers/StaticVector.h"
      24             : #include "renderer/backend/vulkan/Device.h"
      25             : #include "renderer/backend/vulkan/Mapping.h"
      26             : #include "renderer/backend/vulkan/Texture.h"
      27             : #include "renderer/backend/vulkan/Utilities.h"
      28             : 
      29             : #include <array>
      30             : #include <numeric>
      31             : 
      32             : namespace Renderer
      33             : {
      34             : 
      35             : namespace Backend
      36             : {
      37             : 
      38             : namespace Vulkan
      39             : {
      40             : 
      41           0 : CDescriptorManager::CDescriptorManager(CDevice* device, const bool useDescriptorIndexing)
      42           0 :     : m_Device(device), m_UseDescriptorIndexing(useDescriptorIndexing)
      43             : {
      44           0 :     if (useDescriptorIndexing)
      45             :     {
      46           0 :         VkDescriptorPoolSize descriptorPoolSize{};
      47           0 :         descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
      48           0 :         descriptorPoolSize.descriptorCount = DESCRIPTOR_INDEXING_BINDING_SIZE * NUMBER_OF_BINDINGS_PER_DESCRIPTOR_INDEXING_SET;
      49             : 
      50           0 :         VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{};
      51           0 :         descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
      52           0 :         descriptorPoolCreateInfo.poolSizeCount = 1;
      53           0 :         descriptorPoolCreateInfo.pPoolSizes = &descriptorPoolSize;
      54           0 :         descriptorPoolCreateInfo.maxSets = 1;
      55           0 :         descriptorPoolCreateInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT;
      56           0 :         ENSURE_VK_SUCCESS(vkCreateDescriptorPool(
      57             :             device->GetVkDevice(), &descriptorPoolCreateInfo, nullptr, &m_DescriptorIndexingPool));
      58             : 
      59           0 :         const VkShaderStageFlags stageFlags =
      60             :             VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT;
      61           0 :         const std::array<VkDescriptorSetLayoutBinding, NUMBER_OF_BINDINGS_PER_DESCRIPTOR_INDEXING_SET> bindings{{
      62             :             {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, DESCRIPTOR_INDEXING_BINDING_SIZE, stageFlags},
      63             :             {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, DESCRIPTOR_INDEXING_BINDING_SIZE, stageFlags},
      64             :             {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, DESCRIPTOR_INDEXING_BINDING_SIZE, stageFlags}
      65             :         }};
      66             : 
      67           0 :         const VkDescriptorBindingFlagsEXT baseBindingFlags =
      68             :             VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT
      69             :                 | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT
      70             :                 | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT;
      71           0 :         const std::array<VkDescriptorBindingFlagsEXT, NUMBER_OF_BINDINGS_PER_DESCRIPTOR_INDEXING_SET> bindingFlags{{
      72             :             baseBindingFlags, baseBindingFlags, baseBindingFlags
      73             :         }};
      74             : 
      75           0 :         VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCreateInfo{};
      76           0 :         bindingFlagsCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT;
      77           0 :         bindingFlagsCreateInfo.bindingCount = bindingFlags.size();
      78           0 :         bindingFlagsCreateInfo.pBindingFlags = bindingFlags.data();
      79             : 
      80           0 :         VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{};
      81           0 :         descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
      82           0 :         descriptorSetLayoutCreateInfo.bindingCount = bindings.size();
      83           0 :         descriptorSetLayoutCreateInfo.pBindings = bindings.data();
      84           0 :         descriptorSetLayoutCreateInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
      85           0 :         descriptorSetLayoutCreateInfo.pNext = &bindingFlagsCreateInfo;
      86             : 
      87           0 :         ENSURE_VK_SUCCESS(vkCreateDescriptorSetLayout(
      88             :             device->GetVkDevice(), &descriptorSetLayoutCreateInfo,
      89             :             nullptr, &m_DescriptorIndexingSetLayout));
      90             : 
      91           0 :         m_DescriptorSetLayouts.emplace_back(m_DescriptorIndexingSetLayout);
      92             : 
      93           0 :         VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{};
      94           0 :         descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
      95           0 :         descriptorSetAllocateInfo.descriptorPool = m_DescriptorIndexingPool;
      96           0 :         descriptorSetAllocateInfo.descriptorSetCount = 1;
      97           0 :         descriptorSetAllocateInfo.pSetLayouts = &m_DescriptorIndexingSetLayout;
      98             : 
      99           0 :         ENSURE_VK_SUCCESS(vkAllocateDescriptorSets(
     100             :             device->GetVkDevice(), &descriptorSetAllocateInfo, &m_DescriptorIndexingSet));
     101             : 
     102           0 :         for (DescriptorIndexingBindingMap& bindingMap : m_DescriptorIndexingBindings)
     103             :         {
     104           0 :             bindingMap.firstFreeIndex = 0;
     105           0 :             bindingMap.elements.resize(DESCRIPTOR_INDEXING_BINDING_SIZE);
     106           0 :             std::iota(bindingMap.elements.begin(), std::prev(bindingMap.elements.end()), 1);
     107           0 :             bindingMap.elements.back() = -1;
     108             :         }
     109             :     }
     110             : 
     111             :     // Currently we hard-code the layout for uniforms.
     112           0 :     const VkDescriptorSetLayoutBinding bindings[] =
     113             :     {
     114             :         {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT}
     115             :     };
     116             : 
     117           0 :     VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{};
     118           0 :     descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
     119           0 :     descriptorSetLayoutCreateInfo.bindingCount = std::size(bindings);
     120           0 :     descriptorSetLayoutCreateInfo.pBindings = bindings;
     121             : 
     122           0 :     ENSURE_VK_SUCCESS(vkCreateDescriptorSetLayout(
     123             :         device->GetVkDevice(), &descriptorSetLayoutCreateInfo,
     124             :         nullptr, &m_UniformDescriptorSetLayout));
     125           0 :     m_DescriptorSetLayouts.emplace_back(m_UniformDescriptorSetLayout);
     126           0 : }
     127             : 
     128           0 : CDescriptorManager::~CDescriptorManager()
     129             : {
     130           0 :     VkDevice device = m_Device->GetVkDevice();
     131             : 
     132           0 :     for (auto& pair: m_SingleTypePools)
     133             :     {
     134           0 :         for (SingleTypePool& pool : pair.second)
     135             :         {
     136           0 :             if (pool.pool != VK_NULL_HANDLE)
     137           0 :                 vkDestroyDescriptorPool(device, pool.pool, nullptr);
     138           0 :             if (pool.layout != VK_NULL_HANDLE)
     139           0 :                 vkDestroyDescriptorSetLayout(device, pool.layout, nullptr);
     140             :         }
     141             :     }
     142           0 :     m_SingleTypePools.clear();
     143             : 
     144           0 :     for (VkDescriptorSetLayout descriptorSetLayout : m_DescriptorSetLayouts)
     145           0 :         vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
     146           0 :     m_DescriptorSetLayouts.clear();
     147             : 
     148           0 :     if (m_DescriptorIndexingPool != VK_NULL_HANDLE)
     149           0 :         vkDestroyDescriptorPool(device, m_DescriptorIndexingPool, nullptr);
     150           0 : }
     151             : 
     152           0 : CDescriptorManager::SingleTypePool& CDescriptorManager::GetSingleTypePool(
     153             :     const VkDescriptorType type, const uint32_t size)
     154             : {
     155           0 :     ENSURE(size > 0 && size <= 16);
     156           0 :     std::vector<SingleTypePool>& pools = m_SingleTypePools[type];
     157           0 :     if (pools.size() <= size)
     158           0 :         pools.resize(size + 1);
     159           0 :     SingleTypePool& pool = pools[size];
     160           0 :     if (pool.pool == VK_NULL_HANDLE)
     161             :     {
     162           0 :         constexpr uint32_t maxSets = 16384;
     163             : 
     164           0 :         VkDescriptorPoolSize descriptorPoolSize{};
     165           0 :         descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
     166           0 :         descriptorPoolSize.descriptorCount = maxSets * size;
     167             : 
     168           0 :         VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{};
     169           0 :         descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
     170           0 :         descriptorPoolCreateInfo.poolSizeCount = 1;
     171           0 :         descriptorPoolCreateInfo.pPoolSizes = &descriptorPoolSize;
     172           0 :         descriptorPoolCreateInfo.maxSets = maxSets;
     173           0 :         ENSURE_VK_SUCCESS(vkCreateDescriptorPool(
     174             :             m_Device->GetVkDevice(), &descriptorPoolCreateInfo, nullptr, &pool.pool));
     175             : 
     176           0 :         const VkPipelineStageFlags stageFlags =
     177             :             VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT;
     178           0 :         PS::StaticVector<VkDescriptorSetLayoutBinding, 16> bindings;
     179           0 :         for (uint32_t index = 0; index < size; ++index)
     180           0 :             bindings.emplace_back(VkDescriptorSetLayoutBinding{index, type, 1, stageFlags});
     181             : 
     182           0 :         VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{};
     183           0 :         descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
     184           0 :         descriptorSetLayoutCreateInfo.bindingCount = size;
     185           0 :         descriptorSetLayoutCreateInfo.pBindings = bindings.data();
     186             : 
     187           0 :         ENSURE_VK_SUCCESS(vkCreateDescriptorSetLayout(
     188             :             m_Device->GetVkDevice(), &descriptorSetLayoutCreateInfo, nullptr, &pool.layout));
     189             : 
     190           0 :         pool.firstFreeIndex = 0;
     191           0 :         pool.elements.reserve(maxSets);
     192           0 :         for (uint32_t index = 0; index < maxSets; ++index)
     193           0 :             pool.elements.push_back({VK_NULL_HANDLE, static_cast<int16_t>(index + 1)});
     194           0 :         pool.elements.back().second = -1;
     195             :     }
     196           0 :     return pool;
     197             : }
     198             : 
     199           0 : VkDescriptorSetLayout CDescriptorManager::GetSingleTypeDescritorSetLayout(
     200             :     VkDescriptorType type, const uint32_t size)
     201             : {
     202           0 :     return GetSingleTypePool(type, size).layout;
     203             : }
     204             : 
     205           0 : size_t CDescriptorManager::SingleTypeCacheKeyHash::operator()(const SingleTypeCacheKey& key) const
     206             : {
     207           0 :     size_t seed = 0;
     208           0 :     hash_combine(seed, key.first);
     209           0 :     for (CTexture::UID uid : key.second)
     210           0 :         hash_combine(seed, uid);
     211           0 :     return seed;
     212             : }
     213             : 
     214           0 : VkDescriptorSet CDescriptorManager::GetSingleTypeDescritorSet(
     215             :     VkDescriptorType type, VkDescriptorSetLayout layout,
     216             :     const std::vector<CTexture::UID>& texturesUID,
     217             :     const std::vector<CTexture*>& textures)
     218             : {
     219           0 :     ENSURE(texturesUID.size() == textures.size());
     220           0 :     ENSURE(!texturesUID.empty());
     221           0 :     const SingleTypeCacheKey key{layout, texturesUID};
     222           0 :     auto it = m_SingleTypeSets.find(key);
     223           0 :     if (it == m_SingleTypeSets.end())
     224             :     {
     225           0 :         SingleTypePool& pool = GetSingleTypePool(type, texturesUID.size());
     226           0 :         const int16_t elementIndex = pool.firstFreeIndex;
     227           0 :         ENSURE(elementIndex != -1);
     228           0 :         std::pair<VkDescriptorSet, int16_t>& element = pool.elements[elementIndex];
     229           0 :         pool.firstFreeIndex = element.second;
     230             : 
     231           0 :         if (element.first == VK_NULL_HANDLE)
     232             :         {
     233           0 :             VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{};
     234           0 :             descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
     235           0 :             descriptorSetAllocateInfo.descriptorPool = pool.pool;
     236           0 :             descriptorSetAllocateInfo.descriptorSetCount = 1;
     237           0 :             descriptorSetAllocateInfo.pSetLayouts = &layout;
     238             : 
     239           0 :             ENSURE_VK_SUCCESS(vkAllocateDescriptorSets(
     240             :                 m_Device->GetVkDevice(), &descriptorSetAllocateInfo, &element.first));
     241             :         }
     242             : 
     243           0 :         it = m_SingleTypeSets.emplace(key, element.first).first;
     244             : 
     245           0 :         for (const CTexture::UID uid : texturesUID)
     246           0 :             m_TextureSingleTypePoolMap[uid].push_back({type, static_cast<uint8_t>(texturesUID.size()), elementIndex});
     247             : 
     248           0 :         PS::StaticVector<VkDescriptorImageInfo, 16> infos;
     249           0 :         PS::StaticVector<VkWriteDescriptorSet, 16> writes;
     250           0 :         for (size_t index = 0; index < textures.size(); ++index)
     251             :         {
     252           0 :             if (!textures[index])
     253           0 :                 continue;
     254           0 :             VkDescriptorImageInfo descriptorImageInfo{};
     255           0 :             descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
     256           0 :             descriptorImageInfo.imageView = textures[index]->GetSamplerImageView();
     257           0 :             descriptorImageInfo.sampler = textures[index]->GetSampler();
     258           0 :             infos.emplace_back(std::move(descriptorImageInfo));
     259             : 
     260           0 :             VkWriteDescriptorSet writeDescriptorSet{};
     261           0 :             writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
     262           0 :             writeDescriptorSet.dstSet = element.first;
     263           0 :             writeDescriptorSet.dstBinding = index;
     264           0 :             writeDescriptorSet.dstArrayElement = 0;
     265           0 :             writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
     266           0 :             writeDescriptorSet.descriptorCount = 1;
     267           0 :             writeDescriptorSet.pImageInfo = &infos.back();
     268           0 :             writes.emplace_back(std::move(writeDescriptorSet));
     269             :         }
     270             : 
     271           0 :         vkUpdateDescriptorSets(
     272           0 :             m_Device->GetVkDevice(), writes.size(), writes.data(), 0, nullptr);
     273             :     }
     274           0 :     return it->second;
     275             : }
     276             : 
     277           0 : uint32_t CDescriptorManager::GetUniformSet() const
     278             : {
     279           0 :     return m_UseDescriptorIndexing ? 1 : 0;
     280             : }
     281             : 
     282           0 : uint32_t CDescriptorManager::GetTextureDescriptor(CTexture* texture)
     283             : {
     284           0 :     ENSURE(m_UseDescriptorIndexing);
     285             : 
     286           0 :     uint32_t binding = 0;
     287           0 :     if (texture->GetType() == ITexture::Type::TEXTURE_2D &&
     288           0 :         IsDepthFormat(texture->GetFormat()) &&
     289           0 :         texture->IsCompareEnabled())
     290           0 :         binding = 2;
     291           0 :     else if (texture->GetType() == ITexture::Type::TEXTURE_CUBE)
     292           0 :         binding = 1;
     293             : 
     294           0 :     DescriptorIndexingBindingMap& bindingMap = m_DescriptorIndexingBindings[binding];
     295           0 :     auto it = bindingMap.map.find(texture->GetUID());
     296           0 :     if (it != bindingMap.map.end())
     297           0 :         return it->second;
     298           0 :     m_TextureToBindingMap[texture->GetUID()] = binding;
     299             : 
     300           0 :     ENSURE(bindingMap.firstFreeIndex != -1);
     301           0 :     uint32_t descriptorSetIndex = bindingMap.firstFreeIndex;
     302           0 :     bindingMap.firstFreeIndex = bindingMap.elements[bindingMap.firstFreeIndex];
     303             : 
     304           0 :     ENSURE(texture->GetType() != ITexture::Type::TEXTURE_2D_MULTISAMPLE);
     305             : 
     306           0 :     VkDescriptorImageInfo descriptorImageInfo{};
     307           0 :     descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
     308           0 :     descriptorImageInfo.imageView = texture->GetSamplerImageView();
     309           0 :     descriptorImageInfo.sampler = texture->GetSampler();
     310             : 
     311           0 :     VkWriteDescriptorSet writeDescriptorSet{};
     312           0 :     writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
     313           0 :     writeDescriptorSet.dstSet = m_DescriptorIndexingSet;
     314           0 :     writeDescriptorSet.dstBinding = binding;
     315           0 :     writeDescriptorSet.dstArrayElement = descriptorSetIndex;
     316           0 :     writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
     317           0 :     writeDescriptorSet.descriptorCount = 1;
     318           0 :     writeDescriptorSet.pImageInfo = &descriptorImageInfo;
     319             : 
     320           0 :     vkUpdateDescriptorSets(
     321           0 :         m_Device->GetVkDevice(), 1, &writeDescriptorSet, 0, nullptr);
     322             : 
     323           0 :     bindingMap.map[texture->GetUID()] = descriptorSetIndex;
     324             : 
     325           0 :     return descriptorSetIndex;
     326             : }
     327             : 
     328           0 : void CDescriptorManager::OnTextureDestroy(const CTexture::UID uid)
     329             : {
     330           0 :     if (m_UseDescriptorIndexing)
     331             :     {
     332             :         DescriptorIndexingBindingMap& bindingMap =
     333           0 :             m_DescriptorIndexingBindings[m_TextureToBindingMap[uid]];
     334           0 :         auto it = bindingMap.map.find(uid);
     335             :         // It's possible to not have the texture in the map. Because a texture will
     336             :         // be added to it only in case of usage.
     337           0 :         if (it == bindingMap.map.end())
     338           0 :             return;
     339           0 :         const int16_t index = it->second;
     340           0 :         bindingMap.elements[index] = bindingMap.firstFreeIndex;
     341           0 :         bindingMap.firstFreeIndex = index;
     342             :     }
     343             :     else
     344             :     {
     345           0 :         auto it = m_TextureSingleTypePoolMap.find(uid);
     346           0 :         if (it == m_TextureSingleTypePoolMap.end())
     347           0 :             return;
     348           0 :         for (const auto& entry : it->second)
     349             :         {
     350           0 :             SingleTypePool& pool = GetSingleTypePool(std::get<0>(entry), std::get<1>(entry));
     351           0 :             const int16_t elementIndex = std::get<2>(entry);
     352           0 :             pool.elements[elementIndex].second = pool.firstFreeIndex;
     353           0 :             pool.firstFreeIndex = elementIndex;
     354             :         }
     355             :     }
     356             : }
     357             : 
     358             : } // namespace Vulkan
     359             : 
     360             : } // namespace Backend
     361             : 
     362           3 : } // namespace Renderer

Generated by: LCOV version 1.13