From 6ef27d2ffef3182b1813ef103380713a695deca8 Mon Sep 17 00:00:00 2001 From: vladislavbelov Date: Mon, 9 Oct 2023 18:34:50 +0000 Subject: [PATCH] Merges UID from different Vulkan device objects and unifies single type descriptor set creation. Differential Revision: https://code.wildfiregames.com/D5140 This was SVN commit r27879. --- .../backend/vulkan/DescriptorManager.cpp | 105 ++++++++++-------- .../backend/vulkan/DescriptorManager.h | 17 ++- source/renderer/backend/vulkan/Device.cpp | 8 +- source/renderer/backend/vulkan/Device.h | 8 +- .../renderer/backend/vulkan/DeviceObjectUID.h | 49 ++++++++ .../renderer/backend/vulkan/Framebuffer.cpp | 1 + source/renderer/backend/vulkan/Framebuffer.h | 12 +- .../renderer/backend/vulkan/PipelineState.cpp | 1 + .../renderer/backend/vulkan/PipelineState.h | 16 +-- .../renderer/backend/vulkan/ShaderProgram.cpp | 2 +- .../renderer/backend/vulkan/ShaderProgram.h | 2 +- source/renderer/backend/vulkan/Texture.cpp | 14 +-- source/renderer/backend/vulkan/Texture.h | 14 +-- 13 files changed, 155 insertions(+), 94 deletions(-) create mode 100644 source/renderer/backend/vulkan/DeviceObjectUID.h diff --git a/source/renderer/backend/vulkan/DescriptorManager.cpp b/source/renderer/backend/vulkan/DescriptorManager.cpp index 16f69a7f6c..5b80af8f31 100644 --- a/source/renderer/backend/vulkan/DescriptorManager.cpp +++ b/source/renderer/backend/vulkan/DescriptorManager.cpp @@ -212,23 +212,21 @@ size_t CDescriptorManager::SingleTypeCacheKeyHash::operator()(const SingleTypeCa { 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,43 +250,58 @@ VkDescriptorSet CDescriptorManager::GetSingleTypeDescritorSet( 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())}); - - 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); - - 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)); - } - - 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); + 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; } +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); + + 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); + + VkDescriptorImageInfo descriptorImageInfo{}; + descriptorImageInfo.imageLayout = imageLayout; + 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 = 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 { return m_UseDescriptorIndexing ? 1 : 0; @@ -341,9 +354,9 @@ uint32_t CDescriptorManager::GetTextureDescriptor(CTexture* texture) 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 @@ void CDescriptorManager::OnTextureDestroy(const CTexture::UID uid) } 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 @@ void CDescriptorManager::OnTextureDestroy(const CTexture::UID uid) pool.firstFreeIndex = entry.elementIndex; } } - m_TextureSingleTypePoolMap.erase(it); + m_UIDToSingleTypePoolMap.erase(it); } } diff --git a/source/renderer/backend/vulkan/DescriptorManager.h b/source/renderer/backend/vulkan/DescriptorManager.h index 8291f49998..0b94ef622c 100644 --- a/source/renderer/backend/vulkan/DescriptorManager.h +++ b/source/renderer/backend/vulkan/DescriptorManager.h @@ -56,13 +56,14 @@ public: 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 @@ private: }; 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 @@ private: 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 @@ private: 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; diff --git a/source/renderer/backend/vulkan/Device.cpp b/source/renderer/backend/vulkan/Device.cpp index d94ffbd0da..753953545c 100644 --- a/source/renderer/backend/vulkan/Device.cpp +++ b/source/renderer/backend/vulkan/Device.cpp @@ -911,7 +911,7 @@ void CDevice::ScheduleObjectToDestroy( 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 @@ CTexture* CDevice::GetOrCreateBackbufferReadbackTexture() 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); diff --git a/source/renderer/backend/vulkan/Device.h b/source/renderer/backend/vulkan/Device.h index 2fd49f7a70..41234c59b3 100644 --- a/source/renderer/backend/vulkan/Device.h +++ b/source/renderer/backend/vulkan/Device.h @@ -140,7 +140,7 @@ public: 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 @@ public: CTexture* GetOrCreateBackbufferReadbackTexture(); + DeviceObjectUID GenerateNextDeviceObjectUID(); + private: CDevice(); @@ -210,12 +212,14 @@ private: 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 diff --git a/source/renderer/backend/vulkan/DeviceObjectUID.h b/source/renderer/backend/vulkan/DeviceObjectUID.h new file mode 100644 index 0000000000..c792c4bafd --- /dev/null +++ b/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 diff --git a/source/renderer/backend/vulkan/Framebuffer.cpp b/source/renderer/backend/vulkan/Framebuffer.cpp index 63d04c66c3..ce9604d85b 100644 --- a/source/renderer/backend/vulkan/Framebuffer.cpp +++ b/source/renderer/backend/vulkan/Framebuffer.cpp @@ -57,6 +57,7 @@ std::unique_ptr CFramebuffer::Create( std::unique_ptr framebuffer(new CFramebuffer()); framebuffer->m_Device = device; + framebuffer->m_UID = device->GenerateNextDeviceObjectUID(); if (colorAttachment) framebuffer->m_ClearColor = colorAttachment->clearColor; diff --git a/source/renderer/backend/vulkan/Framebuffer.h b/source/renderer/backend/vulkan/Framebuffer.h index a12099c606..e5dd26e79c 100644 --- a/source/renderer/backend/vulkan/Framebuffer.h +++ b/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 @@ public: 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 @@ private: 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{}; diff --git a/source/renderer/backend/vulkan/PipelineState.cpp b/source/renderer/backend/vulkan/PipelineState.cpp index 749244024b..cafd7128ce 100644 --- a/source/renderer/backend/vulkan/PipelineState.cpp +++ b/source/renderer/backend/vulkan/PipelineState.cpp @@ -76,6 +76,7 @@ std::unique_ptr CGraphicsPipelineState::Create( ENSURE(desc.shaderProgram); std::unique_ptr pipelineState{new CGraphicsPipelineState()}; pipelineState->m_Device = device; + pipelineState->m_UID = device->GenerateNextDeviceObjectUID(); pipelineState->m_Desc = desc; return pipelineState; } diff --git a/source/renderer/backend/vulkan/PipelineState.h b/source/renderer/backend/vulkan/PipelineState.h index 17c997c52e..2e6a76f9dc 100644 --- a/source/renderer/backend/vulkan/PipelineState.h +++ b/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 @@ public: 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 @@ private: 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 { diff --git a/source/renderer/backend/vulkan/ShaderProgram.cpp b/source/renderer/backend/vulkan/ShaderProgram.cpp index be82822985..399cb4c2ce 100644 --- a/source/renderer/backend/vulkan/ShaderProgram.cpp +++ b/source/renderer/backend/vulkan/ShaderProgram.cpp @@ -552,7 +552,7 @@ void CShaderProgram::Unbind() { for (CTexture*& texture : m_BoundTextures) texture = nullptr; - for (CTexture::UID& uid : m_BoundTexturesUID) + for (DeviceObjectUID& uid : m_BoundTexturesUID) uid = 0; m_BoundTexturesOutdated = true; } diff --git a/source/renderer/backend/vulkan/ShaderProgram.h b/source/renderer/backend/vulkan/ShaderProgram.h index 9791b4e763..d623f50f59 100644 --- a/source/renderer/backend/vulkan/ShaderProgram.h +++ b/source/renderer/backend/vulkan/ShaderProgram.h @@ -171,7 +171,7 @@ private: 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; diff --git a/source/renderer/backend/vulkan/Texture.cpp b/source/renderer/backend/vulkan/Texture.cpp index e09d06a0df..6666f8ab3e 100644 --- a/source/renderer/backend/vulkan/Texture.cpp +++ b/source/renderer/backend/vulkan/Texture.cpp @@ -40,8 +40,7 @@ std::unique_ptr CTexture::Create( 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 @@ std::unique_ptr CTexture::WrapBackbufferImage( 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 @@ std::unique_ptr CTexture::CreateReadback( 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 @@ std::unique_ptr CTexture::CreateReadback( 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() diff --git a/source/renderer/backend/vulkan/Texture.h b/source/renderer/backend/vulkan/Texture.h index 121fb3c5ee..aaf425ded7 100644 --- a/source/renderer/backend/vulkan/Texture.h +++ b/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 @@ public: 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 @@ private: 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