Index: ps/trunk/source/renderer/backend/vulkan/DescriptorManager.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/DescriptorManager.cpp (revision 27510) +++ ps/trunk/source/renderer/backend/vulkan/DescriptorManager.cpp (revision 27511) @@ -1,365 +1,383 @@ /* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "DescriptorManager.h" #include "lib/hash.h" #include "ps/containers/StaticVector.h" #include "renderer/backend/vulkan/Device.h" #include "renderer/backend/vulkan/Mapping.h" #include "renderer/backend/vulkan/Texture.h" #include "renderer/backend/vulkan/Utilities.h" #include #include namespace Renderer { namespace Backend { namespace Vulkan { 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) { VkDescriptorPoolSize descriptorPoolSize{}; descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorPoolSize.descriptorCount = DESCRIPTOR_INDEXING_BINDING_SIZE * NUMBER_OF_BINDINGS_PER_DESCRIPTOR_INDEXING_SET; VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{}; descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; descriptorPoolCreateInfo.poolSizeCount = 1; descriptorPoolCreateInfo.pPoolSizes = &descriptorPoolSize; descriptorPoolCreateInfo.maxSets = 1; descriptorPoolCreateInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; ENSURE_VK_SUCCESS(vkCreateDescriptorPool( device->GetVkDevice(), &descriptorPoolCreateInfo, nullptr, &m_DescriptorIndexingPool)); const VkShaderStageFlags stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT; const std::array bindings{{ {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, DESCRIPTOR_INDEXING_BINDING_SIZE, stageFlags}, {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, DESCRIPTOR_INDEXING_BINDING_SIZE, stageFlags}, {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, DESCRIPTOR_INDEXING_BINDING_SIZE, stageFlags} }}; const VkDescriptorBindingFlagsEXT baseBindingFlags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT; const std::array bindingFlags{{ baseBindingFlags, baseBindingFlags, baseBindingFlags }}; VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCreateInfo{}; bindingFlagsCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; bindingFlagsCreateInfo.bindingCount = bindingFlags.size(); bindingFlagsCreateInfo.pBindingFlags = bindingFlags.data(); VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{}; descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptorSetLayoutCreateInfo.bindingCount = bindings.size(); descriptorSetLayoutCreateInfo.pBindings = bindings.data(); descriptorSetLayoutCreateInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; descriptorSetLayoutCreateInfo.pNext = &bindingFlagsCreateInfo; ENSURE_VK_SUCCESS(vkCreateDescriptorSetLayout( device->GetVkDevice(), &descriptorSetLayoutCreateInfo, nullptr, &m_DescriptorIndexingSetLayout)); m_DescriptorSetLayouts.emplace_back(m_DescriptorIndexingSetLayout); VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{}; descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; descriptorSetAllocateInfo.descriptorPool = m_DescriptorIndexingPool; descriptorSetAllocateInfo.descriptorSetCount = 1; descriptorSetAllocateInfo.pSetLayouts = &m_DescriptorIndexingSetLayout; ENSURE_VK_SUCCESS(vkAllocateDescriptorSets( device->GetVkDevice(), &descriptorSetAllocateInfo, &m_DescriptorIndexingSet)); for (DescriptorIndexingBindingMap& bindingMap : m_DescriptorIndexingBindings) { bindingMap.firstFreeIndex = 0; bindingMap.elements.resize(DESCRIPTOR_INDEXING_BINDING_SIZE); std::iota(bindingMap.elements.begin(), std::prev(bindingMap.elements.end()), 1); bindingMap.elements.back() = -1; } } // Currently we hard-code the layout for uniforms. const VkDescriptorSetLayoutBinding bindings[] = { {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT} }; VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{}; descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptorSetLayoutCreateInfo.bindingCount = std::size(bindings); descriptorSetLayoutCreateInfo.pBindings = bindings; ENSURE_VK_SUCCESS(vkCreateDescriptorSetLayout( device->GetVkDevice(), &descriptorSetLayoutCreateInfo, nullptr, &m_UniformDescriptorSetLayout)); m_DescriptorSetLayouts.emplace_back(m_UniformDescriptorSetLayout); } CDescriptorManager::~CDescriptorManager() { VkDevice device = m_Device->GetVkDevice(); for (auto& pair: m_SingleTypePools) { for (SingleTypePool& pool : pair.second) { if (pool.pool != VK_NULL_HANDLE) vkDestroyDescriptorPool(device, pool.pool, nullptr); if (pool.layout != VK_NULL_HANDLE) vkDestroyDescriptorSetLayout(device, pool.layout, nullptr); } } m_SingleTypePools.clear(); for (VkDescriptorSetLayout descriptorSetLayout : m_DescriptorSetLayouts) vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); m_DescriptorSetLayouts.clear(); if (m_DescriptorIndexingPool != VK_NULL_HANDLE) vkDestroyDescriptorPool(device, m_DescriptorIndexingPool, nullptr); } CDescriptorManager::SingleTypePool& CDescriptorManager::GetSingleTypePool( const VkDescriptorType type, const uint32_t size) { ENSURE(size > 0 && size <= 16); std::vector& pools = m_SingleTypePools[type]; if (pools.size() <= size) pools.resize(size + 1); SingleTypePool& pool = pools[size]; if (pool.pool == VK_NULL_HANDLE) { constexpr uint32_t maxSets = 16384; VkDescriptorPoolSize descriptorPoolSize{}; descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorPoolSize.descriptorCount = maxSets * size; VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{}; descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; descriptorPoolCreateInfo.poolSizeCount = 1; descriptorPoolCreateInfo.pPoolSizes = &descriptorPoolSize; descriptorPoolCreateInfo.maxSets = maxSets; ENSURE_VK_SUCCESS(vkCreateDescriptorPool( m_Device->GetVkDevice(), &descriptorPoolCreateInfo, nullptr, &pool.pool)); const VkPipelineStageFlags stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT; PS::StaticVector bindings; for (uint32_t index = 0; index < size; ++index) bindings.emplace_back(VkDescriptorSetLayoutBinding{index, type, 1, stageFlags}); VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{}; descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptorSetLayoutCreateInfo.bindingCount = size; descriptorSetLayoutCreateInfo.pBindings = bindings.data(); ENSURE_VK_SUCCESS(vkCreateDescriptorSetLayout( m_Device->GetVkDevice(), &descriptorSetLayoutCreateInfo, nullptr, &pool.layout)); 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; } VkDescriptorSetLayout CDescriptorManager::GetSingleTypeDescritorSetLayout( VkDescriptorType type, const uint32_t size) { return GetSingleTypePool(type, size).layout; } size_t CDescriptorManager::SingleTypeCacheKeyHash::operator()(const SingleTypeCacheKey& key) const { size_t seed = 0; hash_combine(seed, key.first); for (CTexture::UID uid : key.second) hash_combine(seed, uid); return seed; } VkDescriptorSet CDescriptorManager::GetSingleTypeDescritorSet( VkDescriptorType type, VkDescriptorSetLayout layout, const std::vector& texturesUID, const std::vector& textures) { ENSURE(texturesUID.size() == textures.size()); ENSURE(!texturesUID.empty()); const SingleTypeCacheKey key{layout, texturesUID}; auto it = m_SingleTypeSets.find(key); if (it == m_SingleTypeSets.end()) { 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; descriptorSetAllocateInfo.descriptorPool = pool.pool; descriptorSetAllocateInfo.descriptorSetCount = 1; 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; } uint32_t CDescriptorManager::GetUniformSet() const { return m_UseDescriptorIndexing ? 1 : 0; } uint32_t CDescriptorManager::GetTextureDescriptor(CTexture* texture) { ENSURE(m_UseDescriptorIndexing); ENSURE(texture->GetUsage() & ITexture::Usage::SAMPLED); uint32_t binding = 0; if (texture->GetType() == ITexture::Type::TEXTURE_2D && IsDepthFormat(texture->GetFormat()) && texture->IsCompareEnabled()) binding = 2; else if (texture->GetType() == ITexture::Type::TEXTURE_CUBE) binding = 1; DescriptorIndexingBindingMap& bindingMap = m_DescriptorIndexingBindings[binding]; auto it = bindingMap.map.find(texture->GetUID()); if (it != bindingMap.map.end()) return it->second; m_TextureToBindingMap[texture->GetUID()] = binding; ENSURE(bindingMap.firstFreeIndex != -1); uint32_t descriptorSetIndex = bindingMap.firstFreeIndex; bindingMap.firstFreeIndex = bindingMap.elements[bindingMap.firstFreeIndex]; ENSURE(texture->GetType() != ITexture::Type::TEXTURE_2D_MULTISAMPLE); VkDescriptorImageInfo descriptorImageInfo{}; descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; descriptorImageInfo.imageView = texture->GetSamplerImageView(); descriptorImageInfo.sampler = texture->GetSampler(); VkWriteDescriptorSet writeDescriptorSet{}; writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptorSet.dstSet = m_DescriptorIndexingSet; writeDescriptorSet.dstBinding = binding; writeDescriptorSet.dstArrayElement = descriptorSetIndex; writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeDescriptorSet.descriptorCount = 1; writeDescriptorSet.pImageInfo = &descriptorImageInfo; vkUpdateDescriptorSets( m_Device->GetVkDevice(), 1, &writeDescriptorSet, 0, nullptr); bindingMap.map[texture->GetUID()] = descriptorSetIndex; return descriptorSetIndex; } void CDescriptorManager::OnTextureDestroy(const CTexture::UID uid) { + ENSURE(uid != CTexture::INVALID_UID); if (m_UseDescriptorIndexing) { DescriptorIndexingBindingMap& bindingMap = m_DescriptorIndexingBindings[m_TextureToBindingMap[uid]]; auto it = bindingMap.map.find(uid); // It's possible to not have the texture in the map. Because a texture will // be added to it only in case of usage. if (it == bindingMap.map.end()) return; const int16_t index = it->second; bindingMap.elements[index] = bindingMap.firstFreeIndex; bindingMap.firstFreeIndex = index; + bindingMap.map.erase(it); } else { auto it = m_TextureSingleTypePoolMap.find(uid); if (it == m_TextureSingleTypePoolMap.end()) 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); } } } // namespace Vulkan } // namespace Backend } // namespace Renderer Index: ps/trunk/source/renderer/backend/vulkan/DescriptorManager.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/DescriptorManager.h (revision 27510) +++ ps/trunk/source/renderer/backend/vulkan/DescriptorManager.h (revision 27511) @@ -1,124 +1,140 @@ /* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_RENDERER_BACKEND_VULKAN_DESCRIPTORMANAGER #define INCLUDED_RENDERER_BACKEND_VULKAN_DESCRIPTORMANAGER #include "renderer/backend/Sampler.h" #include "renderer/backend/vulkan/Texture.h" #include #include #include #include #include #include namespace Renderer { namespace Backend { namespace Vulkan { class CDevice; class CDescriptorManager { public: CDescriptorManager(CDevice* device, const bool useDescriptorIndexing); ~CDescriptorManager(); bool UseDescriptorIndexing() const { return m_UseDescriptorIndexing; } /** * @return a single type descriptor set layout with the number of bindings * equals to the size. The returned layout is owned by the manager. */ VkDescriptorSetLayout GetSingleTypeDescritorSetLayout( VkDescriptorType type, const uint32_t size); VkDescriptorSet GetSingleTypeDescritorSet( VkDescriptorType type, VkDescriptorSetLayout layout, const std::vector& texturesUID, const std::vector& textures); uint32_t GetUniformSet() const; uint32_t GetTextureDescriptor(CTexture* texture); void OnTextureDestroy(const CTexture::UID uid); const VkDescriptorSetLayout& GetDescriptorIndexingSetLayout() const { return m_DescriptorIndexingSetLayout; } const VkDescriptorSetLayout& GetUniformDescriptorSetLayout() const { return m_UniformDescriptorSetLayout; } const VkDescriptorSet& GetDescriptorIndexingSet() { return m_DescriptorIndexingSet; } const std::vector& GetDescriptorSetLayouts() const { return m_DescriptorSetLayouts; } private: struct SingleTypePool { 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); CDevice* m_Device = nullptr; bool m_UseDescriptorIndexing = false; VkDescriptorPool m_DescriptorIndexingPool = VK_NULL_HANDLE; VkDescriptorSet m_DescriptorIndexingSet = VK_NULL_HANDLE; VkDescriptorSetLayout m_DescriptorIndexingSetLayout = VK_NULL_HANDLE; VkDescriptorSetLayout m_UniformDescriptorSetLayout = VK_NULL_HANDLE; std::vector m_DescriptorSetLayouts; static constexpr uint32_t DESCRIPTOR_INDEXING_BINDING_SIZE = 16384; static constexpr uint32_t NUMBER_OF_BINDINGS_PER_DESCRIPTOR_INDEXING_SET = 3; struct DescriptorIndexingBindingMap { static_assert(std::numeric_limits::max() >= DESCRIPTOR_INDEXING_BINDING_SIZE); int16_t firstFreeIndex = 0; std::vector elements; std::unordered_map map; }; std::array m_DescriptorIndexingBindings; 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 { size_t operator()(const SingleTypeCacheKey& key) const; }; std::unordered_map m_SingleTypeSets; + + std::unique_ptr m_ErrorTexture; }; } // namespace Vulkan } // namespace Backend } // namespace Renderer #endif // INCLUDED_RENDERER_BACKEND_VULKAN_DESCRIPTORMANAGER Index: ps/trunk/source/renderer/backend/vulkan/Texture.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Texture.h (revision 27510) +++ ps/trunk/source/renderer/backend/vulkan/Texture.h (revision 27511) @@ -1,132 +1,133 @@ /* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_RENDERER_BACKEND_VULKAN_TEXTURE #define INCLUDED_RENDERER_BACKEND_VULKAN_TEXTURE #include "renderer/backend/ITexture.h" #include "renderer/backend/Sampler.h" #include "renderer/backend/vulkan/VMA.h" #include #include namespace Renderer { namespace Backend { namespace Vulkan { class CDevice; class CTexture final : public ITexture { public: ~CTexture() override; IDevice* GetDevice() override; Type GetType() const override { return m_Type; } uint32_t GetUsage() const override { return m_Usage; } Format GetFormat() const override { return m_Format; } uint32_t GetWidth() const override { return m_Width; } uint32_t GetHeight() const override { return m_Height; } uint32_t GetMIPLevelCount() const override { return m_MIPLevelCount; } uint32_t GetSampleCount() const { return m_SampleCount; } uint32_t GetLayerCount() const { return m_LayerCount; } VkImage GetImage() { return m_Image; } VkImageView GetAttachmentImageView() { return m_AttachmentImageView; } VkImageView GetSamplerImageView() { return m_SamplerImageView; } VkSampler GetSampler() { return m_Sampler; } bool IsCompareEnabled() { return m_IsCompareEnabled; } VkFormat GetVkFormat() const { return m_VkFormat; } VkImageAspectFlags GetAttachmentImageAspectMask() { return m_AttachmentImageAspectMask; } VkImageAspectFlags GetSamplerImageAspectMask() { return m_SamplerImageAspectMask; } bool IsInitialized() const { return m_Initialized; } void SetInitialized() { m_Initialized = true; } /** * @return UID of the texture. It's unique along all textures during a whole * application run. We assume that 32bits should be enough, else we'd have * a too big texture flow. */ using UID = uint32_t; + static constexpr UID INVALID_UID = 0; UID GetUID() const { return m_UID; } private: friend class CDevice; friend class CSwapChain; CTexture(); static std::unique_ptr Create( CDevice* device, const char* name, const Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount); static std::unique_ptr WrapBackbufferImage( CDevice* device, const char* name, const VkImage image, const VkFormat format, const VkImageUsageFlags usage, const uint32_t width, const uint32_t height); Type m_Type = Type::TEXTURE_2D; uint32_t m_Usage = 0; Format m_Format = Format::UNDEFINED; VkFormat m_VkFormat = VK_FORMAT_UNDEFINED; uint32_t m_Width = 0; uint32_t m_Height = 0; uint32_t m_MIPLevelCount = 0; uint32_t m_SampleCount = 0; uint32_t m_LayerCount = 0; CDevice* m_Device = nullptr; VkImage m_Image = VK_NULL_HANDLE; VkImageView m_AttachmentImageView = VK_NULL_HANDLE; VkImageView m_SamplerImageView = VK_NULL_HANDLE; VkSampler m_Sampler = VK_NULL_HANDLE; bool m_IsCompareEnabled = false; VmaAllocation m_Allocation{}; UID m_UID = 0; // Sampler image aspect mask is submask of the attachment one. As we can't // have both VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT for // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. VkImageAspectFlags m_AttachmentImageAspectMask = 0; VkImageAspectFlags m_SamplerImageAspectMask = 0; // We store a flag of all subresources, we don't have to handle them separately. // It's safe to store the current state while we use a single device command // context. bool m_Initialized = false; }; } // namespace Vulkan } // namespace Backend } // namespace Renderer #endif // INCLUDED_RENDERER_BACKEND_VULKAN_TEXTURE