summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2018-06-05 06:07:00 +0000
committerEgor Yusov <egor.yusov@gmail.com>2018-06-05 06:07:00 +0000
commit31ad9001b14c006000fa3dde1557d9a7e658316c (patch)
treef2ae23256d73adf169580c501915c906528fbd7e /Graphics/GraphicsEngineVulkan
parentUpdated info messages from memory manager (diff)
downloadDiligentCore-31ad9001b14c006000fa3dde1557d9a7e658316c.tar.gz
DiligentCore-31ad9001b14c006000fa3dde1557d9a7e658316c.zip
Reworked upload heap in Vulkan
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/CMakeLists.txt4
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h9
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h16
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.h40
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanUploadHeap.h84
-rw-r--r--Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp6
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp24
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp97
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp4
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp19
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanUploadHeap.cpp103
11 files changed, 313 insertions, 93 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
index 31502969..ab667660 100644
--- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt
+++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
@@ -27,8 +27,8 @@ set(INCLUDE
include/SwapChainVkImpl.h
include/TextureVkImpl.h
include/TextureViewVkImpl.h
- include/VulkanTypeConversions.h
include/VulkanErrors.h
+ include/VulkanTypeConversions.h
)
set(VULKAN_UTILS_INCLUDE
@@ -42,6 +42,7 @@ set(VULKAN_UTILS_INCLUDE
include/VulkanUtilities/VulkanMemoryManager.h
include/VulkanUtilities/VulkanObjectWrappers.h
include/VulkanUtilities/VulkanPhysicalDevice.h
+ include/VulkanUtilities/VulkanUploadHeap.h
)
@@ -99,6 +100,7 @@ set(VULKAN_UTILS_SRC
src/VulkanUtilities/VulkanLogicalDevice.cpp
src/VulkanUtilities/VulkanMemoryManager.cpp
src/VulkanUtilities/VulkanPhysicalDevice.cpp
+ src/VulkanUtilities/VulkanUploadHeap.cpp
)
#set(SHADERS
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
index a748ca58..e14ef3c1 100644
--- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
@@ -32,6 +32,7 @@
#include "GenerateMips.h"
#include "VulkanUtilities/VulkanCommandBufferPool.h"
#include "VulkanUtilities/VulkanCommandBuffer.h"
+#include "VulkanUtilities/VulkanUploadHeap.h"
#include "VulkanDynamicHeap.h"
#ifdef _DEBUG
@@ -112,8 +113,8 @@ public:
///// Number of different shader types (Vertex, Pixel, Geometry, Domain, Hull, Compute)
//static constexpr int NumShaderTypes = 6;
- void UpdateBufferRegion(class BufferVkImpl *pBuffVk, struct VulkanDynamicAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes);
- void UpdateBufferRegion(class BufferVkImpl *pBuffVk, const void *pData, Uint64 DstOffset, Uint64 NumBytes);
+ void UpdateBufferRegion(class BufferVkImpl* pBuffVk, VulkanUtilities::VulkanUploadAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes);
+ void UpdateBufferRegion(class BufferVkImpl* pBuffVk, const void *pData, Uint64 DstOffset, Uint64 NumBytes);
void CopyBufferRegion(class BufferVkImpl *pSrcBuffVk, class BufferVkImpl *pDstBuffVk, Uint64 SrcOffset, Uint64 DstOffset, Uint64 NumBytes);
void CopyTextureRegion(class TextureVkImpl *pSrcTexture, class TextureVkImpl *pDstTexture, const VkImageCopy &CopyRegion);
@@ -122,7 +123,7 @@ public:
#endif
void GenerateMips(class TextureViewVkImpl *pTexView);
- void* AllocateDynamicUploadSpace(BufferVkImpl* pBuffer, size_t NumBytes, size_t Alignment);
+ void* AllocateUploadSpace(BufferVkImpl* pBuffer, size_t NumBytes);
void CopyAndFreeDynamicUploadData(BufferVkImpl* pBuffer);
Uint32 GetContextId()const{return m_ContextId;}
@@ -178,7 +179,7 @@ private:
std::vector<VkPipelineStageFlags> m_WaitDstStageMasks;
std::vector<VkSemaphore> m_SignalSemaphores;
- std::unordered_map<BufferVkImpl*, VulkanDynamicAllocation> m_UploadAllocations;
+ std::unordered_map<BufferVkImpl*, VulkanUtilities::VulkanUploadAllocation> m_UploadAllocations;
};
}
diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h
index fb816379..7ab4df4e 100644
--- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h
@@ -40,6 +40,7 @@
#include "VulkanUtilities/VulkanLogicalDevice.h"
#include "VulkanUtilities/VulkanObjectWrappers.h"
#include "VulkanUtilities/VulkanMemoryManager.h"
+#include "VulkanUtilities/VulkanUploadHeap.h"
#include "FramebufferCache.h"
#include "CommandPoolManager.h"
@@ -102,11 +103,9 @@ public:
void DisposeTransientCmdPool(VulkanUtilities::CommandPoolWrapper&& CmdPool);
- template<typename VulkanObjectType>
- void SafeReleaseVkObject(VulkanUtilities::VulkanObjectWrapper<VulkanObjectType>&& vkObject);
- void SafeReleaseMemoryAllocation(VulkanUtilities::VulkanMemoryAllocation&& Allocation);
-
-
+ template<typename ObjectType>
+ void SafeReleaseVkObject(ObjectType&& Object);
+
void FinishFrame(bool ReleaseAllResources);
virtual void FinishFrame()override final { FinishFrame(false); }
@@ -121,9 +120,9 @@ public:
return m_DescriptorPools[1 + CtxId].Allocate(SetLayout);
}
- VulkanDynamicAllocation AllocateDynamicUploadSpace(Uint32 CtxId, size_t Size, size_t Alignment)
+ VulkanUtilities::VulkanUploadAllocation AllocateUploadSpace(Uint32 CtxId, size_t Size)
{
- return m_UploadHeaps[CtxId]->Allocate(Size, Alignment);
+ return m_UploadHeaps[CtxId].Allocate(Size);
}
std::shared_ptr<const VulkanUtilities::VulkanInstance> GetVulkanInstance()const{return m_VulkanInstance;}
@@ -208,8 +207,7 @@ private:
// [2+] - Deferred context dynamic descriptor pool
std::vector<DescriptorPoolManager, STDAllocatorRawMem<DescriptorPoolManager> > m_DescriptorPools;
- typedef std::unique_ptr<VulkanDynamicHeap, STDDeleterRawMem<VulkanDynamicHeap> > UploadHeapPoolElemType;
- std::vector< UploadHeapPoolElemType, STDAllocatorRawMem<UploadHeapPoolElemType> > m_UploadHeaps;
+ std::vector<VulkanUtilities::VulkanUploadHeap, STDAllocatorRawMem<VulkanUtilities::VulkanUploadHeap>> m_UploadHeaps;
// These one-time command pools are used by buffer and texture constructors to
// issue copy commands. Vulkan requires that every command pool is used by one thread
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.h
index bbe6b91e..8a50da8d 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.h
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.h
@@ -91,7 +91,7 @@ public:
VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr,
VkDeviceSize PageSize,
uint32_t MemoryTypeIndex,
- bool MapMemory)noexcept;
+ bool IsHostVisible)noexcept;
~VulkanMemoryPage();
VulkanMemoryPage(VulkanMemoryPage&& rhs)noexcept :
@@ -150,29 +150,57 @@ public:
m_DeviceLocalReserveSize(DeviceLocalReserveSize),
m_HostVisibleReserveSize(HostVisibleReserveSize)
{}
+
+ // We have to write this constructor because on msvc default
+ // constructor is not labeled with noexcept, which makes all
+ // std containers use copy instead of move
+ VulkanMemoryManager(VulkanMemoryManager&& rhs)noexcept :
+ m_MgrName (std::move(rhs.m_MgrName)),
+ m_LogicalDevice (rhs.m_LogicalDevice),
+ m_PhysicalDevice (rhs.m_PhysicalDevice),
+ m_Allocator (rhs.m_Allocator),
+ m_Pages (std::move(rhs.m_Pages)),
+
+ m_DeviceLocalPageSize (rhs.m_DeviceLocalPageSize),
+ m_HostVisiblePageSize (rhs.m_HostVisiblePageSize),
+ m_DeviceLocalReserveSize (rhs.m_DeviceLocalReserveSize),
+ m_HostVisibleReserveSize (rhs.m_HostVisibleReserveSize),
+ //m_CurrUsedSize (rhs.m_CurrUsedSize),
+ m_PeakUsedSize (rhs.m_PeakUsedSize),
+ m_CurrAllocatedSize (rhs.m_CurrAllocatedSize),
+ m_PeakAllocatedSize (rhs.m_PeakAllocatedSize)
+ {
+ for(int i=0; i < m_CurrUsedSize.size(); ++i)
+ m_CurrUsedSize[i].store(rhs.m_CurrUsedSize[i].load());
+ }
+
~VulkanMemoryManager();
VulkanMemoryManager (const VulkanMemoryManager&) = delete;
- VulkanMemoryManager (VulkanMemoryManager&&) = delete;
VulkanMemoryManager& operator= (const VulkanMemoryManager&) = delete;
VulkanMemoryManager& operator= (VulkanMemoryManager&&) = delete;
+ VulkanMemoryAllocation Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible);
VulkanMemoryAllocation Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps);
void ShrinkMemory();
-private:
+protected:
friend class VulkanMemoryPage;
- const std::string m_MgrName;
+ virtual void OnNewPageCreated(VulkanMemoryPage& NewPage){}
+ virtual void OnPageDestroy(VulkanMemoryPage& Page){}
+
+ std::string m_MgrName;
const VulkanLogicalDevice& m_LogicalDevice;
const VulkanPhysicalDevice& m_PhysicalDevice;
Diligent::IMemoryAllocator& m_Allocator;
+ std::mutex m_PagesMtx;
std::unordered_multimap<uint32_t, VulkanMemoryPage> m_Pages;
- std::mutex m_Mutex;
+
const VkDeviceSize m_DeviceLocalPageSize;
const VkDeviceSize m_HostVisiblePageSize;
const VkDeviceSize m_DeviceLocalReserveSize;
@@ -185,6 +213,8 @@ private:
std::array<VkDeviceSize, 2> m_PeakUsedSize = {};
std::array<VkDeviceSize, 2> m_CurrAllocatedSize = {};
std::array<VkDeviceSize, 2> m_PeakAllocatedSize = {};
+
+ // If adding new member, do not forget to update move ctor
};
}
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanUploadHeap.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanUploadHeap.h
new file mode 100644
index 00000000..a1f07a11
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanUploadHeap.h
@@ -0,0 +1,84 @@
+/* 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
+
+#include <unordered_map>
+#include "VulkanUtilities/VulkanMemoryManager.h"
+
+namespace VulkanUtilities
+{
+
+struct VulkanUploadAllocation
+{
+ VulkanUploadAllocation(){}
+ VulkanUploadAllocation(VulkanMemoryAllocation&& _MemAllocation, VkBuffer _vkBuffer) :
+ MemAllocation(std::move(_MemAllocation)),
+ vkBuffer(_vkBuffer)
+ {}
+ VulkanUploadAllocation (const VulkanUploadAllocation&) = delete;
+ VulkanUploadAllocation& operator = (const VulkanUploadAllocation&) = delete;
+ VulkanUploadAllocation (VulkanUploadAllocation&&) = default;
+ VulkanUploadAllocation& operator = (VulkanUploadAllocation&&) = default;
+
+ VulkanMemoryAllocation MemAllocation;
+ VkBuffer vkBuffer = VK_NULL_HANDLE; // Vulkan buffer associated with this memory.
+};
+
+class VulkanUploadHeap : public VulkanMemoryManager
+{
+public:
+ VulkanUploadHeap(std::string MgrName,
+ const VulkanLogicalDevice& LogicalDevice,
+ const VulkanPhysicalDevice& PhysicalDevice,
+ Diligent::IMemoryAllocator& Allocator,
+ VkDeviceSize HostVisiblePageSize,
+ VkDeviceSize HostVisibleReserveSize);
+
+ VulkanUploadHeap(VulkanUploadHeap&& rhs)noexcept :
+ VulkanMemoryManager(std::move(rhs)),
+ m_StagingBufferMemoryTypeIndex(rhs.m_StagingBufferMemoryTypeIndex),
+ m_Buffers(std::move(rhs.m_Buffers))
+ {
+ }
+ VulkanUploadHeap (const VulkanUploadHeap&) = delete;
+ VulkanUploadHeap& operator= (VulkanUploadHeap&) = delete;
+ VulkanUploadHeap& operator= (VulkanUploadHeap&& rhs) = delete;
+
+ ~VulkanUploadHeap();
+
+ VulkanUploadAllocation Allocate(size_t SizeInBytes);
+
+private:
+ virtual void OnNewPageCreated(VulkanMemoryPage& NewPage);
+ virtual void OnPageDestroy(VulkanMemoryPage& Page);
+ VkBufferCreateInfo GetStagingBufferCI()const;
+
+ uint32_t m_StagingBufferMemoryTypeIndex = 0;
+ std::mutex m_BuffersMtx;
+ std::unordered_map<VulkanMemoryPage*, VulkanUtilities::BufferWrapper> m_Buffers;
+
+ // If adding new member, do not forget to update move ctor
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
index a1711629..fa5170ae 100644
--- a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
@@ -182,7 +182,7 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters,
// until copy operation is complete. This must be done after
// submitting command list for execution!
pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingBuffer));
- pRenderDeviceVk->SafeReleaseMemoryAllocation(std::move(StagingMemoryAllocation));
+ pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingMemoryAllocation));
}
else
{
@@ -259,7 +259,7 @@ BufferVkImpl :: ~BufferVkImpl()
auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice());
// Vk object can only be destroyed when it is no longer used by the GPU
pDeviceVkImpl->SafeReleaseVkObject(std::move(m_VulkanBuffer));
- pDeviceVkImpl->SafeReleaseMemoryAllocation(std::move(m_MemoryAllocation));
+ pDeviceVkImpl->SafeReleaseVkObject(std::move(m_MemoryAllocation));
}
IMPLEMENT_QUERY_INTERFACE( BufferVkImpl, IID_BufferVk, TBufferBase )
@@ -323,7 +323,7 @@ void BufferVkImpl :: Map(IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapF
else if (m_Desc.Usage == USAGE_DYNAMIC)
{
VERIFY(MapFlags & MAP_FLAG_DISCARD, "Vk buffer must be mapped for writing with MAP_FLAG_DISCARD flag");
- pMappedData = pDeviceContextVk->AllocateDynamicUploadSpace(this, m_Desc.uiSizeInBytes, 0);
+ pMappedData = pDeviceContextVk->AllocateUploadSpace(this, m_Desc.uiSizeInBytes);
}
else
{
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
index 631f5542..252142e1 100644
--- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -912,17 +912,17 @@ namespace Diligent
}
}
- void DeviceContextVkImpl::UpdateBufferRegion(BufferVkImpl *pBuffVk, VulkanDynamicAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes)
+ void DeviceContextVkImpl::UpdateBufferRegion(BufferVkImpl *pBuffVk, VulkanUtilities::VulkanUploadAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes)
{
VERIFY(DstOffset + NumBytes <= pBuffVk->GetDesc().uiSizeInBytes, "Update region is out of buffer");
- VERIFY_EXPR(NumBytes <= Allocation.Size);
+ VERIFY_EXPR(NumBytes <= Allocation.MemAllocation.Size);
EnsureVkCmdBuffer();
if(!pBuffVk->CheckAccessFlags(VK_ACCESS_TRANSFER_WRITE_BIT))
{
BufferMemoryBarrier(*pBuffVk, VK_ACCESS_TRANSFER_WRITE_BIT);
}
VkBufferCopy CopyRegion;
- CopyRegion.srcOffset = Allocation.Offset;
+ CopyRegion.srcOffset = Allocation.MemAllocation.UnalignedOffset;
CopyRegion.dstOffset = DstOffset;
CopyRegion.size = NumBytes;
m_CommandBuffer.CopyBuffer(Allocation.vkBuffer, pBuffVk->GetVkBuffer(), 1, &CopyRegion);
@@ -933,9 +933,12 @@ namespace Diligent
{
VERIFY(pBuffVk->GetDesc().Usage != USAGE_DYNAMIC, "Dynamic buffers must be updated via Map()");
VERIFY_EXPR( static_cast<size_t>(NumBytes) == NumBytes );
- auto TmpSpace = m_pDevice.RawPtr<RenderDeviceVkImpl>()->AllocateDynamicUploadSpace(m_ContextId, NumBytes, 0);
- memcpy(TmpSpace.CPUAddress, pData, static_cast<size_t>(NumBytes));
+ auto *pDeviceVkImpl = m_pDevice.RawPtr<RenderDeviceVkImpl>();
+ auto TmpSpace = pDeviceVkImpl->AllocateUploadSpace(m_ContextId, NumBytes);
+ auto CPUAddress = TmpSpace.MemAllocation.Page->GetCPUMemory();
+ memcpy(reinterpret_cast<Uint8*>(CPUAddress) + TmpSpace.MemAllocation.UnalignedOffset, pData, static_cast<size_t>(NumBytes));
UpdateBufferRegion(pBuffVk, TmpSpace, DstOffset, NumBytes);
+ pDeviceVkImpl->SafeReleaseVkObject(std::move(TmpSpace));
}
void DeviceContextVkImpl::CopyBufferRegion(BufferVkImpl *pSrcBuffVk, BufferVkImpl *pDstBuffVk, Uint64 SrcOffset, Uint64 DstOffset, Uint64 NumBytes)
@@ -1151,11 +1154,11 @@ namespace Diligent
BufferVk.SetAccessFlags(NewAccessFlags);
}
- void* DeviceContextVkImpl::AllocateDynamicUploadSpace(BufferVkImpl* pBuffer, size_t NumBytes, size_t Alignment)
+ void* DeviceContextVkImpl::AllocateUploadSpace(BufferVkImpl* pBuffer, size_t NumBytes)
{
VERIFY(m_UploadAllocations.find(pBuffer) == m_UploadAllocations.end(), "Upload space has already been allocated for this buffer");
- auto UploadAllocation = m_pDevice.RawPtr<RenderDeviceVkImpl>()->AllocateDynamicUploadSpace(m_ContextId, NumBytes, Alignment);
- auto *CPUAddress = UploadAllocation.CPUAddress;
+ auto UploadAllocation = m_pDevice.RawPtr<RenderDeviceVkImpl>()->AllocateUploadSpace(m_ContextId, NumBytes);
+ auto *CPUAddress = reinterpret_cast<Uint8*>(UploadAllocation.MemAllocation.Page->GetCPUMemory()) + UploadAllocation.MemAllocation.UnalignedOffset;
m_UploadAllocations.emplace(pBuffer, std::move(UploadAllocation));
return CPUAddress;
}
@@ -1167,10 +1170,11 @@ namespace Diligent
{
#ifdef _DEBUG
- auto CurrentFrame = m_pDevice.RawPtr<RenderDeviceVkImpl>()->GetCurrentFrameNumber();
- VERIFY(it->second.FrameNum == CurrentFrame, "Dynamic allocation is out-of-date. Dynamic buffer \"", pBuffer->GetDesc().Name, "\" must be unmapped in the same frame it is used.");
+ //auto CurrentFrame = m_pDevice.RawPtr<RenderDeviceVkImpl>()->GetCurrentFrameNumber();
+ //VERIFY(it->second.FrameNum == CurrentFrame, "Dynamic allocation is out-of-date. Dynamic buffer \"", pBuffer->GetDesc().Name, "\" must be unmapped in the same frame it is used.");
#endif
UpdateBufferRegion(pBuffer, it->second, 0, pBuffer->GetDesc().uiSizeInBytes);
+ m_pDevice.RawPtr<RenderDeviceVkImpl>()->SafeReleaseVkObject(std::move(it->second));
m_UploadAllocations.erase(it);
}
else
diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
index f69b41dc..2433d657 100644
--- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
@@ -22,6 +22,7 @@
*/
#include "pch.h"
+#include <sstream>
#include "RenderDeviceVkImpl.h"
#include "PipelineStateVkImpl.h"
#include "ShaderVkImpl.h"
@@ -58,7 +59,7 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters,
m_VkObjReleaseQueue(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue<ReleaseQueueElemType>")),
m_StaleVkObjects(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue<ReleaseQueueElemType>")),
m_DescriptorPools(STD_ALLOCATOR_RAW_MEM(DescriptorPoolManager, GetRawAllocator(), "Allocator for vector<DescriptorPoolManager>")),
- m_UploadHeaps(STD_ALLOCATOR_RAW_MEM(UploadHeapPoolElemType, GetRawAllocator(), "Allocator for vector<unique_ptr<VulkanDynamicHeap>>")),
+ m_UploadHeaps(STD_ALLOCATOR_RAW_MEM(VulkanUtilities::VulkanUploadHeap, GetRawAllocator(), "Allocator for vector<VulkanUploadHeap>")),
m_FramebufferCache(*this),
m_TransientCmdPoolMgr(*m_LogicalVkDevice, pCmdQueue->GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT),
m_MemoryMgr("Global resource memory manager", *m_LogicalVkDevice, *m_PhysicalDevice, GetRawAllocator(), CreationAttribs.DeviceLocalMemoryPageSize, CreationAttribs.HostVisibleMemoryPageSize, CreationAttribs.DeviceLocalMemoryReserveSize, CreationAttribs.HostVisibleMemoryReserveSize)
@@ -112,11 +113,15 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters,
);
{
- auto InitialSize = ctx == 0 ? CreationAttribs.ImmediateCtxDynamicHeapInitialSize : CreationAttribs.DeferredCtxDynamicHeapInitialSize;
- auto &UploadHeapAllocator = GetRawAllocator();
- auto *pRawMem = ALLOCATE(UploadHeapAllocator, "DynamicUploadHeap instance", sizeof(VulkanDynamicHeap));
- auto *pNewHeap = new (pRawMem) VulkanDynamicHeap(GetRawAllocator(), this, InitialSize);
- m_UploadHeaps.emplace_back( pNewHeap, STDDeleterRawMem<VulkanDynamicHeap>(UploadHeapAllocator) );
+ auto PageSize = ctx == 0 ? CreationAttribs.ImmediateCtxUploadHeapPageSize : CreationAttribs.DeferredCtxUploadHeapPageSize;
+ auto ReserveSize = ctx == 0 ? CreationAttribs.ImmediateCtxUploadHeapReserveSize : CreationAttribs.DeferredCtxUploadHeapReserveSize;
+ std::stringstream ss;
+ if(ctx == 0)
+ ss << "Immediate context";
+ else
+ ss << "Deferred context " << ctx-1;
+ ss << " upload heap";
+ m_UploadHeaps.emplace_back( ss.str(), *m_LogicalVkDevice, *m_PhysicalDevice, RawMemAllocator, PageSize, ReserveSize );
}
}
}
@@ -208,7 +213,7 @@ void RenderDeviceVkImpl::ExecuteCommandBuffer(const VkSubmitInfo &SubmitInfo, bo
// | was added to the delete queue | |
// | with number N | |
- // Move stale objects into a release queue.
+ // Move stale objects into the release queue.
// Note that objects are moved from stale list to release queue based on the
// cmd list number, not the fence value. This makes sure that basic requirement
// is met even when the fence value is not incremented while executing
@@ -322,8 +327,7 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources)
// time for every context
//std::lock_guard<std::mutex> LockGuard(m_UploadHeapMutex);
- // Upload heaps are used to update resource contents as well as to allocate
- // space for dynamic resources.
+ // Upload heaps are used to update resource contents
// Initial resource data is uploaded using temporary one-time upload buffers,
// so can be performed in parallel across frame boundaries
for (auto &UploadHeap : m_UploadHeaps)
@@ -342,7 +346,7 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources)
//
//
- UploadHeap->FinishFrame(NextFenceValue, CompletedFenceValue);
+ UploadHeap.ShrinkMemory();
}
}
@@ -399,66 +403,53 @@ void RenderDeviceVkImpl::DisposeTransientCmdPool(VulkanUtilities::CommandPoolWra
-template<typename VulkanObjectType>
-void RenderDeviceVkImpl::SafeReleaseVkObject(VulkanUtilities::VulkanObjectWrapper<VulkanObjectType>&& vkObject)
+template<typename ObjectType>
+void RenderDeviceVkImpl::SafeReleaseVkObject(ObjectType&& vkObject)
{
class StaleVulkanObject : public RenderDeviceVkImpl::StaleVulkanObjectBase
{
public:
- StaleVulkanObject(VulkanUtilities::VulkanObjectWrapper<VulkanObjectType>&& Object) :
+ StaleVulkanObject(ObjectType&& Object) :
m_VkObject(std::move(Object))
{}
- ~StaleVulkanObject()
- {
- m_VkObject.Release();
- }
+ StaleVulkanObject (const StaleVulkanObject&) = delete;
+ StaleVulkanObject (StaleVulkanObject&&) = delete;
+ StaleVulkanObject& operator = (const StaleVulkanObject&) = delete;
+ StaleVulkanObject& operator = (StaleVulkanObject&&) = delete;
private:
- VulkanUtilities::VulkanObjectWrapper<VulkanObjectType> m_VkObject;
+ ObjectType m_VkObject;
};
// When Vk object is released, it is first moved into the
// stale objects list. The list is moved into a release queue
// after the next command list is executed.
std::lock_guard<std::mutex> LockGuard(m_StaleObjectsMutex);
- m_StaleVkObjects.emplace_back(m_NextCmdListNumber, new StaleVulkanObject(std::move(vkObject)) );
-}
-
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkBuffer> (VulkanUtilities::BufferWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkBufferView> (VulkanUtilities::BufferViewWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkImage> (VulkanUtilities::ImageWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkImageView> (VulkanUtilities::ImageViewWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkSampler> (VulkanUtilities::SamplerWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkDeviceMemory> (VulkanUtilities::DeviceMemoryWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkRenderPass> (VulkanUtilities::RenderPassWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkPipeline> (VulkanUtilities::PipelineWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkShaderModule> (VulkanUtilities::ShaderModuleWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkPipelineLayout>(VulkanUtilities::PipelineLayoutWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkFramebuffer> (VulkanUtilities::FramebufferWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkDescriptorPool> (VulkanUtilities::DescriptorPoolWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkDescriptorSetLayout>(VulkanUtilities::DescriptorSetLayoutWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkSemaphore> (VulkanUtilities::SemaphoreWrapper &&Object);
-template void RenderDeviceVkImpl::SafeReleaseVkObject<VkCommandPool> (VulkanUtilities::CommandPoolWrapper &&Object);
-
-
-void RenderDeviceVkImpl::SafeReleaseMemoryAllocation(VulkanUtilities::VulkanMemoryAllocation&& Allocation)
-{
- class StaleVulkanMemoryAllocation : public StaleVulkanObjectBase
- {
- public:
- StaleVulkanMemoryAllocation(VulkanUtilities::VulkanMemoryAllocation &&Allocation) :
- m_Allocation(std::move(Allocation))
- {}
-
- private:
- VulkanUtilities::VulkanMemoryAllocation m_Allocation;
- };
-
- std::lock_guard<std::mutex> LockGuard(m_StaleObjectsMutex);
- m_StaleVkObjects.emplace_back(m_NextCmdListNumber, new StaleVulkanMemoryAllocation(std::move(Allocation)) );
+ m_StaleVkObjects.emplace_back(m_NextCmdListNumber, new StaleVulkanObject{std::move(vkObject)} );
}
+#define INSTANTIATE_SAFE_RELEASE_VK_OBJECT(Type) template void RenderDeviceVkImpl::SafeReleaseVkObject<Type>(Type &&Object)
+
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::BufferWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::BufferViewWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::ImageWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::ImageViewWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::SamplerWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::DeviceMemoryWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::RenderPassWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::PipelineWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::ShaderModuleWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::PipelineLayoutWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::FramebufferWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::DescriptorPoolWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::DescriptorSetLayoutWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::SemaphoreWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::CommandPoolWrapper);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::VulkanMemoryAllocation);
+INSTANTIATE_SAFE_RELEASE_VK_OBJECT(VulkanUtilities::VulkanUploadAllocation);
+
+#undef INSTANTIATE_SAFE_RELEASE_VK_OBJECT
void RenderDeviceVkImpl::DiscardStaleVkObjects(Uint64 CmdListNumber, Uint64 FenceValue)
{
diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
index 255f08fd..c43dc5c9 100644
--- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
@@ -394,7 +394,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters *pRefCounters,
// until copy operation is complete. This must be done after
// submitting command list for execution!
pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingBuffer));
- pRenderDeviceVk->SafeReleaseMemoryAllocation(std::move(StagingMemoryAllocation));
+ pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingMemoryAllocation));
}
#if 0
@@ -495,7 +495,7 @@ TextureVkImpl :: ~TextureVkImpl()
// Vk object can only be destroyed when it is no longer used by the GPU
// Wrappers for external texture will not be destroyed as they are created with null device pointer
pDeviceVkImpl->SafeReleaseVkObject(std::move(m_VulkanImage));
- pDeviceVkImpl->SafeReleaseMemoryAllocation(std::move(m_MemoryAllocation));
+ pDeviceVkImpl->SafeReleaseVkObject(std::move(m_MemoryAllocation));
}
void TextureVkImpl::UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint32 Slice, const Box &DstBox, const TextureSubResData &SubresData )
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp
index f3e8e315..8739852f 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp
@@ -40,7 +40,7 @@ VulkanMemoryAllocation::~VulkanMemoryAllocation()
VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr,
VkDeviceSize PageSize,
uint32_t MemoryTypeIndex,
- bool MapMemory)noexcept :
+ bool IsHostVisible)noexcept :
m_ParentMemoryMgr(ParentMemoryMgr),
m_AllocationMgr(PageSize, ParentMemoryMgr.m_Allocator)
{
@@ -54,7 +54,7 @@ VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr,
ss << "Device memory page. Size: " << (PageSize >> 10) << " Kb, type: " << MemoryTypeIndex;
m_VkMemory = ParentMemoryMgr.m_LogicalDevice.AllocateDeviceMemory(MemAlloc, ss.str().c_str());
- if(MapMemory)
+ if(IsHostVisible)
{
auto err = ParentMemoryMgr.m_LogicalDevice.MapMemory(m_VkMemory,
0, // offset
@@ -125,10 +125,16 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements&
LOG_ERROR_AND_THROW("Failed to find suitable device memory type for a buffer");
}
- auto Size = MemReqs.size + MemReqs.alignment;
+ bool HostVisible = (MemoryProps & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
+ return Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, HostVisible);
+}
+
+VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible)
+{
+ Size += Alignment;
VulkanMemoryAllocation Allocation;
- std::lock_guard<std::mutex> Lock(m_Mutex);
+ std::lock_guard<std::mutex> Lock(m_PagesMtx);
auto range = m_Pages.equal_range(MemoryTypeIndex);
for(auto page_it = range.first; page_it != range.second; ++page_it)
{
@@ -137,7 +143,6 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements&
break;
}
- bool HostVisible = (MemoryProps & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
size_t stat_ind = HostVisible ? 1 : 0;
if(Allocation.Page == nullptr)
{
@@ -152,6 +157,7 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements&
LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "': created new ", (HostVisible ? "host-visible" : "device-local"), " page. (",
std::fixed, std::setprecision(2), PageSize / double{1 << 20}, " MB, type idx: ", MemoryTypeIndex,
"). Current allocated size: ", std::fixed, std::setprecision(2), m_CurrAllocatedSize[stat_ind] / double{1 << 20}, " MB");
+ OnNewPageCreated(it->second);
Allocation = it->second.Allocate(Size);
VERIFY(Allocation.Page != nullptr, "Failed to allocate new memory page");
}
@@ -164,7 +170,7 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements&
void VulkanMemoryManager::ShrinkMemory()
{
- std::lock_guard<std::mutex> Lock(m_Mutex);
+ std::lock_guard<std::mutex> Lock(m_PagesMtx);
if(m_CurrAllocatedSize[0] <= m_DeviceLocalReserveSize && m_CurrAllocatedSize[1] <= m_HostVisibleReserveSize)
return;
@@ -183,6 +189,7 @@ void VulkanMemoryManager::ShrinkMemory()
LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "': destroying ", (IsHostVisible ? "host-visible" : "device-local"), " page (",
std::fixed, std::setprecision(2), PageSize / double{1 << 20},
" MB). Current allocated size: ", std::fixed, std::setprecision(2), m_CurrAllocatedSize[IsHostVisible ? 1 : 0] / double{1 << 20}, " MB");
+ OnPageDestroy(Page);
m_Pages.erase(curr_it);
}
}
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanUploadHeap.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanUploadHeap.cpp
new file mode 100644
index 00000000..57b4075d
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanUploadHeap.cpp
@@ -0,0 +1,103 @@
+/* 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 "VulkanUtilities/VulkanUploadHeap.h"
+
+namespace VulkanUtilities
+{
+
+VkBufferCreateInfo VulkanUploadHeap::GetStagingBufferCI()const
+{
+ VkBufferCreateInfo StagingBufferCI = {};
+ StagingBufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ StagingBufferCI.pNext = nullptr;
+ StagingBufferCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
+ StagingBufferCI.size = m_HostVisiblePageSize;
+ StagingBufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ StagingBufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ StagingBufferCI.queueFamilyIndexCount = 0;
+ StagingBufferCI.pQueueFamilyIndices = nullptr;
+ return StagingBufferCI;
+}
+
+VulkanUploadHeap::VulkanUploadHeap(std::string MgrName,
+ const VulkanLogicalDevice& LogicalDevice,
+ const VulkanPhysicalDevice& PhysicalDevice,
+ Diligent::IMemoryAllocator& Allocator,
+ VkDeviceSize HostVisiblePageSize,
+ VkDeviceSize HostVisibleReserveSize) :
+ VulkanMemoryManager(MgrName, LogicalDevice, PhysicalDevice, Allocator, 0, HostVisiblePageSize, 0, HostVisibleReserveSize)
+{
+ auto StagingBufferCI = GetStagingBufferCI();
+ auto TmpStagingBuffer = LogicalDevice.CreateBuffer(StagingBufferCI);
+
+ VkMemoryRequirements StagingBufferMemReqs = LogicalDevice.GetBufferMemoryRequirements(TmpStagingBuffer);
+ m_StagingBufferMemoryTypeIndex = m_PhysicalDevice.GetMemoryTypeIndex(StagingBufferMemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+ VERIFY(m_StagingBufferMemoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex,
+ "Vulkan spec requires that for a VkBuffer not created with the VK_BUFFER_CREATE_SPARSE_BINDING_BIT "
+ "bit set, or for a VkImage that was created with a VK_IMAGE_TILING_LINEAR value in the tiling member "
+ "of the VkImageCreateInfo structure passed to vkCreateImage, the memoryTypeBits member always contains "
+ "at least one bit set corresponding to a VkMemoryType with a propertyFlags that has both the "
+ "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT bit AND the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit set. (11.6)");
+}
+
+VulkanUploadHeap::~VulkanUploadHeap()
+{
+ VERIFY_EXPR(m_Pages.size() == m_Buffers.size());
+}
+
+VulkanUploadAllocation VulkanUploadHeap::Allocate(size_t SizeInBytes)
+{
+ VulkanUploadAllocation Allocation;
+ Allocation.MemAllocation = VulkanMemoryManager::Allocate(SizeInBytes, 0, m_StagingBufferMemoryTypeIndex, true);
+
+ std::lock_guard<std::mutex> Lock(m_BuffersMtx);
+ auto BuffIt = m_Buffers.find(Allocation.MemAllocation.Page);
+ VERIFY_EXPR(BuffIt != m_Buffers.end());
+ Allocation.vkBuffer = BuffIt->second;
+
+ return Allocation;
+}
+
+void VulkanUploadHeap::OnNewPageCreated(VulkanMemoryPage& NewPage)
+{
+ std::lock_guard<std::mutex> Lock(m_BuffersMtx);
+ auto BufferCI = GetStagingBufferCI();
+ auto NewBuffer = m_LogicalDevice.CreateBuffer(BufferCI, "Upload buffer");
+ auto MemReqs = m_LogicalDevice.GetBufferMemoryRequirements(NewBuffer);
+ auto MemoryTypeIndex = m_PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+ VERIFY(MemoryTypeIndex == m_StagingBufferMemoryTypeIndex, "Incosistent memory type");
+ auto err = m_LogicalDevice.BindBufferMemory(NewBuffer, NewPage.GetVkMemory(), 0);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to bind buffer memory");
+ m_Buffers.emplace(&NewPage, std::move(NewBuffer));
+}
+
+void VulkanUploadHeap::OnPageDestroy(VulkanMemoryPage& Page)
+{
+ std::lock_guard<std::mutex> Lock(m_BuffersMtx);
+ auto ElemsRemoved = m_Buffers.erase(&Page);
+ VERIFY_EXPR(ElemsRemoved == 1);
+}
+
+}