Index: ps/trunk/source/renderer/backend/vulkan/DescriptorManager.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/DescriptorManager.h +++ ps/trunk/source/renderer/backend/vulkan/DescriptorManager.h @@ -76,7 +76,14 @@ VkDescriptorSetLayout layout; VkDescriptorPool pool; int16_t firstFreeIndex = 0; - std::vector> elements; + static constexpr int16_t INVALID_INDEX = -1; + struct Element + { + VkDescriptorSet set = VK_NULL_HANDLE; + uint32_t version = 0; + int16_t nextFreeIndex = INVALID_INDEX; + }; + std::vector elements; }; SingleTypePool& GetSingleTypePool(const VkDescriptorType type, const uint32_t size); @@ -105,7 +112,14 @@ std::unordered_map m_TextureToBindingMap; std::unordered_map> m_SingleTypePools; - std::unordered_map>> m_TextureSingleTypePoolMap; + struct SingleTypePoolReference + { + VkDescriptorType type = VK_DESCRIPTOR_TYPE_MAX_ENUM; + uint32_t version = 0; + int16_t elementIndex = SingleTypePool::INVALID_INDEX; + uint8_t size = 0; + }; + std::unordered_map> m_TextureSingleTypePoolMap; using SingleTypeCacheKey = std::pair>; struct SingleTypeCacheKeyHash @@ -113,6 +127,8 @@ size_t operator()(const SingleTypeCacheKey& key) const; }; std::unordered_map m_SingleTypeSets; + + std::unique_ptr m_ErrorTexture; }; } // namespace Vulkan Index: ps/trunk/source/renderer/backend/vulkan/DescriptorManager.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/DescriptorManager.cpp +++ ps/trunk/source/renderer/backend/vulkan/DescriptorManager.cpp @@ -39,7 +39,13 @@ { CDescriptorManager::CDescriptorManager(CDevice* device, const bool useDescriptorIndexing) - : m_Device(device), m_UseDescriptorIndexing(useDescriptorIndexing) + : m_Device(device), m_UseDescriptorIndexing(useDescriptorIndexing), + m_ErrorTexture(device->CreateTexture( + "DescriptorManagerErrorTexture", ITexture::Type::TEXTURE_2D, + ITexture::Usage::TRANSFER_DST | ITexture::Usage::SAMPLED, + Format::R8G8B8A8_UNORM, 1, 1, + Sampler::MakeDefaultSampler(Sampler::Filter::NEAREST, Sampler::AddressMode::REPEAT), + 1, 1)) { if (useDescriptorIndexing) { @@ -190,8 +196,8 @@ pool.firstFreeIndex = 0; pool.elements.reserve(maxSets); for (uint32_t index = 0; index < maxSets; ++index) - pool.elements.push_back({VK_NULL_HANDLE, static_cast(index + 1)}); - pool.elements.back().second = -1; + pool.elements.push_back({VK_NULL_HANDLE, 1, static_cast(index + 1)}); + pool.elements.back().nextFreeIndex = SingleTypePool::INVALID_INDEX; } return pool; } @@ -224,11 +230,15 @@ { SingleTypePool& pool = GetSingleTypePool(type, texturesUID.size()); const int16_t elementIndex = pool.firstFreeIndex; - ENSURE(elementIndex != -1); - std::pair& element = pool.elements[elementIndex]; - pool.firstFreeIndex = element.second; + ENSURE(elementIndex != SingleTypePool::INVALID_INDEX); + SingleTypePool::Element& element = pool.elements[elementIndex]; + ENSURE(pool.firstFreeIndex != element.nextFreeIndex); + pool.firstFreeIndex = element.nextFreeIndex; + ++element.version; + // Occupy the index. + element.nextFreeIndex = SingleTypePool::INVALID_INDEX; - if (element.first == VK_NULL_HANDLE) + if (element.set == VK_NULL_HANDLE) { VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{}; descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -237,41 +247,40 @@ descriptorSetAllocateInfo.pSetLayouts = &layout; ENSURE_VK_SUCCESS(vkAllocateDescriptorSets( - m_Device->GetVkDevice(), &descriptorSetAllocateInfo, &element.first)); + m_Device->GetVkDevice(), &descriptorSetAllocateInfo, &element.set)); } - it = m_SingleTypeSets.emplace(key, element.first).first; + it = m_SingleTypeSets.emplace(key, element.set).first; for (const CTexture::UID uid : texturesUID) - m_TextureSingleTypePoolMap[uid].push_back({type, static_cast(texturesUID.size()), elementIndex}); + if (uid != CTexture::INVALID_UID) + m_TextureSingleTypePoolMap[uid].push_back({type, element.version, elementIndex, static_cast(texturesUID.size())}); PS::StaticVector infos; - PS::StaticVector writes; - for (size_t index = 0; index < textures.size(); ++index) + for (CTexture* texture : textures) { - if (!textures[index]) - continue; - ENSURE(textures[index]->GetUsage() & ITexture::Usage::SAMPLED); + if (!texture) + texture = m_ErrorTexture->As(); + ENSURE(texture->GetUsage() & ITexture::Usage::SAMPLED); VkDescriptorImageInfo descriptorImageInfo{}; descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - descriptorImageInfo.imageView = textures[index]->GetSamplerImageView(); - descriptorImageInfo.sampler = textures[index]->GetSampler(); + descriptorImageInfo.imageView = texture->GetSamplerImageView(); + descriptorImageInfo.sampler = texture->GetSampler(); infos.emplace_back(std::move(descriptorImageInfo)); - - VkWriteDescriptorSet writeDescriptorSet{}; - writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSet.dstSet = element.first; - writeDescriptorSet.dstBinding = index; - writeDescriptorSet.dstArrayElement = 0; - writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSet.descriptorCount = 1; - writeDescriptorSet.pImageInfo = &infos.back(); - writes.emplace_back(std::move(writeDescriptorSet)); } + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.dstSet = element.set; + writeDescriptorSet.dstBinding = 0; + writeDescriptorSet.dstArrayElement = 0; + writeDescriptorSet.descriptorType = type; + writeDescriptorSet.descriptorCount = static_cast(infos.size()); + writeDescriptorSet.pImageInfo = infos.data(); + vkUpdateDescriptorSets( - m_Device->GetVkDevice(), writes.size(), writes.data(), 0, nullptr); + m_Device->GetVkDevice(), 1, &writeDescriptorSet, 0, nullptr); } return it->second; } @@ -330,6 +339,7 @@ void CDescriptorManager::OnTextureDestroy(const CTexture::UID uid) { + ENSURE(uid != CTexture::INVALID_UID); if (m_UseDescriptorIndexing) { DescriptorIndexingBindingMap& bindingMap = @@ -342,6 +352,7 @@ const int16_t index = it->second; bindingMap.elements[index] = bindingMap.firstFreeIndex; bindingMap.firstFreeIndex = index; + bindingMap.map.erase(it); } else { @@ -350,11 +361,18 @@ return; for (const auto& entry : it->second) { - SingleTypePool& pool = GetSingleTypePool(std::get<0>(entry), std::get<1>(entry)); - const int16_t elementIndex = std::get<2>(entry); - pool.elements[elementIndex].second = pool.firstFreeIndex; - pool.firstFreeIndex = elementIndex; + SingleTypePool& pool = GetSingleTypePool(entry.type, entry.size); + SingleTypePool::Element& element = pool.elements[entry.elementIndex]; + // Multiple textures might be used by the same descriptor set and + // we don't need to reset it if it was already. + if (element.version == entry.version && element.nextFreeIndex == SingleTypePool::INVALID_INDEX) + { + ENSURE(pool.firstFreeIndex != entry.elementIndex); + element.nextFreeIndex = pool.firstFreeIndex; + pool.firstFreeIndex = entry.elementIndex; + } } + m_TextureSingleTypePoolMap.erase(it); } } Index: ps/trunk/source/renderer/backend/vulkan/Texture.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Texture.h +++ ps/trunk/source/renderer/backend/vulkan/Texture.h @@ -72,6 +72,7 @@ * a too big texture flow. */ using UID = uint32_t; + static constexpr UID INVALID_UID = 0; UID GetUID() const { return m_UID; } private: