summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2018-05-30 15:20:35 +0000
committerEgor Yusov <egor.yusov@gmail.com>2018-05-30 15:20:35 +0000
commit5a56e75e2f3c7243eb040590e73312c5fef98534 (patch)
treee54be16682aed5f44db86484517606c64fb5ab01 /Graphics/GraphicsEngineVulkan
parentAdded vertex buffer committing in Vk (diff)
downloadDiligentCore-5a56e75e2f3c7243eb040590e73312c5fef98534.tar.gz
DiligentCore-5a56e75e2f3c7243eb040590e73312c5fef98534.zip
Implemented dynamic resource write-discard mapping
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/CMakeLists.txt4
-rw-r--r--Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h50
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h23
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DynamicUploadHeap.h142
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h2
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h15
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanDynamicHeap.h130
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h1
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h29
-rw-r--r--Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp393
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp95
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DynamicUploadHeap.cpp171
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp32
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp41
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp168
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp4
16 files changed, 600 insertions, 700 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
index fff5b003..ef9273ab 100644
--- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt
+++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
@@ -11,7 +11,7 @@ set(INCLUDE
include/VulkanTypeConversions.h
include/DescriptorPoolManager.h
include/DeviceContextVkImpl.h
- include/DynamicUploadHeap.h
+ include/VulkanDynamicHeap.h
include/FramebufferCache.h
include/GenerateMips.h
include/pch.h
@@ -68,7 +68,7 @@ set(SRC
src/VulkanTypeConversions.cpp
src/DescriptorPoolManager.cpp
src/DeviceContextVkImpl.cpp
- src/DynamicUploadHeap.cpp
+ src/VulkanDynamicHeap.cpp
src/FramebufferCache.cpp
src/GenerateMips.cpp
src/PipelineLayout.cpp
diff --git a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h
index 15c9b226..97a86bc5 100644
--- a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h
@@ -30,7 +30,7 @@
#include "RenderDeviceVk.h"
#include "BufferBase.h"
#include "BufferViewVkImpl.h"
-#include "DynamicUploadHeap.h"
+#include "VulkanDynamicHeap.h"
#include "VulkanUtilities/VulkanObjectWrappers.h"
namespace Diligent
@@ -66,27 +66,6 @@ public:
void DbgVerifyDynamicAllocation(Uint32 ContextId);
#endif
- /*virtual IVkResource *GetVkBuffer(size_t &DataStartByteOffset, Uint32 ContextId)override final
- {
- auto *pVkResource = GetVkResource();
- if(pVkResource != nullptr)
- {
- VERIFY(m_Desc.Usage != USAGE_DYNAMIC || (m_Desc.BindFlags | (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) != 0, "Expected non-dynamic buffer or a buffer with SRV or UAV bind flags");
- DataStartByteOffset = 0;
- return pVkResource;
- }
- else
- {
- VERIFY(m_Desc.Usage == USAGE_DYNAMIC, "Dynamic buffer is expected");
-
-#ifdef _DEBUG
- DbgVerifyDynamicAllocation(ContextId);
-#endif
- DataStartByteOffset = m_DynamicData[ContextId].Offset;
- return m_DynamicData[ContextId].pBuffer;
- }
- }
- */
VkBuffer GetVkBuffer()const override final
{
@@ -95,47 +74,22 @@ public:
virtual void* GetNativeHandle()override final
{
- //VERIFY(GetVkResource() != nullptr, "The buffer is dynamic and has no pointer to Vk resource");
- //size_t DataStartByteOffset = 0;
auto VkBuffer = GetVkBuffer();
- //VERIFY(DataStartByteOffset == 0, "0 offset expected");
return VkBuffer;
}
virtual void SetAccessFlags(VkAccessFlags AccessFlags )override final{ m_AccessFlags = AccessFlags; }
VkAccessFlags GetAccessFlags()const{return m_AccessFlags;}
-/*
- Vk_GPU_VIRTUAL_ADDRESS GetGPUAddress(Uint32 ContextId)
- {
- if(m_Desc.Usage == USAGE_DYNAMIC)
- {
-#ifdef _DEBUG
- DbgVerifyDynamicAllocation(ContextId);
-#endif
- return m_DynamicData[ContextId].GPUAddress;
- }
- else
- {
- return GetVkResource()->GetGPUVirtualAddress();
- }
- }
-
- */
private:
virtual void CreateViewInternal( const struct BufferViewDesc &ViewDesc, IBufferView **ppView, bool bIsDefaultView )override;
VulkanUtilities::BufferViewWrapper CreateView(struct BufferViewDesc &ViewDesc);
VkAccessFlags m_AccessFlags = 0;
- /*
#ifdef _DEBUG
- std::vector< std::pair<MAP_TYPE, Uint32>, STDAllocatorRawMem<std::pair<MAP_TYPE, Uint32>> > m_DbgMapType;
+ std::vector< std::pair<MAP_TYPE, Uint32> > m_DbgMapType;
#endif
-
- friend class DeviceContextVkImpl;
- // Array of dynamic allocations for every device context
- std::vector<DynamicAllocation, STDAllocatorRawMem<DynamicAllocation> > m_DynamicData;*/
VulkanUtilities::BufferWrapper m_VulkanBuffer;
VulkanUtilities::DeviceMemoryWrapper m_BufferMemory;
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
index 17f8844c..799ccb31 100644
--- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
@@ -25,12 +25,14 @@
/// \file
/// Declaration of Diligent::DeviceContextVkImpl class
+#include <unordered_map>
#include "DeviceContextVk.h"
#include "DeviceContextBase.h"
#include "GenerateMips.h"
#include "VulkanUtilities/VulkanCommandBufferPool.h"
#include "VulkanUtilities/VulkanCommandBuffer.h"
+#include "VulkanDynamicHeap.h"
#ifdef _DEBUG
# define VERIFY_CONTEXT_BINDINGS
@@ -103,8 +105,6 @@ public:
}
#if 0
- virtual void TransitionBufferState(IBuffer *pBuffer, Vk_RESOURCE_STATES State)override final;
-
///// Clears the state caches. This function is called once per frame
///// (before present) to release all outstanding objects
///// that are only kept alive by references in the cache
@@ -122,9 +122,9 @@ public:
#endif
void GenerateMips(class TextureViewVkImpl *pTexView);
-#if 0
- struct DynamicAllocation AllocateDynamicSpace(size_t NumBytes);
-#endif
+ void* AllocateDynamicUploadSpace(BufferVkImpl* pBuffer, size_t NumBytes, size_t Alignment);
+ void CopyAndFreeDynamicUploadData(BufferVkImpl* pBuffer);
+
Uint32 GetContextId()const{return m_ContextId;}
size_t GetNumCommandsInCtx()const { return m_State.NumCommands; }
@@ -137,7 +137,6 @@ public:
private:
void CommitRenderPassAndFramebuffer(class PipelineStateVkImpl *pPipelineStateVk);
- void CommitVkIndexBuffer(VALUE_TYPE IndexType);
void CommitVkVertexBuffers();
void TransitionVkVertexBuffers();
void CommitRenderTargets();
@@ -158,17 +157,8 @@ private:
/// Flag indicating if currently committed index buffer is up to date
bool CommittedIBUpToDate = false;
- /// Format of the currently committed index buffer
- VALUE_TYPE CommittedIBFormat = VT_UNDEFINED;
- /// Offset in the currently committed index buffer
- Uint32 CommittedVkIndexDataStartOffset = 0;
- /// Currently committed index buffer
- VkBuffer CommittedVkIndexBuffer = VK_NULL_HANDLE;
-
Uint32 NumCommands = 0;
}m_State;
-
-
#if 0
@@ -177,7 +167,6 @@ private:
CComPtr<IVkCommandSignature> m_pDispatchIndirectSignature;
GenerateMipsHelper m_MipsGenerator;
- class DynamicUploadHeap* m_pUploadHeap = nullptr;
#endif
class ShaderResourceCacheVk *m_pCommittedResourceCache = nullptr;
#if 0
@@ -191,6 +180,8 @@ private:
std::vector<VkSemaphore> m_WaitSemaphores;
std::vector<VkPipelineStageFlags> m_WaitDstStageMasks;
std::vector<VkSemaphore> m_SignalSemaphores;
+
+ std::unordered_map<BufferVkImpl*, VulkanDynamicAllocation> m_UploadAllocations;
};
}
diff --git a/Graphics/GraphicsEngineVulkan/include/DynamicUploadHeap.h b/Graphics/GraphicsEngineVulkan/include/DynamicUploadHeap.h
deleted file mode 100644
index b6b24ed1..00000000
--- a/Graphics/GraphicsEngineVulkan/include/DynamicUploadHeap.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/* 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 "RingBuffer.h"
-
-namespace Diligent
-{
-
-// Constant blocks must be multiples of 16 constants @ 16 bytes each
-#define DEFAULT_ALIGN 256
-
-struct DynamicAllocation
-{
-#if 0
- DynamicAllocation(ID3D12Resource *pBuff = nullptr, size_t ThisOffset = 0, size_t ThisSize = 0)
- : pBuffer(pBuff), Offset(ThisOffset), Size(ThisSize) {}
-
- //CComPtr<ID3D12Resource> pBuffer; // The D3D buffer associated with this memory.
- ID3D12Resource *pBuffer = nullptr; // The D3D buffer associated with this memory.
- size_t Offset = 0; // Offset from start of buffer resource
- size_t Size = 0; // Reserved size of this allocation
- void* CPUAddress = 0; // The CPU-writeable address
- D3D12_GPU_VIRTUAL_ADDRESS GPUAddress = 0; // The GPU-visible address
-#ifdef _DEBUG
- Uint64 FrameNum = static_cast<Uint64>(-1);
-#endif
-#endif
-};
-
-class GPURingBuffer : public RingBuffer
-{
-public:
-#if 0
- GPURingBuffer(size_t MaxSize, IMemoryAllocator &Allocator, ID3D12Device *pd3d12Device, bool AllowCPUAccess);
-
- GPURingBuffer(GPURingBuffer&& rhs) :
- RingBuffer(std::move(rhs)),
- m_CpuVirtualAddress(rhs.m_CpuVirtualAddress),
- m_GpuVirtualAddress(rhs.m_GpuVirtualAddress),
- m_pBuffer(std::move(rhs.m_pBuffer))
- {
- rhs.m_CpuVirtualAddress = nullptr;
- rhs.m_GpuVirtualAddress = 0;
- rhs.m_pBuffer.Release();
- }
-
- GPURingBuffer& operator =(GPURingBuffer&& rhs)
- {
- Destroy();
-
- static_cast<RingBuffer&>(*this) = std::move(rhs);
- m_CpuVirtualAddress = rhs.m_CpuVirtualAddress;
- m_GpuVirtualAddress = rhs.m_GpuVirtualAddress;
- m_pBuffer = std::move(rhs.m_pBuffer);
- rhs.m_CpuVirtualAddress = 0;
- rhs.m_GpuVirtualAddress = 0;
-
- return *this;
- }
-
- ~GPURingBuffer();
-
- DynamicAllocation Allocate(size_t SizeInBytes)
- {
- auto Offset = RingBuffer::Allocate(SizeInBytes);
- if (Offset != RingBuffer::InvalidOffset)
- {
- DynamicAllocation DynAlloc(m_pBuffer, Offset, SizeInBytes);
- DynAlloc.GPUAddress = m_GpuVirtualAddress + Offset;
- DynAlloc.CPUAddress = m_CpuVirtualAddress;
- if(DynAlloc.CPUAddress)
- DynAlloc.CPUAddress = reinterpret_cast<char*>(DynAlloc.CPUAddress) + Offset;
- return DynAlloc;
- }
- else
- {
- return DynamicAllocation(nullptr, 0, 0);
- }
- }
-
- GPURingBuffer(const GPURingBuffer&) = delete;
- GPURingBuffer& operator =(GPURingBuffer&) = delete;
-
-private:
- void Destroy();
-
- void* m_CpuVirtualAddress;
- D3D12_GPU_VIRTUAL_ADDRESS m_GpuVirtualAddress;
- CComPtr<ID3D12Resource> m_pBuffer;
-#endif
-};
-
-class DynamicUploadHeap
-{
-public:
-#if 0
- DynamicUploadHeap(IMemoryAllocator &Allocator, bool bIsCPUAccessible, class RenderDeviceD3D12Impl* pDevice, size_t InitialSize);
-
- DynamicUploadHeap(const DynamicUploadHeap&)=delete;
- DynamicUploadHeap(DynamicUploadHeap&&)=delete;
- DynamicUploadHeap& operator=(const DynamicUploadHeap&)=delete;
- DynamicUploadHeap& operator=(DynamicUploadHeap&&)=delete;
-
- DynamicAllocation Allocate( size_t SizeInBytes, size_t Alignment = DEFAULT_ALIGN );
-
- void FinishFrame(Uint64 FenceValue, Uint64 LastCompletedFenceValue);
-
-private:
- const bool m_bIsCPUAccessible;
- // When a chunk of dynamic memory is requested, the heap first tries to allocate the memory in the largest GPU buffer.
- // If allocation fails, a new ring buffer is created that provides enough space and requests memory from that buffer.
- // Only the largest buffer is used for allocation and all other buffers are released when GPU is done with corresponding frames
- std::vector<GPURingBuffer, STDAllocatorRawMem<GPURingBuffer> > m_RingBuffers;
- IMemoryAllocator &m_Allocator;
- RenderDeviceD3D12Impl* m_pDeviceD3D12 = nullptr;
- //std::mutex m_Mutex;
-#endif
-};
-
-}
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h
index b857054c..44950419 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h
@@ -133,6 +133,8 @@ private:
VulkanUtilities::RenderPassWrapper m_RenderPass;
VulkanUtilities::PipelineWrapper m_Pipeline;
PipelineLayout m_PipelineLayout;
+ bool m_HasStaticResources = false;
+ bool m_HasNonStaticResources = false;
};
}
diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h
index d89d6e71..c44b97f2 100644
--- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h
@@ -31,7 +31,7 @@
#include "RenderDeviceBase.h"
#include "DescriptorPoolManager.h"
#include "CommandContext.h"
-#include "DynamicUploadHeap.h"
+#include "VulkanDynamicHeap.h"
#include "Atomics.h"
#include "CommandQueueVk.h"
#include "VulkanUtilities/VulkanInstance.h"
@@ -105,10 +105,6 @@ public:
void FinishFrame(bool ReleaseAllResources);
virtual void FinishFrame()override final { FinishFrame(false); }
- /*
- DynamicUploadHeap* RequestUploadHeap();
- void ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap);
- */
DescriptorPoolAllocation AllocateDescriptorSet(VkDescriptorSetLayout SetLayout)
{
@@ -121,6 +117,10 @@ public:
return m_DescriptorPools[1 + CtxId].Allocate(SetLayout);
}
+ VulkanDynamicAllocation AllocateDynamicUploadSpace(Uint32 CtxId, size_t Size, size_t Alignment)
+ {
+ return m_UploadHeaps[CtxId]->Allocate(Size, Alignment);
+ }
std::shared_ptr<const VulkanUtilities::VulkanInstance> GetVulkanInstance()const{return m_VulkanInstance;}
const VulkanUtilities::VulkanPhysicalDevice &GetPhysicalDevice(){return *m_PhysicalDevice;}
@@ -205,11 +205,8 @@ private:
std::vector<DescriptorPoolManager, STDAllocatorRawMem<DescriptorPoolManager> > m_DescriptorPools;
-#if 0
- std::mutex m_UploadHeapMutex;
- typedef std::unique_ptr<DynamicUploadHeap, STDDeleterRawMem<DynamicUploadHeap> > UploadHeapPoolElemType;
+ typedef std::unique_ptr<VulkanDynamicHeap, STDDeleterRawMem<VulkanDynamicHeap> > UploadHeapPoolElemType;
std::vector< UploadHeapPoolElemType, STDAllocatorRawMem<UploadHeapPoolElemType> > m_UploadHeaps;
-#endif
};
}
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanDynamicHeap.h b/Graphics/GraphicsEngineVulkan/include/VulkanDynamicHeap.h
new file mode 100644
index 00000000..791afbf9
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanDynamicHeap.h
@@ -0,0 +1,130 @@
+/* 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 "RingBuffer.h"
+#include "VulkanUtilities/VulkanLogicalDevice.h"
+#include "VulkanUtilities/VulkanObjectWrappers.h"
+
+namespace Diligent
+{
+
+// Constant blocks must be multiples of 16 constants @ 16 bytes each
+#define DEFAULT_ALIGN 256
+
+class RenderDeviceVkImpl;
+
+struct VulkanDynamicAllocation
+{
+ VulkanDynamicAllocation(VkBuffer _Buff, size_t _Offset, size_t _Size, void *_CPUAddress)
+ : vkBuffer(_Buff), Offset(_Offset), Size(_Size), CPUAddress(_CPUAddress)
+ {}
+
+ VkBuffer vkBuffer = VK_NULL_HANDLE; // Vulkan buffer associated with this memory.
+ size_t Offset = 0; // Offset from the start of the buffer resource
+ size_t Size = 0; // Reserved size of this allocation
+ void *CPUAddress = nullptr;
+#ifdef _DEBUG
+ Uint64 FrameNum = static_cast<Uint64>(-1);
+#endif
+};
+
+class VulkanRingBuffer : public RingBuffer
+{
+public:
+ VulkanRingBuffer(size_t MaxSize, IMemoryAllocator &Allocator, RenderDeviceVkImpl* pDeviceVk);
+
+ VulkanRingBuffer(VulkanRingBuffer&& rhs)noexcept :
+ RingBuffer(std::move(rhs)),
+ m_pDeviceVk(rhs.m_pDeviceVk),
+ m_VkBuffer(std::move(rhs.m_VkBuffer)),
+ m_CPUAddress(rhs.m_CPUAddress)
+ {
+ rhs.m_CPUAddress = nullptr;
+ }
+
+ VulkanRingBuffer (const VulkanRingBuffer&) = delete;
+ VulkanRingBuffer& operator= (VulkanRingBuffer&) = delete;
+ VulkanRingBuffer& operator= (VulkanRingBuffer&& rhs)
+ {
+ Destroy();
+
+ static_cast<RingBuffer&>(*this) = std::move(rhs);
+ m_pDeviceVk = rhs.m_pDeviceVk;
+ m_VkBuffer = std::move(rhs.m_VkBuffer);
+ m_CPUAddress = rhs.m_CPUAddress;
+ rhs.m_CPUAddress = nullptr;
+
+ return *this;
+ }
+
+ ~VulkanRingBuffer();
+
+ VulkanDynamicAllocation Allocate(size_t SizeInBytes)
+ {
+ auto Offset = RingBuffer::Allocate(SizeInBytes);
+ if (Offset != RingBuffer::InvalidOffset)
+ {
+ return VulkanDynamicAllocation {m_VkBuffer, Offset, SizeInBytes, m_CPUAddress + Offset};
+ }
+ else
+ {
+ return VulkanDynamicAllocation {nullptr, 0, 0, nullptr};
+ }
+ }
+
+private:
+ void Destroy();
+
+ RenderDeviceVkImpl* m_pDeviceVk;
+ VulkanUtilities::BufferWrapper m_VkBuffer;
+ VulkanUtilities::DeviceMemoryWrapper m_BufferMemory;
+ Uint8* m_CPUAddress;
+};
+
+class VulkanDynamicHeap
+{
+public:
+ VulkanDynamicHeap(IMemoryAllocator &Allocator, class RenderDeviceVkImpl* pDeviceVk, size_t InitialSize);
+
+ VulkanDynamicHeap (const VulkanDynamicHeap&) = delete;
+ VulkanDynamicHeap (VulkanDynamicHeap&&) = delete;
+ VulkanDynamicHeap& operator= (const VulkanDynamicHeap&) = delete;
+ VulkanDynamicHeap& operator= (VulkanDynamicHeap&&) = delete;
+
+ VulkanDynamicAllocation Allocate( size_t SizeInBytes, size_t Alignment = DEFAULT_ALIGN );
+
+ void FinishFrame(Uint64 FenceValue, Uint64 LastCompletedFenceValue);
+
+private:
+ // When a chunk of dynamic memory is requested, the heap first tries to allocate the memory in the largest GPU buffer.
+ // If allocation fails, a new ring buffer is created that provides enough space and requests memory from that buffer.
+ // Only the largest buffer is used for allocation and all other buffers are released when GPU is done with corresponding frames
+ std::vector<VulkanRingBuffer, STDAllocatorRawMem<VulkanRingBuffer> > m_RingBuffers;
+ IMemoryAllocator &m_Allocator;
+ RenderDeviceVkImpl* m_pDeviceVk = nullptr;
+ //std::mutex m_Mutex;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h
index 10dec2a7..cc2f794a 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h
@@ -44,7 +44,6 @@ void BlendStateDesc_To_VkBlendStateCI(const BlendStateDesc &BSDesc,
std::vector<VkPipelineColorBlendAttachmentState> &ColorBlendAttachments);
void InputLayoutDesc_To_VkVertexInputStateCI(const InputLayoutDesc& LayoutDesc,
- const std::array<Uint32, MaxBufferSlots>& Strides,
VkPipelineVertexInputStateCreateInfo &VertexInputStateCI,
std::array<VkVertexInputBindingDescription, iMaxLayoutElements>& BindingDescriptions,
std::array<VkVertexInputAttributeDescription, iMaxLayoutElements>& AttributeDescription);
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h
index 905e8400..22fa8286 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h
@@ -253,10 +253,15 @@ namespace VulkanUtilities
void BindIndexBuffer(VkBuffer Buffer, VkDeviceSize Offset, VkIndexType IndexType)
{
VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
- vkCmdBindIndexBuffer(m_VkCmdBuffer, Buffer, Offset, IndexType);
- m_State.IndexBuffer = Buffer;
- m_State.IndexBufferOffset = Offset;
- m_State.IndexType = IndexType;
+ if(m_State.IndexBuffer != Buffer ||
+ m_State.IndexBufferOffset != Offset ||
+ m_State.IndexType != IndexType)
+ {
+ vkCmdBindIndexBuffer(m_VkCmdBuffer, Buffer, Offset, IndexType);
+ m_State.IndexBuffer = Buffer;
+ m_State.IndexBufferOffset = Offset;
+ m_State.IndexType = IndexType;
+ }
}
void BindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets)
@@ -326,6 +331,20 @@ namespace VulkanUtilities
vkCmdBindDescriptorSets(m_VkCmdBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
}
+ void CopyBuffer(VkBuffer srcBuffer,
+ VkBuffer dstBuffer,
+ uint32_t regionCount,
+ const VkBufferCopy* pRegions)
+ {
+ VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
+ if(m_State.RenderPass != VK_NULL_HANDLE)
+ {
+ // Copy buffer operation must be performed outside of render pass.
+ EndRenderPass();
+ }
+ vkCmdCopyBuffer(m_VkCmdBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
+ }
+
void FlushBarriers();
void SetVkCmdBuffer(VkCommandBuffer VkCmdBuffer)
@@ -342,9 +361,9 @@ namespace VulkanUtilities
VkPipeline ComputePipeline = VK_NULL_HANDLE;
VkBuffer IndexBuffer = VK_NULL_HANDLE;
VkDeviceSize IndexBufferOffset = 0;
+ VkIndexType IndexType = VK_INDEX_TYPE_MAX_ENUM;
uint32_t FramebufferWidth = 0;
uint32_t FramebufferHeight = 0;
- VkIndexType IndexType = VK_INDEX_TYPE_MAX_ENUM;
};
const StateCache& GetState()const{return m_State;}
diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
index 8bd36c3e..32bf143c 100644
--- a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
@@ -40,12 +40,11 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters,
RenderDeviceVkImpl *pRenderDeviceVk,
const BufferDesc& BuffDesc,
const BufferData &BuffData /*= BufferData()*/) :
- TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BuffDesc, false)/*,
+ TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BuffDesc, false),
#ifdef _DEBUG
- m_DbgMapType(1 + pRenderDeviceVk->GetNumDeferredContexts(), std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1)), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<pair<MAP_TYPE,Uint32>>")),
+ m_DbgMapType(1 + pRenderDeviceVk->GetNumDeferredContexts()),
#endif
- m_DynamicData(BuffDesc.Usage == USAGE_DYNAMIC ? (1 + pRenderDeviceVk->GetNumDeferredContexts()) : 0, DynamicAllocation(), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>"))
- */
+ m_AccessFlags(0)
{
#define LOG_BUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Buffer \"", BuffDesc.Name ? BuffDesc.Name : "", "\": ", ##__VA_ARGS__);
@@ -68,198 +67,179 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters,
}
const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice();
- if(m_Desc.Usage == USAGE_DYNAMIC && (m_Desc.BindFlags & (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) == 0)
- {
- UNSUPPORTED("Dynamic buffers are not yet implemented");
- // Dynamic constant/vertex/index buffers are suballocated in the upload heap when Map() is called.
- // Dynamic buffers with SRV or UAV flags need to be allocated in GPU-only memory
- // Dynamic upload heap buffer is always in Vk_RESOURCE_STATE_GENERIC_READ state
-#if 0
- m_UsageState = Vk_RESOURCE_STATE_GENERIC_READ;
- VERIFY_EXPR(m_DynamicData.size() == 1 + pRenderDeviceVk->GetNumDeferredContexts());
-#endif
- }
- else
- {
- VkBufferCreateInfo VkBuffCI = {};
- VkBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- VkBuffCI.pNext = nullptr;
- VkBuffCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
- VkBuffCI.size = m_Desc.uiSizeInBytes;
- VkBuffCI.usage =
- VK_BUFFER_USAGE_TRANSFER_SRC_BIT | // The buffer can be used as the source of a transfer command
- VK_BUFFER_USAGE_TRANSFER_DST_BIT; // The buffer can be used as the destination of a transfer command
- if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS)
- VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- if (m_Desc.BindFlags & BIND_SHADER_RESOURCE)
- VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- if (m_Desc.BindFlags & BIND_VERTEX_BUFFER)
- VkBuffCI.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
- if (m_Desc.BindFlags & BIND_INDEX_BUFFER)
- VkBuffCI.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
- if (m_Desc.BindFlags & BIND_INDIRECT_DRAW_ARGS)
- VkBuffCI.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
- if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER)
- VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
-
- VkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // sharing mode of the buffer when it will be accessed by multiple queue families.
- VkBuffCI.queueFamilyIndexCount = 0; // number of entries in the pQueueFamilyIndices array
- VkBuffCI.pQueueFamilyIndices = nullptr; // list of queue families that will access this buffer
- // (ignored if sharingMode is not VK_SHARING_MODE_CONCURRENT).
-
- m_VulkanBuffer = LogicalDevice.CreateBuffer(VkBuffCI, m_Desc.Name);
-
- VkMemoryRequirements MemReqs = LogicalDevice.GetBufferMemoryRequirements(m_VulkanBuffer);
-
- VkMemoryAllocateInfo MemAlloc = {};
- MemAlloc.pNext = nullptr;
- MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- MemAlloc.allocationSize = MemReqs.size;
+
+ VkBufferCreateInfo VkBuffCI = {};
+ VkBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ VkBuffCI.pNext = nullptr;
+ VkBuffCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
+ VkBuffCI.size = m_Desc.uiSizeInBytes;
+ VkBuffCI.usage =
+ VK_BUFFER_USAGE_TRANSFER_SRC_BIT | // The buffer can be used as the source of a transfer command
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT; // The buffer can be used as the destination of a transfer command
+ if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS)
+ VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ if (m_Desc.BindFlags & BIND_SHADER_RESOURCE)
+ VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ if (m_Desc.BindFlags & BIND_VERTEX_BUFFER)
+ VkBuffCI.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ if (m_Desc.BindFlags & BIND_INDEX_BUFFER)
+ VkBuffCI.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ if (m_Desc.BindFlags & BIND_INDIRECT_DRAW_ARGS)
+ VkBuffCI.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
+ if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER)
+ VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+
+ VkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // sharing mode of the buffer when it will be accessed by multiple queue families.
+ VkBuffCI.queueFamilyIndexCount = 0; // number of entries in the pQueueFamilyIndices array
+ VkBuffCI.pQueueFamilyIndices = nullptr; // list of queue families that will access this buffer
+ // (ignored if sharingMode is not VK_SHARING_MODE_CONCURRENT).
+
+ m_VulkanBuffer = LogicalDevice.CreateBuffer(VkBuffCI, m_Desc.Name);
+
+ VkMemoryRequirements MemReqs = LogicalDevice.GetBufferMemoryRequirements(m_VulkanBuffer);
+
+ VkMemoryAllocateInfo MemAlloc = {};
+ MemAlloc.pNext = nullptr;
+ MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ MemAlloc.allocationSize = MemReqs.size;
- auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
+ auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
- VkMemoryPropertyFlags BufferMemoryFlags = 0;
- if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE)
- BufferMemoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
- else
- BufferMemoryFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ VkMemoryPropertyFlags BufferMemoryFlags = 0;
+ if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE)
+ BufferMemoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ else
+ BufferMemoryFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
- // memoryTypeBits is a bitmask and contains one bit set for every supported memory type for the resource.
- // Bit i is set if and only if the memory type i in the VkPhysicalDeviceMemoryProperties structure for the
- // physical device is supported for the resource.
- MemAlloc.memoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, BufferMemoryFlags);
- if(BufferMemoryFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
- {
- // There must be at least one memory type with the DEVICE_LOCAL_BIT bit set
- VERIFY(MemAlloc.memoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex,
- "Vulkan spec requires that memoryTypeBits member always contains "
- "at least one bit set corresponding to a VkMemoryType with a propertyFlags that has the "
- "VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT bit set (11.6)");
- }
- else if(MemAlloc.memoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex)
- {
- LOG_ERROR_AND_THROW("Failed to find suitable device memory type for a buffer");
- }
+ // memoryTypeBits is a bitmask and contains one bit set for every supported memory type for the resource.
+ // Bit i is set if and only if the memory type i in the VkPhysicalDeviceMemoryProperties structure for the
+ // physical device is supported for the resource.
+ MemAlloc.memoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, BufferMemoryFlags);
+ if(BufferMemoryFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
+ {
+ // There must be at least one memory type with the DEVICE_LOCAL_BIT bit set
+ VERIFY(MemAlloc.memoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex,
+ "Vulkan spec requires that memoryTypeBits member always contains "
+ "at least one bit set corresponding to a VkMemoryType with a propertyFlags that has the "
+ "VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT bit set (11.6)");
+ }
+ else if(MemAlloc.memoryTypeIndex == VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex)
+ {
+ LOG_ERROR_AND_THROW("Failed to find suitable device memory type for a buffer");
+ }
- {
- std::string MemoryName("Device local memory for buffer '");
- MemoryName += m_Desc.Name;
- MemoryName += '\'';
- m_BufferMemory = LogicalDevice.AllocateDeviceMemory(MemAlloc, MemoryName.c_str());
- }
+ {
+ std::string MemoryName("Device local memory for buffer '");
+ MemoryName += m_Desc.Name;
+ MemoryName += '\'';
+ m_BufferMemory = LogicalDevice.AllocateDeviceMemory(MemAlloc, MemoryName.c_str());
+ }
- auto err = LogicalDevice.BindBufferMemory(m_VulkanBuffer, m_BufferMemory, 0 /*offset*/);
- CHECK_VK_ERROR_AND_THROW(err, "Failed to bind buffer memory");
+ auto err = LogicalDevice.BindBufferMemory(m_VulkanBuffer, m_BufferMemory, 0 /*offset*/);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to bind buffer memory");
- bool bInitializeBuffer = (BuffData.pData != nullptr && BuffData.DataSize > 0);
- //if(bInitializeBuffer)
- // m_UsageState = Vk_RESOURCE_STATE_COPY_DEST;
+ bool bInitializeBuffer = (BuffData.pData != nullptr && BuffData.DataSize > 0);
+ //if(bInitializeBuffer)
+ // m_UsageState = Vk_RESOURCE_STATE_COPY_DEST;
- if( bInitializeBuffer )
- {
- m_AccessFlags = VK_ACCESS_TRANSFER_WRITE_BIT;
+ if( bInitializeBuffer )
+ {
+ m_AccessFlags = VK_ACCESS_TRANSFER_WRITE_BIT;
- VkBufferCreateInfo VkStaginBuffCI = VkBuffCI;
- VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ VkBufferCreateInfo VkStaginBuffCI = VkBuffCI;
+ VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
- std::string StagingBufferName = "Staging buffer for '";
- StagingBufferName += m_Desc.Name;
- StagingBufferName += '\'';
- VulkanUtilities::BufferWrapper StagingBuffer = LogicalDevice.CreateBuffer(VkStaginBuffCI, StagingBufferName.c_str());
+ std::string StagingBufferName = "Staging buffer for '";
+ StagingBufferName += m_Desc.Name;
+ StagingBufferName += '\'';
+ VulkanUtilities::BufferWrapper StagingBuffer = LogicalDevice.CreateBuffer(VkStaginBuffCI, StagingBufferName.c_str());
- VkMemoryRequirements StagingBufferMemReqs = LogicalDevice.GetBufferMemoryRequirements(StagingBuffer);
+ VkMemoryRequirements StagingBufferMemReqs = LogicalDevice.GetBufferMemoryRequirements(StagingBuffer);
- VkMemoryAllocateInfo StagingMemAlloc = {};
- StagingMemAlloc.pNext = nullptr;
- StagingMemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- StagingMemAlloc.allocationSize = StagingBufferMemReqs.size;
+ VkMemoryAllocateInfo StagingMemAlloc = {};
+ StagingMemAlloc.pNext = nullptr;
+ StagingMemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ StagingMemAlloc.allocationSize = StagingBufferMemReqs.size;
- // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges
- // and vkInvalidateMappedMemoryRanges are NOT needed to flush host writes to the device or make device writes visible
- // to the host (10.2)
- StagingMemAlloc.memoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(StagingBufferMemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
-
- VERIFY(StagingMemAlloc.memoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex,
- "Vulkan spec requires that for a VkBuffer not created with the "
- "VK_BUFFER_CREATE_SPARSE_BINDING_BIT bit set, 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)");
-
- std::string StagingMemoryName("Staging memory for buffer '");
- StagingMemoryName += m_Desc.Name;
- StagingMemoryName += '\'';
- VulkanUtilities::DeviceMemoryWrapper StagingBufferMemory = LogicalDevice.AllocateDeviceMemory(StagingMemAlloc, StagingMemoryName.c_str());
+ // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges
+ // and vkInvalidateMappedMemoryRanges are NOT needed to flush host writes to the device or make device writes visible
+ // to the host (10.2)
+ StagingMemAlloc.memoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(StagingBufferMemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+ VERIFY(StagingMemAlloc.memoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex,
+ "Vulkan spec requires that for a VkBuffer not created with the "
+ "VK_BUFFER_CREATE_SPARSE_BINDING_BIT bit set, 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)");
+
+ std::string StagingMemoryName("Staging memory for buffer '");
+ StagingMemoryName += m_Desc.Name;
+ StagingMemoryName += '\'';
+ VulkanUtilities::DeviceMemoryWrapper StagingBufferMemory = LogicalDevice.AllocateDeviceMemory(StagingMemAlloc, StagingMemoryName.c_str());
- {
- void *StagingData = nullptr;
- err = LogicalDevice.MapMemory(StagingBufferMemory,
- 0, // offset
- StagingMemAlloc.allocationSize,
- 0, // flags, reserved for future use
- &StagingData);
- CHECK_VK_ERROR_AND_THROW(err, "Failed to map staging memory");
- memcpy(StagingData, BuffData.pData, BuffData.DataSize);
- LogicalDevice.UnmapMemory(StagingBufferMemory);
- }
+ {
+ void *StagingData = nullptr;
+ err = LogicalDevice.MapMemory(StagingBufferMemory,
+ 0, // offset
+ StagingMemAlloc.allocationSize,
+ 0, // flags, reserved for future use
+ &StagingData);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to map staging memory");
+ memcpy(StagingData, BuffData.pData, BuffData.DataSize);
+ LogicalDevice.UnmapMemory(StagingBufferMemory);
+ }
- err = LogicalDevice.BindBufferMemory(StagingBuffer, StagingBufferMemory, 0 /*offset*/);
- CHECK_VK_ERROR_AND_THROW(err, "Failed to bind staging bufer memory");
+ err = LogicalDevice.BindBufferMemory(StagingBuffer, StagingBufferMemory, 0 /*offset*/);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to bind staging bufer memory");
- auto vkCmdBuff = pRenderDeviceVk->AllocateCommandBuffer("Transient cmd buff to copy staging data to a device buffer");
+ auto vkCmdBuff = pRenderDeviceVk->AllocateCommandBuffer("Transient cmd buff to copy staging data to a device buffer");
#if 0
- // copy data to the intermediate upload heap and then schedule a copy from the upload heap to the default buffer
- VERIFY_EXPR(m_UsageState == Vk_RESOURCE_STATE_COPY_DEST);
+ // copy data to the intermediate upload heap and then schedule a copy from the upload heap to the default buffer
+ VERIFY_EXPR(m_UsageState == Vk_RESOURCE_STATE_COPY_DEST);
#endif
- // We MUST NOT call TransitionResource() from here, because
- // it will call AddRef() and potentially Release(), while
- // the object is not constructed yet
-
- // Copy commands MUST be recorded outside of a render pass instance. This is OK here
- // as copy will be the only command in the cmd buffer
- VkBufferCopy BuffCopy = {};
- BuffCopy.srcOffset = 0;
- BuffCopy.dstOffset = 0;
- BuffCopy.size = VkBuffCI.size;
- vkCmdCopyBuffer(vkCmdBuff, StagingBuffer, m_VulkanBuffer, 1, &BuffCopy);
-
- // Command list fence should only be signaled when submitting cmd list
- // from the immediate context, otherwise the basic requirement will be violated
- // as in the scenario below
- // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/
- //
- // Signaled Fence | Immediate Context | InitContext |
- // | | |
- // N | Draw(ResourceX) | |
- // | Release(ResourceX) | |
- // | - (ResourceX, N) -> Release Queue | |
- // | | CopyResource() |
- // N+1 | | CloseAndExecuteCommandContext() |
- // | | |
- // N+2 | CloseAndExecuteCommandContext() | |
- // | - Cmd list is submitted with number | |
- // | N+1, but resource it references | |
- // | was added to the delete queue | |
- // | with value N | |
- pRenderDeviceVk->ExecuteCommandBuffer(vkCmdBuff, false);
- pRenderDeviceVk->DisposeCommandBuffer(vkCmdBuff);
-
- // Add reference to the object to the release queue to keep it alive
- // until copy operation is complete. This must be done after
- // submitting command list for execution!
- pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingBuffer));
- pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingBufferMemory));
- }
- else
- {
- m_AccessFlags = 0;
- }
-
- //if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER)
- //{
- // m_CBVDescriptorAllocation = pRenderDeviceVk->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
- // CreateCBV(m_CBVDescriptorAllocation.GetCpuHandle());
- //}
+ // We MUST NOT call TransitionResource() from here, because
+ // it will call AddRef() and potentially Release(), while
+ // the object is not constructed yet
+
+ // Copy commands MUST be recorded outside of a render pass instance. This is OK here
+ // as copy will be the only command in the cmd buffer
+ VkBufferCopy BuffCopy = {};
+ BuffCopy.srcOffset = 0;
+ BuffCopy.dstOffset = 0;
+ BuffCopy.size = VkBuffCI.size;
+ vkCmdCopyBuffer(vkCmdBuff, StagingBuffer, m_VulkanBuffer, 1, &BuffCopy);
+
+ // Command list fence should only be signaled when submitting cmd list
+ // from the immediate context, otherwise the basic requirement will be violated
+ // as in the scenario below
+ // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/
+ //
+ // Signaled Fence | Immediate Context | InitContext |
+ // | | |
+ // N | Draw(ResourceX) | |
+ // | Release(ResourceX) | |
+ // | - (ResourceX, N) -> Release Queue | |
+ // | | CopyResource() |
+ // N+1 | | CloseAndExecuteCommandContext() |
+ // | | |
+ // N+2 | CloseAndExecuteCommandContext() | |
+ // | - Cmd list is submitted with number | |
+ // | N+1, but resource it references | |
+ // | was added to the delete queue | |
+ // | with value N | |
+ pRenderDeviceVk->ExecuteCommandBuffer(vkCmdBuff, false);
+ pRenderDeviceVk->DisposeCommandBuffer(vkCmdBuff);
+
+ // Add reference to the object to the release queue to keep it alive
+ // until copy operation is complete. This must be done after
+ // submitting command list for execution!
+ pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingBuffer));
+ pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingBufferMemory));
+ }
+ else
+ {
+ m_AccessFlags = 0;
}
}
@@ -307,16 +287,15 @@ static BufferDesc BufferDescFromVkResource(BufferDesc BuffDesc, void *pVkBuffer)
}
BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters,
- FixedBlockMemoryAllocator &BuffViewObjMemAllocator,
- RenderDeviceVkImpl *pRenderDeviceVk,
- const BufferDesc& BuffDesc,
- void *pVkBuffer) :
- TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BufferDescFromVkResource(BuffDesc, pVkBuffer), false)/*,
+ FixedBlockMemoryAllocator &BuffViewObjMemAllocator,
+ RenderDeviceVkImpl *pRenderDeviceVk,
+ const BufferDesc& BuffDesc,
+ void *pVkBuffer) :
+ TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BufferDescFromVkResource(BuffDesc, pVkBuffer), false),
#ifdef _DEBUG
- m_DbgMapType(1 + pRenderDeviceVk->GetNumDeferredContexts(), std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1)), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<pair<MAP_TYPE,Uint32>>")),
+ m_DbgMapType(1 + pRenderDeviceVk->GetNumDeferredContexts()),
#endif
- m_DynamicData(BuffDesc.Usage == USAGE_DYNAMIC ? (1 + pRenderDeviceVk->GetNumDeferredContexts()) : 0, DynamicAllocation(), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>"))
- */
+ m_AccessFlags(0)
{
#if 0
m_pVkResource = pVkBuffer;
@@ -362,7 +341,7 @@ void BufferVkImpl :: CopyData(IDeviceContext *pContext, IBuffer *pSrcBuffer, Uin
void BufferVkImpl :: Map(IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags, PVoid &pMappedData)
{
TBufferBase::Map( pContext, MapType, MapFlags, pMappedData );
-#if 0
+
auto *pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pContext);
#ifdef _DEBUG
if(pDeviceContextVk != nullptr)
@@ -370,6 +349,8 @@ void BufferVkImpl :: Map(IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapF
#endif
if (MapType == MAP_READ )
{
+ UNSUPPORTED("Mapping buffer for reading is not yet imlemented");
+#if 0
LOG_WARNING_MESSAGE_ONCE("Mapping CPU buffer for reading on Vk currently requires flushing context and idling GPU");
pDeviceContextVk->Flush();
auto *pDeviceVk = ValidatedCast<RenderDeviceVkImpl>(GetDevice());
@@ -380,25 +361,26 @@ void BufferVkImpl :: Map(IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapF
MapRange.Begin = 0;
MapRange.End = m_Desc.uiSizeInBytes;
m_pVkResource->Map(0, &MapRange, &pMappedData);
+#endif
}
else if(MapType == MAP_WRITE)
{
if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE)
{
+ UNSUPPORTED("Not implemented");
+#if 0
VERIFY(m_pVkResource != nullptr, "USAGE_CPU_ACCESSIBLE buffer mapped for writing must intialize Vk resource");
if (MapFlags & MAP_FLAG_DISCARD)
{
}
m_pVkResource->Map(0, nullptr, &pMappedData);
+#endif
}
else if (m_Desc.Usage == USAGE_DYNAMIC)
{
VERIFY(MapFlags & MAP_FLAG_DISCARD, "Vk buffer must be mapped for writing with MAP_FLAG_DISCARD flag");
- auto *pCtxVk = ValidatedCast<DeviceContextVkImpl>(pContext);
- auto ContextId = pDeviceContextVk->GetContextId();
- m_DynamicData[ContextId] = pCtxVk->AllocateDynamicSpace(m_Desc.uiSizeInBytes);
- pMappedData = m_DynamicData[ContextId].CPUAddress;
+ pMappedData = pDeviceContextVk->AllocateDynamicUploadSpace(this, m_Desc.uiSizeInBytes, 0);
}
else
{
@@ -413,17 +395,15 @@ void BufferVkImpl :: Map(IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapF
{
LOG_ERROR("Only MAP_WRITE_DISCARD and MAP_READ are currently implemented in Vk");
}
-#endif
}
void BufferVkImpl::Unmap( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags )
{
TBufferBase::Unmap( pContext, MapType, MapFlags );
-#if 0
auto *pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pContext);
- Uint32 CtxId = pDeviceContextVk != nullptr ? pDeviceContextVk->GetContextId() : static_cast<Uint32>(-1);
#ifdef _DEBUG
+ Uint32 CtxId = pDeviceContextVk != nullptr ? pDeviceContextVk->GetContextId() : static_cast<Uint32>(-1);
if (pDeviceContextVk != nullptr)
{
VERIFY(m_DbgMapType[CtxId].first == MapType, "Map type does not match the type provided to Map()");
@@ -433,27 +413,29 @@ void BufferVkImpl::Unmap( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 Map
if (MapType == MAP_READ )
{
+ UNSUPPORTED("This map type is not yet supported");
+#if 0
Vk_RANGE MapRange;
// It is valid to specify the CPU didn't write any data by passing a range where End is less than or equal to Begin.
MapRange.Begin = 1;
MapRange.End = 0;
m_pVkResource->Unmap(0, &MapRange);
+#endif
}
else if(MapType == MAP_WRITE)
{
if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE)
{
+ UNSUPPORTED("This map type is not yet supported");
+#if 0
VERIFY(m_pVkResource != nullptr, "USAGE_CPU_ACCESSIBLE buffer mapped for writing must intialize Vk resource");
m_pVkResource->Unmap(0, nullptr);
+#endif
}
else if (m_Desc.Usage == USAGE_DYNAMIC)
{
VERIFY(MapFlags & MAP_FLAG_DISCARD, "Vk buffer must be mapped for writing with MAP_FLAG_DISCARD flag");
- // Copy data into the resource
- if (m_pVkResource)
- {
- pDeviceContextVk->UpdateBufferRegion(this, m_DynamicData[CtxId], 0, m_Desc.uiSizeInBytes);
- }
+ pDeviceContextVk->CopyAndFreeDynamicUploadData(this);
}
}
@@ -461,7 +443,6 @@ void BufferVkImpl::Unmap( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 Map
if(pDeviceContextVk != nullptr)
m_DbgMapType[CtxId] = std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1));
#endif
-#endif
}
void BufferVkImpl::CreateViewInternal( const BufferViewDesc &OrigViewDesc, IBufferView **ppView, bool bIsDefaultView )
@@ -520,16 +501,4 @@ VulkanUtilities::BufferViewWrapper BufferVkImpl::CreateView(struct BufferViewDes
return BuffView;
}
-#if 0
-#ifdef _DEBUG
-void BufferVkImpl::DbgVerifyDynamicAllocation(Uint32 ContextId)
-{
- VERIFY(m_DynamicData[ContextId].GPUAddress != 0, "Dynamic buffer must be mapped before the first use");
- auto CurrentFrame = ValidatedCast<RenderDeviceVkImpl>(GetDevice())->GetCurrentFrameNumber();
- VERIFY(m_DynamicData[ContextId].FrameNum == CurrentFrame, "Dynamic allocation is out-of-date. Dynamic buffer \"", m_Desc.Name, "\" must be mapped in the same frame it is used.");
- VERIFY(GetState() == Vk_RESOURCE_STATE_GENERIC_READ, "Dynamic buffers are expected to always be in Vk_RESOURCE_STATE_GENERIC_READ state");
-}
-#endif
-
-#endif
}
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
index 78291140..f8e87c77 100644
--- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -30,7 +30,6 @@
#include "TextureVkImpl.h"
#include "BufferVkImpl.h"
#include "VulkanTypeConversions.h"
-#include "DynamicUploadHeap.h"
#include "CommandListVkImpl.h"
namespace Diligent
@@ -38,7 +37,6 @@ namespace Diligent
DeviceContextVkImpl::DeviceContextVkImpl( IReferenceCounters *pRefCounters, RenderDeviceVkImpl *pDeviceVkImpl, bool bIsDeferred, const EngineVkAttribs &Attribs, Uint32 ContextId) :
TDeviceContextBase(pRefCounters, pDeviceVkImpl, bIsDeferred),
- //m_pUploadHeap(pDeviceVkImpl->RequestUploadHeap() ),
m_NumCommandsToFlush(bIsDeferred ? std::numeric_limits<decltype(m_NumCommandsToFlush)>::max() : Attribs.NumCommandsToFlushCmdBuffer),
/*m_MipsGenerator(pDeviceVkImpl->GetVkDevice()),
m_CmdListAllocator(GetRawAllocator(), sizeof(CommandListVkImpl), 64 ),*/
@@ -300,47 +298,6 @@ namespace Diligent
m_CommandBuffer.BeginRenderPass(Key.Pass, vkFramebuffer, m_FramebufferWidth, m_FramebufferHeight);
}
- void DeviceContextVkImpl::CommitVkIndexBuffer(VALUE_TYPE IndexType)
- {
- BufferVkImpl *pBuffVk = m_pIndexBuffer.RawPtr<BufferVkImpl>();
-
- // Device context keeps strong reference to bound index buffer.
- // When the buffer is unbound, the reference to the Vk resource
- // is added to the context. There is no need to add reference here
-
-// bool IsDynamic = pBuffVk->GetDesc().Usage == USAGE_DYNAMIC;
-//#ifdef _DEBUG
-// if(IsDynamic)
-// pBuffVk->DbgVerifyDynamicAllocation(m_ContextId);
-//#endif
-
- size_t BuffDataStartByteOffset = 0;
- auto *vkBuffer = pBuffVk->GetVkBuffer();
-
- if( //IsDynamic ||
- m_State.CommittedVkIndexBuffer != vkBuffer ||
- m_State.CommittedIBFormat != IndexType ||
- m_State.CommittedVkIndexDataStartOffset != m_IndexDataStartOffset + BuffDataStartByteOffset)
- {
- m_State.CommittedVkIndexBuffer = vkBuffer;
- m_State.CommittedIBFormat = IndexType;
- m_State.CommittedVkIndexDataStartOffset = m_IndexDataStartOffset + static_cast<Uint32>(BuffDataStartByteOffset);
- VkIndexType vkIndexType;
- if( IndexType == VT_UINT32 )
- vkIndexType = VK_INDEX_TYPE_UINT32;
- else
- {
- VERIFY(IndexType == VT_UINT16, "Unsupported index format. Only R16_UINT and R32_UINT are allowed.");
- vkIndexType = VK_INDEX_TYPE_UINT16;
- }
- m_CommandBuffer.BindIndexBuffer(m_State.CommittedVkIndexBuffer, m_State.CommittedVkIndexDataStartOffset, vkIndexType);
- }
-
- // GPU virtual address of a dynamic index buffer can change every time
- // a draw command is invoked
- m_State.CommittedIBUpToDate = true;//!IsDynamic;
- }
-
void DeviceContextVkImpl::TransitionVkVertexBuffers()
{
for( UINT Buff = 0; Buff < m_NumVertexStreams; ++Buff )
@@ -419,22 +376,18 @@ namespace Diligent
auto *pPipelineStateVk = m_pPipelineState.RawPtr<PipelineStateVkImpl>();
EnsureVkCmdBuffer();
- if(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE)
- CommitRenderPassAndFramebuffer(pPipelineStateVk);
if( DrawAttribs.IsIndexed )
{
VERIFY( m_pIndexBuffer != nullptr, "Index buffer is not set up for indexed draw command" );
- if( m_State.CommittedIBFormat != DrawAttribs.IndexType )
- m_State.CommittedIBUpToDate = false;
-
BufferVkImpl *pBuffVk = m_pIndexBuffer.RawPtr<BufferVkImpl>();
if(pBuffVk->GetAccessFlags() != VK_ACCESS_INDEX_READ_BIT)
BufferMemoryBarrier(*pBuffVk, VK_ACCESS_INDEX_READ_BIT);
- if(!m_State.CommittedIBUpToDate)
- CommitVkIndexBuffer(DrawAttribs.IndexType);
+ VERIFY(DrawAttribs.IndexType == VT_UINT16 || DrawAttribs.IndexType == VT_UINT32, "Unsupported index format. Only R16_UINT and R32_UINT are allowed.");
+ VkIndexType vkIndexType = DrawAttribs.IndexType == VT_UINT16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32;
+ m_CommandBuffer.BindIndexBuffer(pBuffVk->GetVkBuffer(), m_IndexDataStartOffset, vkIndexType);
}
if(m_State.CommittedVBsUpToDate)
@@ -457,6 +410,10 @@ namespace Diligent
}
#endif
#endif
+
+ if(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE)
+ CommitRenderPassAndFramebuffer(pPipelineStateVk);
+
if( DrawAttribs.IsIndirect )
{
#if 0
@@ -1174,4 +1131,42 @@ namespace Diligent
m_CommandBuffer.BufferMemoryBarrier(vkBuff, BufferVk.GetAccessFlags(), NewAccessFlags);
BufferVk.SetAccessFlags(NewAccessFlags);
}
+
+ void* DeviceContextVkImpl::AllocateDynamicUploadSpace(BufferVkImpl* pBuffer, size_t NumBytes, size_t Alignment)
+ {
+ 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;
+ m_UploadAllocations.emplace(pBuffer, std::move(UploadAllocation));
+ return CPUAddress;
+ }
+
+ void DeviceContextVkImpl::CopyAndFreeDynamicUploadData(BufferVkImpl* pBuffer)
+ {
+ auto it = m_UploadAllocations.find(pBuffer);
+ if(it != m_UploadAllocations.end())
+ {
+
+#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.");
+#endif
+ EnsureVkCmdBuffer();
+ if(pBuffer->GetAccessFlags() != VK_ACCESS_TRANSFER_WRITE_BIT)
+ {
+ BufferMemoryBarrier(*pBuffer, VK_ACCESS_TRANSFER_WRITE_BIT);
+ }
+ VkBufferCopy CopyRegion;
+ CopyRegion.srcOffset = it->second.Offset;
+ CopyRegion.dstOffset = 0;
+ CopyRegion.size = it->second.Size;
+ m_CommandBuffer.CopyBuffer(it->second.vkBuffer, pBuffer->GetVkBuffer(), 1, &CopyRegion);
+
+ m_UploadAllocations.erase(it);
+ }
+ else
+ {
+ UNEXPECTED("Unable to find dynamic allocation for this buffer");
+ }
+ }
}
diff --git a/Graphics/GraphicsEngineVulkan/src/DynamicUploadHeap.cpp b/Graphics/GraphicsEngineVulkan/src/DynamicUploadHeap.cpp
deleted file mode 100644
index ae01cc3e..00000000
--- a/Graphics/GraphicsEngineVulkan/src/DynamicUploadHeap.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/* 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 "DynamicUploadHeap.h"
-#include "RenderDeviceVkImpl.h"
-
-namespace Diligent
-{
-#if 0
- GPURingBuffer::GPURingBuffer(size_t MaxSize, IMemoryAllocator &Allocator, IVkDevice *pVkDevice, bool AllowCPUAccess) :
- RingBuffer(MaxSize, Allocator),
- m_CpuVirtualAddress(nullptr),
- m_GpuVirtualAddress(0)
- {
- Vk_HEAP_PROPERTIES HeapProps;
- HeapProps.CPUPageProperty = Vk_CPU_PAGE_PROPERTY_UNKNOWN;
- HeapProps.MemoryPoolPreference = Vk_MEMORY_POOL_UNKNOWN;
- HeapProps.CreationNodeMask = 1;
- HeapProps.VisibleNodeMask = 1;
-
- Vk_RESOURCE_DESC ResourceDesc;
- ResourceDesc.Dimension = Vk_RESOURCE_DIMENSION_BUFFER;
- ResourceDesc.Alignment = 0;
- ResourceDesc.Height = 1;
- ResourceDesc.DepthOrArraySize = 1;
- ResourceDesc.MipLevels = 1;
- ResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
- ResourceDesc.SampleDesc.Count = 1;
- ResourceDesc.SampleDesc.Quality = 0;
- ResourceDesc.Layout = Vk_TEXTURE_LAYOUT_ROW_MAJOR;
-
- Vk_RESOURCE_STATES DefaultUsage;
- if (AllowCPUAccess)
- {
- HeapProps.Type = Vk_HEAP_TYPE_UPLOAD;
- ResourceDesc.Flags = Vk_RESOURCE_FLAG_NONE;
- DefaultUsage = Vk_RESOURCE_STATE_GENERIC_READ;
- }
- else
- {
- HeapProps.Type = Vk_HEAP_TYPE_DEFAULT;
- ResourceDesc.Flags = Vk_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
- DefaultUsage = Vk_RESOURCE_STATE_UNORDERED_ACCESS;
- }
- ResourceDesc.Width = MaxSize;
-
- auto hr = pVkDevice->CreateCommittedResource(&HeapProps, Vk_HEAP_FLAG_NONE, &ResourceDesc,
- DefaultUsage, nullptr, __uuidof(m_pBuffer), reinterpret_cast<void**>(static_cast<IVkResource**>(&m_pBuffer)) );
- if(FAILED(hr))
- LOG_ERROR("Failed to create new upload ring buffer");
-
- m_pBuffer->SetName(L"Upload Ring Buffer");
-
- m_GpuVirtualAddress = m_pBuffer->GetGPUVirtualAddress();
-
- if (AllowCPUAccess)
- {
- m_pBuffer->Map(0, nullptr, &m_CpuVirtualAddress);
- }
-
- LOG_INFO_MESSAGE("GPU ring buffer created. Size: ", MaxSize, "; GPU virtual address 0x", std::hex, m_GpuVirtualAddress);
- }
-
- void GPURingBuffer::Destroy()
- {
- if(m_pBuffer)
- {
- LOG_INFO_MESSAGE("Destroying GPU ring buffer. Size: ", m_pBuffer->GetDesc().Width, "; GPU virtual address 0x", std::hex, m_GpuVirtualAddress);
- }
-
- if (m_CpuVirtualAddress)
- {
- m_pBuffer->Unmap(0, nullptr);
- }
- m_CpuVirtualAddress = 0;
- m_GpuVirtualAddress = 0;
- m_pBuffer.Release();
- }
-
- GPURingBuffer::~GPURingBuffer()
- {
- Destroy();
- }
-
- DynamicUploadHeap::DynamicUploadHeap(IMemoryAllocator &Allocator, bool bIsCPUAccessible, class RenderDeviceVkImpl* pDevice, size_t InitialSize) :
- m_Allocator(Allocator),
- m_pDeviceVk(pDevice),
- m_bIsCPUAccessible(bIsCPUAccessible),
- m_RingBuffers(STD_ALLOCATOR_RAW_MEM(GPURingBuffer, GetRawAllocator(), "Allocator for vector<GPURingBuffer>"))
- {
- m_RingBuffers.emplace_back(InitialSize, Allocator, pDevice->GetVkDevice(), m_bIsCPUAccessible);
- }
-
- DynamicAllocation DynamicUploadHeap::Allocate(size_t SizeInBytes, size_t Alignment /*= DEFAULT_ALIGN*/)
- {
- // Every device context has its own upload heap, so there is no need to lock
-
- //std::lock_guard<std::mutex> Lock(m_Mutex);
-
- //
- // Deferred contexts must not update resources or map dynamic buffers
- // across several frames!
- //
-
- const size_t AlignmentMask = Alignment - 1;
- // Assert that it's a power of two.
- VERIFY_EXPR((AlignmentMask & Alignment) == 0);
- // Align the allocation
- const size_t AlignedSize = (SizeInBytes + AlignmentMask) & ~AlignmentMask;
- auto DynAlloc = m_RingBuffers.back().Allocate(AlignedSize);
- if (!DynAlloc.pBuffer)
- {
- auto NewMaxSize = m_RingBuffers.back().GetMaxSize() * 2;
- while(NewMaxSize < AlignedSize)NewMaxSize*=2;
- m_RingBuffers.emplace_back(NewMaxSize, m_Allocator, m_pDeviceVk->GetVkDevice(), m_bIsCPUAccessible);
- DynAlloc = m_RingBuffers.back().Allocate(AlignedSize);
- }
-#ifdef _DEBUG
- DynAlloc.FrameNum = m_pDeviceVk->GetCurrentFrameNumber();
-#endif
- return DynAlloc;
- }
-
- void DynamicUploadHeap::FinishFrame(Uint64 FenceValue, Uint64 LastCompletedFenceValue)
- {
- // Every device context has its own upload heap, so there is no need to lock
- //std::lock_guard<std::mutex> Lock(m_Mutex);
-
- //
- // Deferred contexts must not update resources or map dynamic buffers
- // across several frames!
- //
-
- size_t NumBuffsToDelete = 0;
- for(size_t Ind = 0; Ind < m_RingBuffers.size(); ++Ind)
- {
- auto &RingBuff = m_RingBuffers[Ind];
- RingBuff.FinishCurrentFrame(FenceValue);
- RingBuff.ReleaseCompletedFrames(LastCompletedFenceValue);
- if ( NumBuffsToDelete == Ind && Ind < m_RingBuffers.size()-1 && RingBuff.IsEmpty())
- {
- ++NumBuffsToDelete;
- }
- }
-
- if(NumBuffsToDelete)
- m_RingBuffers.erase(m_RingBuffers.begin(), m_RingBuffers.begin()+NumBuffsToDelete);
- }
-#endif
-}
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
index ad575083..3cdd2b62 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
@@ -159,9 +159,9 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren
for(Uint32 s=0; s < m_NumShaders; ++s)
new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk(*this, LogicalDevice, GetRawAllocator());
- if (PipelineDesc.IsComputePipeline)
+ if (m_Desc.IsComputePipeline)
{
- auto &ComputePipeline = PipelineDesc.ComputePipeline;
+ auto &ComputePipeline = m_Desc.ComputePipeline;
if( ComputePipeline.pCS == nullptr )
LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc");
@@ -196,7 +196,7 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren
{
const auto &PhysicalDevice = pDeviceVk->GetPhysicalDevice();
- auto &GraphicsPipeline = PipelineDesc.GraphicsPipeline;
+ auto &GraphicsPipeline = m_Desc.GraphicsPipeline;
CreateRenderPass(LogicalDevice);
@@ -207,10 +207,6 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren
PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT;
#endif
-#if 0
- m_PipelineLayout.AllocateStaticSamplers(GetShaders(), GetNumShaders());
-#endif
-
PipelineCI.stageCount = m_NumShaders;
std::vector<VkPipelineShaderStageCreateInfo> Stages(PipelineCI.stageCount);
for (Uint32 s = 0; s < m_NumShaders; ++s)
@@ -247,7 +243,7 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren
VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {};
std::array<VkVertexInputBindingDescription, iMaxLayoutElements> BindingDescriptions;
std::array<VkVertexInputAttributeDescription, iMaxLayoutElements> AttributeDescription;
- InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, m_Strides, VertexInputStateCI, BindingDescriptions, AttributeDescription);
+ InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, VertexInputStateCI, BindingDescriptions, AttributeDescription);
PipelineCI.pVertexInputState = &VertexInputStateCI;
@@ -372,18 +368,21 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren
if(PipelineDesc.SRBAllocationGranularity > 1)
m_VariableDataAllocators.Init(m_NumShaders, PipelineDesc.SRBAllocationGranularity);
- bool HasStaticResources = false;
- bool HasNonStaticResources = false;
+ m_HasStaticResources = false;
+ m_HasNonStaticResources = false;
for (Uint32 s=0; s < m_NumShaders; ++s)
{
const auto &Layout = m_ShaderResourceLayouts[s];
- HasStaticResources = Layout.GetResourceCount(SHADER_VARIABLE_TYPE_STATIC) != 0;
- HasNonStaticResources = Layout.GetResourceCount(SHADER_VARIABLE_TYPE_MUTABLE) != 0 ||
- Layout.GetResourceCount(SHADER_VARIABLE_TYPE_DYNAMIC) != 0;
+ if(Layout.GetResourceCount(SHADER_VARIABLE_TYPE_STATIC) != 0)
+ m_HasStaticResources = true;
+
+ if(Layout.GetResourceCount(SHADER_VARIABLE_TYPE_MUTABLE) != 0 ||
+ Layout.GetResourceCount(SHADER_VARIABLE_TYPE_DYNAMIC) != 0)
+ m_HasNonStaticResources = true;
}
// If there are only static resources, create default shader resource binding
- if(HasStaticResources && !HasNonStaticResources)
+ if(m_HasStaticResources && !m_HasNonStaticResources)
{
auto &SRBAllocator = pDeviceVk->GetSRBAllocator();
// Default shader resource binding must be initialized after resource layouts are parsed!
@@ -497,8 +496,11 @@ ShaderResourceCacheVk* PipelineStateVkImpl::CommitAndTransitionShaderResources(I
bool CommitResources,
bool TransitionResources)const
{
+ if(!m_HasStaticResources && !m_HasNonStaticResources)
+ return nullptr;
+
#ifdef VERIFY_SHADER_BINDINGS
- if (pShaderResourceBinding == nullptr && !m_pDefaultShaderResBinding)
+ if (pShaderResourceBinding == nullptr && m_HasNonStaticResources)
{
LOG_ERROR_MESSAGE("Pipeline state \"", m_Desc.Name, "\" contains mutable/dynamic shader variables and requires shader resource binding to commit all resources, but none is provided.");
}
diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
index 899a72fa..b7ef1308 100644
--- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
@@ -58,7 +58,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<DynamicUploadHeap>>")),
+ m_UploadHeaps(STD_ALLOCATOR_RAW_MEM(UploadHeapPoolElemType, GetRawAllocator(), "Allocator for vector<unique_ptr<VulkanDynamicHeap>>")),
m_CmdBufferPool(m_LogicalVkDevice->GetSharedPtr(), pCmdQueue->GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT),
m_FramebufferCache(*this)
{
@@ -89,6 +89,7 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters,
true // Thread-safe
);
+ m_UploadHeaps.reserve(1 + NumDeferredContexts);
for(Uint32 ctx = 0; ctx < 1 + NumDeferredContexts; ++ctx)
{
m_DescriptorPools.emplace_back(
@@ -108,6 +109,18 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters,
CreationAttribs.DynamicDescriptorPoolSize.MaxDescriptorSets,
false // Dynamic descriptor pools need not to be thread-safe
);
+
+ {
+#ifdef _DEBUG
+ size_t InitialSize = 1024+64;
+#else
+ size_t InitialSize = 64<<10;//16<<20;
+#endif
+ 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) );
+ }
}
}
@@ -306,7 +319,6 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources)
Atomics::AtomicIncrement(m_NextCmdListNumber);
}
-#if 0
{
// There is no need to lock as new heaps are only created during initialization
// time for every context
@@ -336,7 +348,6 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources)
}
}
-#endif
{
// This is OK if other thread disposes descriptor heap allocation at this time
@@ -353,30 +364,6 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources)
Atomics::AtomicIncrement(m_FrameNumber);
}
-#if 0
-DynamicUploadHeap* RenderDeviceVkImpl::RequestUploadHeap()
-{
- std::lock_guard<std::mutex> LockGuard(m_UploadHeapMutex);
-
-#ifdef _DEBUG
- size_t InitialSize = 1024+64;
-#else
- size_t InitialSize = 64<<10;//16<<20;
-#endif
-
- auto &UploadHeapAllocator = GetRawAllocator();
- auto *pRawMem = ALLOCATE(UploadHeapAllocator, "DynamicUploadHeap instance", sizeof(DynamicUploadHeap));
- auto *pNewHeap = new (pRawMem) DynamicUploadHeap(GetRawAllocator(), true, this, InitialSize);
- m_UploadHeaps.emplace_back( pNewHeap, STDDeleterRawMem<DynamicUploadHeap>(UploadHeapAllocator) );
- return pNewHeap;
-}
-
-void RenderDeviceVkImpl::ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap)
-{
-
-}
-#endif
-
VkCommandBuffer RenderDeviceVkImpl::AllocateCommandBuffer(const Char *DebugName)
{
std::lock_guard<std::mutex> LockGuard(m_CmdPoolMutex);
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp
new file mode 100644
index 00000000..ae219873
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp
@@ -0,0 +1,168 @@
+/* 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 "VulkanDynamicHeap.h"
+#include "RenderDeviceVkImpl.h"
+
+namespace Diligent
+{
+VulkanRingBuffer::VulkanRingBuffer(size_t MaxSize, IMemoryAllocator &Allocator, RenderDeviceVkImpl* pDeviceVk) :
+ RingBuffer(MaxSize, Allocator),
+ m_pDeviceVk(pDeviceVk)
+{
+ VkBufferCreateInfo VkBuffCI = {};
+ VkBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ VkBuffCI.pNext = nullptr;
+ VkBuffCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
+ VkBuffCI.size = MaxSize;
+ VkBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ VkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ VkBuffCI.queueFamilyIndexCount = 0;
+ VkBuffCI.pQueueFamilyIndices = nullptr;
+
+ const auto& LogicalDevice = pDeviceVk->GetLogicalDevice();
+ m_VkBuffer = LogicalDevice.CreateBuffer(VkBuffCI, "Upload buffer");
+ VkMemoryRequirements MemReqs = LogicalDevice.GetBufferMemoryRequirements(m_VkBuffer);
+
+ const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice();
+
+ VkMemoryAllocateInfo MemAlloc = {};
+ MemAlloc.pNext = nullptr;
+ MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ MemAlloc.allocationSize = MemReqs.size;
+
+ // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges
+ // and vkInvalidateMappedMemoryRanges are NOT needed to flush host writes to the device or make device writes visible
+ // to the host (10.2)
+ MemAlloc.memoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+ VERIFY(MemAlloc.memoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex,
+ "Vulkan spec requires that for a VkBuffer not created with the "
+ "VK_BUFFER_CREATE_SPARSE_BINDING_BIT bit set, 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)");
+
+ m_BufferMemory = LogicalDevice.AllocateDeviceMemory(MemAlloc, "Host-visible memory for upload buffer");
+
+ void *Data = nullptr;
+ auto err = LogicalDevice.MapMemory(m_BufferMemory,
+ 0, // offset
+ MemAlloc.allocationSize,
+ 0, // flags, reserved for future use
+ &Data);
+ m_CPUAddress = reinterpret_cast<Uint8*>(Data);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to map memory");
+
+ err = LogicalDevice.BindBufferMemory(m_VkBuffer, m_BufferMemory, 0 /*offset*/);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to bind bufer memory");
+
+ LOG_INFO_MESSAGE("GPU ring buffer created. Size: ", MaxSize);
+}
+
+void VulkanRingBuffer::Destroy()
+{
+ if(m_VkBuffer)
+ {
+ LOG_INFO_MESSAGE("Destroying GPU ring buffer. Size: ", GetMaxSize());
+ m_pDeviceVk->GetLogicalDevice().UnmapMemory(m_BufferMemory);
+ m_pDeviceVk->SafeReleaseVkObject(std::move(m_VkBuffer));
+ m_pDeviceVk->SafeReleaseVkObject(std::move(m_BufferMemory));
+ }
+ m_CPUAddress = nullptr;
+}
+
+VulkanRingBuffer::~VulkanRingBuffer()
+{
+ Destroy();
+}
+
+
+VulkanDynamicHeap::VulkanDynamicHeap(IMemoryAllocator &Allocator, RenderDeviceVkImpl* pDevice, size_t InitialSize) :
+ m_Allocator(Allocator),
+ m_pDeviceVk(pDevice),
+ m_RingBuffers(STD_ALLOCATOR_RAW_MEM(VulkanRingBuffer, GetRawAllocator(), "Allocator for vector<VulkanRingBuffer>"))
+{
+ m_RingBuffers.emplace_back(InitialSize, Allocator, pDevice);
+}
+
+
+VulkanDynamicAllocation VulkanDynamicHeap::Allocate(size_t SizeInBytes, size_t Alignment /*= DEFAULT_ALIGN*/)
+{
+ if(Alignment == 0)
+ Alignment = DEFAULT_ALIGN;
+ // Every device context has its own upload heap, so there is no need to lock
+
+ //std::lock_guard<std::mutex> Lock(m_Mutex);
+
+ //
+ // Deferred contexts must not update resources or map dynamic buffers
+ // across several frames!
+ //
+
+ const size_t AlignmentMask = Alignment - 1;
+ // Assert that it's a power of two.
+ VERIFY_EXPR((AlignmentMask & Alignment) == 0);
+ // Align the allocation
+ const size_t AlignedSize = (SizeInBytes + AlignmentMask) & ~AlignmentMask;
+ auto DynAlloc = m_RingBuffers.back().Allocate(AlignedSize);
+ if (DynAlloc.vkBuffer == VK_NULL_HANDLE)
+ {
+ auto NewMaxSize = m_RingBuffers.back().GetMaxSize() * 2;
+ while(NewMaxSize < AlignedSize)NewMaxSize*=2;
+ m_RingBuffers.emplace_back(NewMaxSize, m_Allocator, m_pDeviceVk);
+ DynAlloc = m_RingBuffers.back().Allocate(AlignedSize);
+ }
+#ifdef _DEBUG
+ DynAlloc.FrameNum = m_pDeviceVk->GetCurrentFrameNumber();
+#endif
+ return DynAlloc;
+}
+
+void VulkanDynamicHeap::FinishFrame(Uint64 FenceValue, Uint64 LastCompletedFenceValue)
+{
+ // Every device context has its own upload heap, so there is no need to lock
+ //std::lock_guard<std::mutex> Lock(m_Mutex);
+
+ //
+ // Deferred contexts must not update resources or map dynamic buffers
+ // across several frames!
+ //
+
+ size_t NumBuffsToDelete = 0;
+ for(size_t Ind = 0; Ind < m_RingBuffers.size(); ++Ind)
+ {
+ auto &RingBuff = m_RingBuffers[Ind];
+ RingBuff.FinishCurrentFrame(FenceValue);
+ RingBuff.ReleaseCompletedFrames(LastCompletedFenceValue);
+ if ( NumBuffsToDelete == Ind && Ind < m_RingBuffers.size()-1 && RingBuff.IsEmpty())
+ {
+ ++NumBuffsToDelete;
+ }
+ }
+
+ if(NumBuffsToDelete)
+ m_RingBuffers.erase(m_RingBuffers.begin(), m_RingBuffers.begin()+NumBuffsToDelete);
+}
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
index ac04ec7c..95a64f3e 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
@@ -927,7 +927,6 @@ VkVertexInputRate LayoutElemFrequencyToVkInputRate(LayoutElement::FREQUENCY freq
}
void InputLayoutDesc_To_VkVertexInputStateCI(const InputLayoutDesc& LayoutDesc,
- const std::array<Uint32, MaxBufferSlots>& Strides,
VkPipelineVertexInputStateCreateInfo &VertexInputStateCI,
std::array<VkVertexInputBindingDescription, iMaxLayoutElements>& BindingDescriptions,
std::array<VkVertexInputAttributeDescription, iMaxLayoutElements>& AttributeDescription)
@@ -951,12 +950,13 @@ void InputLayoutDesc_To_VkVertexInputStateCI(const InputLayoutDesc& LayoutDesc,
BindingDescInd = VertexInputStateCI.vertexBindingDescriptionCount++;
auto &BindingDesc = BindingDescriptions[BindingDescInd];
BindingDesc.binding = LayoutElem.BufferSlot;
- BindingDesc.stride = Strides[LayoutElem.BufferSlot];
+ BindingDesc.stride = LayoutElem.Stride;
BindingDesc.inputRate = LayoutElemFrequencyToVkInputRate(LayoutElem.Frequency);
}
const auto &BindingDesc = BindingDescriptions[BindingDescInd];
VERIFY(BindingDesc.binding == LayoutElem.BufferSlot, "Inconsistent buffer slot");
+ VERIFY(BindingDesc.stride == LayoutElem.Stride, "Inconsistent strides");
VERIFY(BindingDesc.inputRate == LayoutElemFrequencyToVkInputRate(LayoutElem.Frequency), "Incosistent layout element frequency");
auto &AttribDesc = AttributeDescription[elem];