diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2018-04-16 03:20:02 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2018-04-16 03:20:02 +0000 |
| commit | 0400f81cac9540a460a57595b28c9e403124c727 (patch) | |
| tree | 3336489453635051aa2a8ae80419f0d3ba61d86e /Graphics/GraphicsEngineVulkan | |
| parent | Implemented vulkan swap chain resize (diff) | |
| download | DiligentCore-0400f81cac9540a460a57595b28c9e403124c727.tar.gz DiligentCore-0400f81cac9540a460a57595b28c9e403124c727.zip | |
Added vulkan framebuffer cache
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
7 files changed, 246 insertions, 2 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 63a4d1ec..1da9c203 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -13,6 +13,7 @@ set(INCLUDE include/DescriptorHeap.h include/DeviceContextVkImpl.h include/DynamicUploadHeap.h + include/FramebufferCache.h include/GenerateMips.h include/pch.h include/PipelineStateVkImpl.h @@ -68,6 +69,7 @@ set(SRC src/DescriptorHeap.cpp src/DeviceContextVkImpl.cpp src/DynamicUploadHeap.cpp + src/FramebufferCache.cpp src/GenerateMips.cpp src/PipelineStateVkImpl.cpp src/RenderDeviceVkImpl.cpp diff --git a/Graphics/GraphicsEngineVulkan/include/FramebufferCache.h b/Graphics/GraphicsEngineVulkan/include/FramebufferCache.h new file mode 100644 index 00000000..db9861da --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/FramebufferCache.h @@ -0,0 +1,88 @@ +/* Copyright 2015-2018 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::FramebufferCache class + +#include <unordered_map> +#include <mutex> +#include "VulkanUtilities/VulkanObjectWrappers.h" + +namespace Diligent +{ + +class RenderDeviceVkImpl; +class FramebufferCache +{ +public: + FramebufferCache(RenderDeviceVkImpl& DeviceVKImpl) : + m_DeviceVk(DeviceVKImpl) + {} + + FramebufferCache(const FramebufferCache&) = delete; + FramebufferCache(FramebufferCache&&) = delete; + FramebufferCache& operator = (const FramebufferCache&) = delete; + FramebufferCache& operator = (FramebufferCache&&) = delete; + + ~FramebufferCache(); + + // This structure is used as the key to find framebuffer + struct FramebufferCacheKey + { + // Default memeber initialization is intentionally omitted + VkRenderPass Pass; + Uint32 NumRenderTargets; + VkImageView DSV; + VkImageView RTVs[MaxRenderTargets]; + bool operator == (const FramebufferCacheKey &rhs)const; + size_t GetHash()const; + + private: + mutable size_t Hash = 0; + }; + + VkFramebuffer GetFramebuffer(const FramebufferCacheKey& Key, uint32_t width, uint32_t height, uint32_t layers); + void OnDestroyImageView(VkImageView ImgView); + void OnDestroyRenderPass(VkRenderPass Pass); + +private: + + RenderDeviceVkImpl& m_DeviceVk; + + struct FramebufferCacheKeyHash + { + std::size_t operator() (const FramebufferCacheKey& Key)const + { + return Key.GetHash(); + } + }; + + std::mutex m_Mutex; + std::unordered_map<FramebufferCacheKey, VulkanUtilities::FramebufferWrapper, FramebufferCacheKeyHash> m_Cache; + std::unordered_multimap<VkImageView, FramebufferCacheKey> m_ViewToKeyMap; + std::unordered_multimap<VkRenderPass, FramebufferCacheKey> m_RenderPassToKeyMap; +}; + +} diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h index 98275f24..471ed78c 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h @@ -39,6 +39,7 @@ #include "VulkanUtilities/VulkanCommandBufferPool.h" #include "VulkanUtilities/VulkanLogicalDevice.h" #include "VulkanUtilities/VulkanObjectWrappers.h" +#include "FramebufferCache.h" /// Namespace for the Direct3D11 implementation of the graphics engine namespace Diligent @@ -115,6 +116,7 @@ public: std::shared_ptr<const VulkanUtilities::VulkanInstance> GetVulkanInstance()const{return m_VulkanInstance;} const VulkanUtilities::VulkanPhysicalDevice &GetPhysicalDevice(){return *m_PhysicalDevice;} const auto &GetLogicalDevice(){return *m_LogicalVkDevice;} + FramebufferCache& GetFramebufferCache(){return m_FramebufferCache;} private: virtual void TestTextureFormat( TEXTURE_FORMAT TexFormat )override final; @@ -193,7 +195,7 @@ private: std::mutex m_StaleObjectsMutex; std::deque< ReleaseQueueElemType, STDAllocatorRawMem<ReleaseQueueElemType> > m_StaleVkObjects; - + FramebufferCache m_FramebufferCache; #if 0 std::mutex m_UploadHeapMutex; typedef std::unique_ptr<DynamicUploadHeap, STDDeleterRawMem<DynamicUploadHeap> > UploadHeapPoolElemType; diff --git a/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp b/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp new file mode 100644 index 00000000..d34564c3 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp @@ -0,0 +1,148 @@ +/* Copyright 2015-2018 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "FramebufferCache.h" +#include "HashUtils.h" +#include "RenderDeviceVkImpl.h" + +namespace Diligent +{ + + +bool FramebufferCache::FramebufferCacheKey::operator == (const FramebufferCacheKey &rhs)const +{ + if (GetHash() != rhs.GetHash() || + Pass != rhs.Pass || + NumRenderTargets != rhs.NumRenderTargets || + DSV != rhs.DSV) + { + return false; + } + + for (Uint32 rt = 0; rt < NumRenderTargets; ++rt) + if (RTVs[rt] != rhs.RTVs[rt]) + return false; + + return true; +} + +size_t FramebufferCache::FramebufferCacheKey::GetHash()const +{ + if(Hash == 0) + { + Hash = ComputeHash(Pass, NumRenderTargets, DSV); + for(Uint32 rt = 0; rt < NumRenderTargets; ++rt) + HashCombine(Hash, RTVs[rt]); + } + return Hash; +} + +VkFramebuffer FramebufferCache::GetFramebuffer(const FramebufferCacheKey& Key, uint32_t width, uint32_t height, uint32_t layers) +{ + std::lock_guard<std::mutex> Lock(m_Mutex); + auto it = m_Cache.find(Key); + if(it != m_Cache.end()) + { + return it->second; + } + else + { + VkFramebufferCreateInfo FramebufferCI = {}; + FramebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + FramebufferCI.pNext = nullptr; + FramebufferCI.flags = 0; // reserved for future use + FramebufferCI.renderPass = Key.Pass; + FramebufferCI.attachmentCount = (Key.DSV != VK_NULL_HANDLE ? 1 : 0) + Key.NumRenderTargets; + VkImageView Attachments[1 + MaxRenderTargets]; + uint32_t attachment = 0; + if(Key.DSV != VK_NULL_HANDLE) + Attachments[attachment++] = Key.DSV; + for(Uint32 rt=0; rt < Key.NumRenderTargets; ++rt) + Attachments[attachment++] = Key.RTVs[rt]; + VERIFY_EXPR(attachment == FramebufferCI.attachmentCount); + FramebufferCI.pAttachments = Attachments; + FramebufferCI.width = width; + FramebufferCI.height = height; + FramebufferCI.layers = layers; + auto Framebuffer = m_DeviceVk.GetLogicalDevice().CreateFramebuffer(FramebufferCI); + VkFramebuffer fb = Framebuffer; + + auto new_it = m_Cache.insert(std::make_pair(Key, std::move(Framebuffer))); + VERIFY(new_it.second, "New framebuffer must be inserted into the map"); + + m_RenderPassToKeyMap.emplace(Key.Pass, Key); + if(Key.DSV != VK_NULL_HANDLE) + m_ViewToKeyMap.emplace(Key.DSV, Key); + for(Uint32 rt=0; rt < Key.NumRenderTargets; ++rt) + if(Key.RTVs[rt] != VK_NULL_HANDLE) + m_ViewToKeyMap.emplace(Key.RTVs[rt], Key); + + return fb; + } +} + +FramebufferCache::~FramebufferCache() +{ + VERIFY(m_Cache.empty(), "All framebuffers must be released"); + VERIFY(m_ViewToKeyMap.empty(), "All image views must be released and the cache must be notified"); + VERIFY(m_RenderPassToKeyMap.empty(), "All render passes must be released and the cache must be notified"); +} + +void FramebufferCache::OnDestroyImageView(VkImageView ImgView) +{ + std::lock_guard<std::mutex> Lock(m_Mutex); + auto equal_range = m_ViewToKeyMap.equal_range(ImgView); + for(auto it = equal_range.first; it != equal_range.second; ++it) + { + auto fb_it = m_Cache.find(it->second); + // Multiple image views may be associated with the same key. + // The framebuffer is deleted whenever any of the image views is deleted + if(fb_it != m_Cache.end()) + { + m_DeviceVk.SafeReleaseVkObject(std::move(fb_it->second)); + m_Cache.erase(fb_it); + } + } + m_ViewToKeyMap.erase(equal_range.first, equal_range.second); +} + +void FramebufferCache::OnDestroyRenderPass(VkRenderPass Pass) +{ + std::lock_guard<std::mutex> Lock(m_Mutex); + auto equal_range = m_RenderPassToKeyMap.equal_range(Pass); + for (auto it = equal_range.first; it != equal_range.second; ++it) + { + auto fb_it = m_Cache.find(it->second); + // Multiple image views may be associated with the same key. + // The framebuffer is deleted whenever any of the image views or render pass is destroyed + if (fb_it != m_Cache.end()) + { + m_DeviceVk.SafeReleaseVkObject(std::move(fb_it->second)); + m_Cache.erase(fb_it); + } + } + m_RenderPassToKeyMap.erase(equal_range.first, equal_range.second); +} + +} diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 17a9216a..3785ba0e 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -439,6 +439,7 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren PipelineStateVkImpl::~PipelineStateVkImpl() { auto pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice()); + pDeviceVkImpl->GetFramebufferCache().OnDestroyRenderPass(m_RenderPass); pDeviceVkImpl->SafeReleaseVkObject(std::move(m_RenderPass)); pDeviceVkImpl->SafeReleaseVkObject(std::move(m_Pipeline)); pDeviceVkImpl->SafeReleaseVkObject(std::move(m_PipelineLayout)); diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index cb90a89d..f6dcdf51 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -76,7 +76,8 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters, m_StaleVkObjects(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue<ReleaseQueueElemType>")),/*, m_UploadHeaps(STD_ALLOCATOR_RAW_MEM(UploadHeapPoolElemType, GetRawAllocator(), "Allocator for vector<unique_ptr<DynamicUploadHeap>>")) */ - m_CmdBufferPool(m_LogicalVkDevice->GetSharedPtr(), pCmdQueue->GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT) + m_CmdBufferPool(m_LogicalVkDevice->GetSharedPtr(), pCmdQueue->GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT), + m_FramebufferCache(*this) { m_DeviceCaps.DevType = DeviceType::Vulkan; m_DeviceCaps.MajorVersion = 1; diff --git a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp index 48536542..432ead97 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp @@ -43,6 +43,8 @@ TextureViewVkImpl::TextureViewVkImpl( IReferenceCounters *pRefCounters, TextureViewVkImpl::~TextureViewVkImpl() { auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice()); + if(m_Desc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL || m_Desc.ViewType == TEXTURE_VIEW_RENDER_TARGET) + pDeviceVkImpl->GetFramebufferCache().OnDestroyImageView(m_ImageView); pDeviceVkImpl->SafeReleaseVkObject(std::move(m_ImageView)); } |
