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 @@ -56,13 +56,14 @@ VkDescriptorSet GetSingleTypeDescritorSet( VkDescriptorType type, VkDescriptorSetLayout layout, - const std::vector& texturesUID, + const std::vector& texturesUID, const std::vector& textures); uint32_t GetUniformSet() const; uint32_t GetTextureDescriptor(CTexture* texture); - void OnTextureDestroy(const CTexture::UID uid); + + void OnTextureDestroy(const DeviceObjectUID uid); const VkDescriptorSetLayout& GetDescriptorIndexingSetLayout() const { return m_DescriptorIndexingSetLayout; } const VkDescriptorSetLayout& GetUniformDescriptorSetLayout() const { return m_UniformDescriptorSetLayout; } @@ -87,6 +88,10 @@ }; SingleTypePool& GetSingleTypePool(const VkDescriptorType type, const uint32_t size); + VkDescriptorSet GetSingleTypeDescritorSetImpl( + VkDescriptorType type, VkDescriptorSetLayout layout, + const std::vector& uids); + CDevice* m_Device = nullptr; bool m_UseDescriptorIndexing = false; @@ -105,11 +110,11 @@ static_assert(std::numeric_limits::max() >= DESCRIPTOR_INDEXING_BINDING_SIZE); int16_t firstFreeIndex = 0; std::vector elements; - std::unordered_map map; + std::unordered_map map; }; std::array m_DescriptorIndexingBindings; - std::unordered_map m_TextureToBindingMap; + std::unordered_map m_TextureToBindingMap; std::unordered_map> m_SingleTypePools; struct SingleTypePoolReference @@ -119,9 +124,9 @@ int16_t elementIndex = SingleTypePool::INVALID_INDEX; uint8_t size = 0; }; - std::unordered_map> m_TextureSingleTypePoolMap; + std::unordered_map> m_UIDToSingleTypePoolMap; - using SingleTypeCacheKey = std::pair>; + using SingleTypeCacheKey = std::pair>; struct SingleTypeCacheKeyHash { size_t operator()(const SingleTypeCacheKey& key) const; 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 @@ -212,23 +212,21 @@ { size_t seed = 0; hash_combine(seed, key.first); - for (CTexture::UID uid : key.second) + for (DeviceObjectUID uid : key.second) hash_combine(seed, uid); return seed; } -VkDescriptorSet CDescriptorManager::GetSingleTypeDescritorSet( +VkDescriptorSet CDescriptorManager::GetSingleTypeDescritorSetImpl( VkDescriptorType type, VkDescriptorSetLayout layout, - const std::vector& texturesUID, - const std::vector& textures) + const std::vector& uids) { - ENSURE(texturesUID.size() == textures.size()); - ENSURE(!texturesUID.empty()); - const SingleTypeCacheKey key{layout, texturesUID}; + ENSURE(!uids.empty()); + const SingleTypeCacheKey key{layout, uids}; auto it = m_SingleTypeSets.find(key); if (it == m_SingleTypeSets.end()) { - SingleTypePool& pool = GetSingleTypePool(type, texturesUID.size()); + SingleTypePool& pool = GetSingleTypePool(type, uids.size()); const int16_t elementIndex = pool.firstFreeIndex; ENSURE(elementIndex != SingleTypePool::INVALID_INDEX); SingleTypePool::Element& element = pool.elements[elementIndex]; @@ -252,41 +250,56 @@ it = m_SingleTypeSets.emplace(key, element.set).first; - for (const CTexture::UID uid : texturesUID) - if (uid != CTexture::INVALID_UID) - m_TextureSingleTypePoolMap[uid].push_back({type, element.version, elementIndex, static_cast(texturesUID.size())}); + for (const DeviceObjectUID uid : uids) + if (uid != INVALID_DEVICE_OBJECT_UID) + m_UIDToSingleTypePoolMap[uid].push_back({type, element.version, elementIndex, static_cast(uids.size())}); + } + return it->second; +} - PS::StaticVector infos; - for (CTexture* texture : textures) - { - if (!texture) - { - // We can use a default texture only for read-only bindings. - ENSURE(type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - texture = m_ErrorTexture->As(); - } - ENSURE(texture->GetUsage() & ITexture::Usage::SAMPLED); +VkDescriptorSet CDescriptorManager::GetSingleTypeDescritorSet( + VkDescriptorType type, VkDescriptorSetLayout layout, + const std::vector& texturesUID, + const std::vector& textures) +{ + ENSURE(texturesUID.size() == textures.size()); + ENSURE(!texturesUID.empty()); + VkDescriptorSet set = GetSingleTypeDescritorSetImpl(type, layout, texturesUID); - VkDescriptorImageInfo descriptorImageInfo{}; - descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - descriptorImageInfo.imageView = texture->GetSamplerImageView(); - descriptorImageInfo.sampler = texture->GetSampler(); - infos.emplace_back(std::move(descriptorImageInfo)); + const VkImageLayout imageLayout = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE + ? VK_IMAGE_LAYOUT_GENERAL + : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + PS::StaticVector infos; + for (CTexture* texture : textures) + { + if (!texture) + { + // We can use a default texture only for read-only bindings. + ENSURE(type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + texture = m_ErrorTexture->As(); } + ENSURE(texture->GetUsage() & ITexture::Usage::SAMPLED); - 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(), 1, &writeDescriptorSet, 0, nullptr); + VkDescriptorImageInfo descriptorImageInfo{}; + descriptorImageInfo.imageLayout = imageLayout; + descriptorImageInfo.imageView = texture->GetSamplerImageView(); + descriptorImageInfo.sampler = texture->GetSampler(); + infos.emplace_back(std::move(descriptorImageInfo)); } - return it->second; + + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.dstSet = set; + writeDescriptorSet.dstBinding = 0; + writeDescriptorSet.dstArrayElement = 0; + writeDescriptorSet.descriptorType = type; + writeDescriptorSet.descriptorCount = static_cast(infos.size()); + writeDescriptorSet.pImageInfo = infos.data(); + + vkUpdateDescriptorSets( + m_Device->GetVkDevice(), 1, &writeDescriptorSet, 0, nullptr); + + return set; } uint32_t CDescriptorManager::GetUniformSet() const @@ -341,9 +354,9 @@ return descriptorSetIndex; } -void CDescriptorManager::OnTextureDestroy(const CTexture::UID uid) +void CDescriptorManager::OnTextureDestroy(const DeviceObjectUID uid) { - ENSURE(uid != CTexture::INVALID_UID); + ENSURE(uid != INVALID_DEVICE_OBJECT_UID); if (m_UseDescriptorIndexing) { DescriptorIndexingBindingMap& bindingMap = @@ -360,8 +373,8 @@ } else { - auto it = m_TextureSingleTypePoolMap.find(uid); - if (it == m_TextureSingleTypePoolMap.end()) + auto it = m_UIDToSingleTypePoolMap.find(uid); + if (it == m_UIDToSingleTypePoolMap.end()) return; for (const auto& entry : it->second) { @@ -376,7 +389,7 @@ pool.firstFreeIndex = entry.elementIndex; } } - m_TextureSingleTypePoolMap.erase(it); + m_UIDToSingleTypePoolMap.erase(it); } } Index: ps/trunk/source/renderer/backend/vulkan/Device.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Device.h +++ ps/trunk/source/renderer/backend/vulkan/Device.h @@ -140,7 +140,7 @@ void ScheduleObjectToDestroy( VkObjectType type, const uint64_t handle, const VmaAllocation allocation); - void ScheduleTextureToDestroy(const CTexture::UID uid); + void ScheduleTextureToDestroy(const DeviceObjectUID uid); void SetObjectName(VkObjectType type, const void* handle, const char* name) { @@ -163,6 +163,8 @@ CTexture* GetOrCreateBackbufferReadbackTexture(); + DeviceObjectUID GenerateNextDeviceObjectUID(); + private: CDevice(); @@ -210,12 +212,14 @@ VmaAllocation allocation; }; std::queue m_ObjectToDestroyQueue; - std::queue> m_TextureToDestroyQueue; + std::queue> m_TextureToDestroyQueue; std::unique_ptr m_RenderPassManager; std::unique_ptr m_SamplerManager; std::unique_ptr m_DescriptorManager; std::unique_ptr m_SubmitScheduler; + + DeviceObjectUID m_LastAvailableUID{1}; }; } // namespace Vulkan Index: ps/trunk/source/renderer/backend/vulkan/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Device.cpp +++ ps/trunk/source/renderer/backend/vulkan/Device.cpp @@ -911,7 +911,7 @@ m_ObjectToDestroyQueue.push({m_FrameID, type, handle, allocation}); } -void CDevice::ScheduleTextureToDestroy(const CTexture::UID uid) +void CDevice::ScheduleTextureToDestroy(const DeviceObjectUID uid) { m_TextureToDestroyQueue.push({m_FrameID, uid}); } @@ -1029,6 +1029,12 @@ return m_BackbufferReadbackTexture.get(); } +DeviceObjectUID CDevice::GenerateNextDeviceObjectUID() +{ + ENSURE(m_LastAvailableUID < std::numeric_limits::max()); + return m_LastAvailableUID++; +} + std::unique_ptr CreateDevice(SDL_Window* window) { return Vulkan::CDevice::Create(window); Index: ps/trunk/source/renderer/backend/vulkan/DeviceObjectUID.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/DeviceObjectUID.h +++ ps/trunk/source/renderer/backend/vulkan/DeviceObjectUID.h @@ -0,0 +1,49 @@ +/* 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_UID +#define INCLUDED_RENDERER_BACKEND_VULKAN_UID + +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace Vulkan +{ + +/** + * Unique identifier for a device object. It must be unique along all objects + * during a whole application run. We assume that 32bits should be enough, else + * we'd have a too big object flow. + * TODO: maybe it makes sense to add it for all backends. Also it might make + * sense to add categories/types. Several high bits might be for describing an + * object type, low bits for indexing. + */ +using DeviceObjectUID = uint32_t; +static constexpr DeviceObjectUID INVALID_DEVICE_OBJECT_UID = 0; + +} // namespace Vulkan + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_VULKAN_UID Index: ps/trunk/source/renderer/backend/vulkan/Framebuffer.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Framebuffer.h +++ ps/trunk/source/renderer/backend/vulkan/Framebuffer.h @@ -20,6 +20,7 @@ #include "ps/containers/StaticVector.h" #include "renderer/backend/IFramebuffer.h" +#include "renderer/backend/vulkan/DeviceObjectUID.h" #include #include @@ -61,8 +62,7 @@ AttachmentLoadOp GetDepthStencilAttachmentLoadOp() const { return m_DepthStencilAttachmentLoadOp; } AttachmentStoreOp GetDepthStencilAttachmentStoreOp() const { return m_DepthStencilAttachmentStoreOp; } - using UID = uint32_t; - UID GetUID() const { return m_UID; } + DeviceObjectUID GetUID() const { return m_UID; } private: friend class CDevice; @@ -72,15 +72,11 @@ CDevice* device, const char* name, SColorAttachment* colorAttachment, SDepthStencilAttachment* depthStencilAttachment); - CFramebuffer() - { - static uint32_t m_LastAvailableUID = 1; - m_UID = m_LastAvailableUID++; - } + CFramebuffer() = default; CDevice* m_Device = nullptr; - UID m_UID = 0; + DeviceObjectUID m_UID{INVALID_DEVICE_OBJECT_UID}; CColor m_ClearColor{}; Index: ps/trunk/source/renderer/backend/vulkan/Framebuffer.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Framebuffer.cpp +++ ps/trunk/source/renderer/backend/vulkan/Framebuffer.cpp @@ -57,6 +57,7 @@ std::unique_ptr framebuffer(new CFramebuffer()); framebuffer->m_Device = device; + framebuffer->m_UID = device->GenerateNextDeviceObjectUID(); if (colorAttachment) framebuffer->m_ClearColor = colorAttachment->clearColor; Index: ps/trunk/source/renderer/backend/vulkan/PipelineState.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/PipelineState.h +++ ps/trunk/source/renderer/backend/vulkan/PipelineState.h @@ -21,6 +21,7 @@ #include "renderer/backend/PipelineState.h" #include "renderer/backend/vulkan/Framebuffer.h" #include "renderer/backend/vulkan/ShaderProgram.h" +#include "renderer/backend/vulkan/DeviceObjectUID.h" #include #include @@ -53,8 +54,7 @@ VkPipeline GetOrCreatePipeline( const CVertexInputLayout* vertexInputLayout, CFramebuffer* framebuffer); - using UID = uint32_t; - UID GetUID() const { return m_UID; } + DeviceObjectUID GetUID() const { return m_UID; } private: friend class CDevice; @@ -62,23 +62,19 @@ static std::unique_ptr Create( CDevice* device, const SGraphicsPipelineStateDesc& desc); - CGraphicsPipelineState() - { - static uint32_t m_LastAvailableUID = 1; - m_UID = m_LastAvailableUID++; - } + CGraphicsPipelineState() = default; CDevice* m_Device = nullptr; - UID m_UID = 0; + DeviceObjectUID m_UID{INVALID_DEVICE_OBJECT_UID}; SGraphicsPipelineStateDesc m_Desc{}; struct CacheKey { - CVertexInputLayout::UID vertexInputLayoutUID; + DeviceObjectUID vertexInputLayoutUID; // TODO: try to replace the UID by the only required parameters. - CFramebuffer::UID framebufferUID; + DeviceObjectUID framebufferUID; }; struct CacheKeyHash { Index: ps/trunk/source/renderer/backend/vulkan/PipelineState.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/PipelineState.cpp +++ ps/trunk/source/renderer/backend/vulkan/PipelineState.cpp @@ -76,6 +76,7 @@ ENSURE(desc.shaderProgram); std::unique_ptr pipelineState{new CGraphicsPipelineState()}; pipelineState->m_Device = device; + pipelineState->m_UID = device->GenerateNextDeviceObjectUID(); pipelineState->m_Desc = desc; return pipelineState; } Index: ps/trunk/source/renderer/backend/vulkan/ShaderProgram.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/ShaderProgram.h +++ ps/trunk/source/renderer/backend/vulkan/ShaderProgram.h @@ -171,7 +171,7 @@ VkDescriptorSetLayout m_TexturesDescriptorSetLayout = VK_NULL_HANDLE; std::vector m_BoundTextures; - std::vector m_BoundTexturesUID; + std::vector m_BoundTexturesUID; VkDescriptorSet m_ActiveTexturesDescriptorSet = VK_NULL_HANDLE; std::unordered_map m_TextureMapping; Index: ps/trunk/source/renderer/backend/vulkan/ShaderProgram.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/ShaderProgram.cpp +++ ps/trunk/source/renderer/backend/vulkan/ShaderProgram.cpp @@ -552,7 +552,7 @@ { for (CTexture*& texture : m_BoundTextures) texture = nullptr; - for (CTexture::UID& uid : m_BoundTexturesUID) + for (DeviceObjectUID& uid : m_BoundTexturesUID) uid = 0; m_BoundTexturesOutdated = true; } 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 @@ -20,6 +20,7 @@ #include "renderer/backend/ITexture.h" #include "renderer/backend/Sampler.h" +#include "renderer/backend/vulkan/DeviceObjectUID.h" #include "renderer/backend/vulkan/VMA.h" #include @@ -73,20 +74,13 @@ 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; } + DeviceObjectUID GetUID() const { return m_UID; } private: friend class CDevice; friend class CSwapChain; - CTexture(); + CTexture(CDevice* device); static std::unique_ptr Create( CDevice* device, const char* name, const Type type, const uint32_t usage, @@ -122,7 +116,7 @@ VmaAllocation m_Allocation{}; VmaAllocationInfo m_AllocationInfo{}; - UID m_UID = 0; + DeviceObjectUID m_UID{INVALID_DEVICE_OBJECT_UID}; // 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 Index: ps/trunk/source/renderer/backend/vulkan/Texture.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Texture.cpp +++ ps/trunk/source/renderer/backend/vulkan/Texture.cpp @@ -40,8 +40,7 @@ const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) { - std::unique_ptr texture(new CTexture()); - texture->m_Device = device; + std::unique_ptr texture(new CTexture(device)); texture->m_Format = format; texture->m_Type = type; @@ -225,8 +224,7 @@ CDevice* device, const char* name, const VkImage image, const VkFormat format, const VkImageUsageFlags usage, const uint32_t width, const uint32_t height) { - std::unique_ptr texture(new CTexture()); - texture->m_Device = device; + std::unique_ptr texture(new CTexture(device)); if (format == VK_FORMAT_R8G8B8A8_UNORM) texture->m_Format = Format::R8G8B8A8_UNORM; @@ -279,8 +277,7 @@ CDevice* device, const char* name, const Format format, const uint32_t width, const uint32_t height) { - std::unique_ptr texture(new CTexture()); - texture->m_Device = device; + std::unique_ptr texture(new CTexture(device)); texture->m_Format = format; texture->m_Type = Type::TEXTURE_2D; @@ -338,10 +335,9 @@ return texture; } -CTexture::CTexture() +CTexture::CTexture(CDevice* device) + : m_Device(device), m_UID(device->GenerateNextDeviceObjectUID()) { - static uint32_t m_LastAvailableUID = 1; - m_UID = m_LastAvailableUID++; } CTexture::~CTexture()