diff options
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
35 files changed, 1395 insertions, 580 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 6b71a279..2ceabf85 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -7,7 +7,6 @@ set(INCLUDE include/BufferViewVkImpl.h include/CommandContext.h include/CommandListVkImpl.h - include/CommandListManager.h include/CommandQueueVkImpl.h include/VulkanResourceBase.h include/VulkanTypeConversions.h @@ -34,8 +33,12 @@ set(INCLUDE ) set(VULKAN_UTILS_INCLUDE + include/VulkanUtilities/VulkanCommandBufferPool.h include/VulkanUtilities/VulkanDebug.h + include/VulkanUtilities/VulkanFencePool.h include/VulkanUtilities/VulkanInstance.h + include/VulkanUtilities/VulkanLogicalDevice.h + include/VulkanUtilities/VulkanObjectWrappers.h include/VulkanUtilities/VulkanPhysicalDevice.h ) @@ -61,7 +64,6 @@ set(SRC src/BufferVkImpl.cpp src/BufferViewVkImpl.cpp src/CommandContext.cpp - src/CommandListManager.cpp src/CommandQueueVkImpl.cpp src/VulkanResourceBase.cpp src/VulkanTypeConversions.cpp @@ -86,8 +88,11 @@ set(SRC ) set(VULKAN_UTILS_SRC + src/VulkanUtilities/VulkanCommandBufferPool.cpp src/VulkanUtilities/VulkanDebug.cpp + src/VulkanUtilities/VulkanFencePool.cpp src/VulkanUtilities/VulkanInstance.cpp + src/VulkanUtilities/VulkanLogicalDevice.cpp src/VulkanUtilities/VulkanPhysicalDevice.cpp ) diff --git a/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h b/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h index ff203851..71506640 100644 --- a/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h @@ -30,6 +30,7 @@ #include "RenderDeviceVk.h" #include "BufferViewBase.h" #include "DescriptorHeap.h" +#include "VulkanUtilities/VulkanObjectWrappers.h" namespace Diligent { @@ -45,16 +46,17 @@ public: IRenderDevice *pDevice, const BufferViewDesc& ViewDesc, class IBuffer *pBuffer, - VkBufferView vkBuffView, + VulkanUtilities::BufferViewWrapper &&BuffView, bool bIsDefaultView); + ~BufferViewVkImpl(); virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ); - virtual VkBufferView GetVkBufferView()override final{return m_VkBuffView;} + virtual VkBufferView GetVkBufferView()override final{return m_BuffView;} protected: - VkBufferView m_VkBuffView; + VulkanUtilities::BufferViewWrapper m_BuffView; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h index 2b70c416..31b58787 100644 --- a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h @@ -32,6 +32,7 @@ #include "BufferViewVkImpl.h" #include "VulkanResourceBase.h" #include "DynamicUploadHeap.h" +#include "VulkanUtilities/VulkanObjectWrappers.h" namespace Diligent { @@ -122,7 +123,7 @@ public: private: virtual void CreateViewInternal( const struct BufferViewDesc &ViewDesc, IBufferView **ppView, bool bIsDefaultView )override; - VkBufferView CreateView(struct BufferViewDesc &ViewDesc); + VulkanUtilities::BufferViewWrapper CreateView(struct BufferViewDesc &ViewDesc); /* DescriptorHeapAllocation m_CBVDescriptorAllocation; #ifdef _DEBUG @@ -132,8 +133,9 @@ private: friend class DeviceContextVkImpl; // Array of dynamic allocations for every device context std::vector<DynamicAllocation, STDAllocatorRawMem<DynamicAllocation> > m_DynamicData;*/ - VkBuffer m_VkBuffer = VK_NULL_HANDLE; - VkDeviceMemory m_BufferMemory = VK_NULL_HANDLE; + + VulkanUtilities::BufferWrapper m_VulkanBuffer; + VulkanUtilities::DeviceMemoryWrapper m_BufferMemory; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/CommandListManager.h b/Graphics/GraphicsEngineVulkan/include/CommandListManager.h deleted file mode 100644 index 461e7116..00000000 --- a/Graphics/GraphicsEngineVulkan/include/CommandListManager.h +++ /dev/null @@ -1,67 +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 <vector> -#include <deque> -#include <mutex> -#include <stdint.h> - -namespace Diligent -{ - -class CommandListManager -{ -public: - CommandListManager(class RenderDeviceVkImpl *pDeviceVk); - ~CommandListManager(); - - CommandListManager(const CommandListManager&) = delete; - CommandListManager(CommandListManager&&) = delete; - CommandListManager& operator = (const CommandListManager&) = delete; - CommandListManager& operator = (CommandListManager&&) = delete; - - /*void CreateNewCommandList( IVkGraphicsCommandList** ppList, IVkCommandAllocator** ppAllocator ); - - // Discards the allocator. - // FenceValue is the value that was signaled by the command queue after it - // executed the the command list created by the allocator - void DiscardAllocator( Uint64 FenceValue, IVkCommandAllocator* pAllocator ); - - void RequestAllocator(IVkCommandAllocator** ppAllocator); - -private: - // fist - the fence value associated with the command list that was created by the allocator - // second - the allocator to be discarded - typedef std::pair<Uint64, CComPtr<IVkCommandAllocator> > DiscardedAllocatorQueueElemType; - std::deque< DiscardedAllocatorQueueElemType, STDAllocatorRawMem<DiscardedAllocatorQueueElemType> > m_DiscardedAllocators; - - std::mutex m_AllocatorMutex; - RenderDeviceVkImpl *m_pDeviceVk; - - Atomics::AtomicLong m_NumAllocators = 0; // For debug purposes only - */ -}; - -}
\ No newline at end of file diff --git a/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h b/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h index c655b67d..bf8a2866 100644 --- a/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h @@ -26,9 +26,13 @@ /// \file /// Declaration of Diligent::CommandQueueVkImpl class +#include <mutex> +#include <deque> #include "vulkan.h" #include "CommandQueueVk.h" #include "ObjectBase.h" +#include "VulkanUtilities/VulkanLogicalDevice.h" +#include "VulkanUtilities/VulkanFencePool.h" namespace Diligent { @@ -39,43 +43,44 @@ class CommandQueueVkImpl : public ObjectBase<ICommandQueueVk> public: typedef ObjectBase<ICommandQueueVk> TBase; - CommandQueueVkImpl(IReferenceCounters *pRefCounters, VkQueue VkNativeCmdQueue, uint32_t QueueFamilyIndex); + CommandQueueVkImpl(IReferenceCounters *pRefCounters, + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> LogicalDevice, + uint32_t QueueFamilyIndex); ~CommandQueueVkImpl(); virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override; // Returns the fence value that will be signaled next time - //virtual UINT64 GetNextFenceValue()override final { return m_NextFenceValue; } + virtual UINT64 GetNextFenceValue()override final { return m_NextFenceValue; } - // Executes a given command list - //virtual UINT64 ExecuteCommandList(IVkGraphicsCommandList* commandList)override final; + // Executes a given command buffer + virtual Uint64 ExecuteCommandBuffer(VkCommandBuffer cmdBuffer)override final; virtual VkQueue GetVkQueue()override final{return m_VkQueue;} virtual uint32_t GetQueueFamilyIndex()override final { return m_QueueFamilyIndex; } + + virtual void IdleGPU()override final; - - //virtual void IdleGPU()override final; - - //virtual Uint64 GetCompletedFenceValue()override final; + virtual Uint64 GetCompletedFenceValue()override final; private: // A value that will be signaled by the command queue next - //Atomics::AtomicInt64 m_NextFenceValue; + Atomics::AtomicInt64 m_NextFenceValue; - // Last fence value completed by the GPU - //volatile Uint64 m_LastCompletedFenceValue = 0; + // Last fence value that is known to be completed by the GPU + volatile Uint64 m_LastCompletedFenceValue = 0; + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> m_LogicalDevice; + const VkQueue m_VkQueue; const uint32_t m_QueueFamilyIndex; -/* - // The fence is signaled right after the command list has been + VulkanUtilities::VulkanFencePool m_FencePool; + // Queue of fences signaled right after a command buffer has been // submitted to the command queue for execution. - // All command lists with fence value less or equal to the signaled value + // All command buffers with fence value less or equal to the signaled value // are guaranteed to be finished by the GPU - CComPtr<IVkFence> m_VkFence; - - HANDLE m_WaitForGPUEventHandle = {}; - */ + std::deque<std::pair<Uint64, VulkanUtilities::FenceWrapper>> m_PendingFences; + std::mutex m_QueueMutex; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h index d46806ae..98275f24 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h @@ -25,17 +25,20 @@ /// \file /// Declaration of Diligent::RenderDeviceVkImpl class +#include <memory> #include "RenderDeviceVk.h" #include "RenderDeviceBase.h" #include "DescriptorHeap.h" -#include "CommandListManager.h" #include "CommandContext.h" #include "DynamicUploadHeap.h" #include "Atomics.h" #include "CommandQueueVk.h" #include "VulkanUtilities/VulkanInstance.h" #include "VulkanUtilities/VulkanPhysicalDevice.h" +#include "VulkanUtilities/VulkanCommandBufferPool.h" +#include "VulkanUtilities/VulkanLogicalDevice.h" +#include "VulkanUtilities/VulkanObjectWrappers.h" /// Namespace for the Direct3D11 implementation of the graphics engine namespace Diligent @@ -53,7 +56,7 @@ public: ICommandQueueVk *pCmdQueue, std::shared_ptr<VulkanUtilities::VulkanInstance> Instance, std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> PhysicalDevice, - VkDevice vkLogicalDevice, + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> LogicalDevice, Uint32 NumDeferredContexts ); ~RenderDeviceVkImpl(); @@ -71,7 +74,7 @@ public: virtual void CreateSampler(const SamplerDesc& SamplerDesc, ISampler **ppSampler)override final; - //virtual IVkDevice* GetVkDevice()override final{return m_pVkDevice;} + virtual VkDevice GetVkDevice()override final{ return m_LogicalVkDevice->GetVkDevice();} //virtual void CreateTextureFromD3DResource(IVkResource *pVkTexture, ITexture **ppTexture)override final; @@ -80,7 +83,7 @@ public: /* DescriptorHeapAllocation AllocateDescriptor( Vk_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1 ); DescriptorHeapAllocation AllocateGPUDescriptors( Vk_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1 ); - +*/ Uint64 GetCompletedFenceValue(); virtual Uint64 GetNextFenceValue() override final { @@ -89,40 +92,39 @@ public: Uint64 GetCurrentFrameNumber()const {return static_cast<Uint64>(m_FrameNumber);} virtual Bool IsFenceSignaled(Uint64 FenceValue) override final; - */ + ICommandQueueVk *GetCmdQueue(){return m_pCommandQueue;} - /* - void IdleGPU(bool ReleaseStaleObjects); - CommandContext* AllocateCommandContext(const Char *ID = ""); - void CloseAndExecuteCommandContext(CommandContext *pCtx, bool DiscardStaleObjects); - void DisposeCommandContext(CommandContext*); -*/ - void SafeReleaseVkBuffer(VkBuffer vkBuffer); -/* + void IdleGPU(bool ReleaseStaleObjects); + VkCommandBuffer AllocateCommandBuffer(const Char *DebugName = nullptr); + void ExecuteCommandBuffer(VkCommandBuffer CmdBuff, bool DiscardStaleObjects); + void DisposeCommandBuffer(VkCommandBuffer CmdBuff); + + + template<typename VulkanObjectType> + void SafeReleaseVkObject(VulkanUtilities::VulkanObjectWrapper<VulkanObjectType>&& vkObject); + + void FinishFrame(bool ReleaseAllResources); virtual void FinishFrame()override final { FinishFrame(false); } - + /* DynamicUploadHeap* RequestUploadHeap(); void ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap); */ - - std::shared_ptr<VulkanUtilities::VulkanInstance> GetVulkanInstance(){return m_VulkanInstance;} + std::shared_ptr<const VulkanUtilities::VulkanInstance> GetVulkanInstance()const{return m_VulkanInstance;} const VulkanUtilities::VulkanPhysicalDevice &GetPhysicalDevice(){return *m_PhysicalDevice;} - VkDevice GetVkDevice()const{return m_VkDevice;} + const auto &GetLogicalDevice(){return *m_LogicalVkDevice;} private: - virtual void TestTextureFormat( TEXTURE_FORMAT TexFormat ); -#if 0 + virtual void TestTextureFormat( TEXTURE_FORMAT TexFormat )override final; void ProcessReleaseQueue(Uint64 CompletedFenceValue); void DiscardStaleVkObjects(Uint64 CmdListNumber, Uint64 FenceValue); -#endif + std::shared_ptr<VulkanUtilities::VulkanInstance> m_VulkanInstance; std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> m_PhysicalDevice; - - /// Vk device - VkDevice m_VkDevice = VK_NULL_HANDLE; + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> m_LogicalVkDevice; + RefCntAutoPtr<ICommandQueueVk> m_pCommandQueue; EngineVkAttribs m_EngineAttribs; @@ -132,12 +134,12 @@ private: // Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER == 1 const Uint32 m_DynamicDescriptorAllocationChunkSize[2]; - +#endif std::mutex m_CmdQueueMutex; Atomics::AtomicInt64 m_FrameNumber; Atomics::AtomicInt64 m_NextCmdListNumber; - +#if 0 // The following basic requirement guarantees correctness of resource deallocation: // // A resource is never released before the last draw command referencing it is invoked on the immediate context @@ -170,18 +172,29 @@ private: typedef std::unique_ptr<CommandContext, STDDeleterRawMem<CommandContext> > ContextPoolElemType; std::vector< ContextPoolElemType, STDAllocatorRawMem<ContextPoolElemType> > m_ContextPool; - - std::deque<CommandContext*, STDAllocatorRawMem<CommandContext*> > m_AvailableContexts; - std::mutex m_ContextAllocationMutex; + std::deque<CommandContext*, STDAllocatorRawMem<CommandContext*> > m_AvailableContexts; +#endif + + VulkanUtilities::VulkanCommandBufferPool m_CmdBufferPool; + std::mutex m_CmdPoolMutex; std::mutex m_ReleaseQueueMutex; - typedef std::pair<Uint64, CComPtr<IVkObject> > ReleaseQueueElemType; + + class StaleVulkanObjectBase + { + public: + virtual ~StaleVulkanObjectBase() = 0 {} + }; + template<typename VulkanObjectType> + class StaleVulkanObject; + + using ReleaseQueueElemType = std::pair<Uint64, std::unique_ptr<StaleVulkanObjectBase> >; std::deque< ReleaseQueueElemType, STDAllocatorRawMem<ReleaseQueueElemType> > m_VkObjReleaseQueue; -#endif + std::mutex m_StaleObjectsMutex; -#if 0 std::deque< ReleaseQueueElemType, STDAllocatorRawMem<ReleaseQueueElemType> > m_StaleVkObjects; +#if 0 std::mutex m_UploadHeapMutex; typedef std::unique_ptr<DynamicUploadHeap, STDDeleterRawMem<DynamicUploadHeap> > UploadHeapPoolElemType; std::vector< UploadHeapPoolElemType, STDAllocatorRawMem<UploadHeapPoolElemType> > m_UploadHeaps; diff --git a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h index 7b543619..bad8c1ed 100644 --- a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h @@ -64,7 +64,7 @@ public: private: void InitBuffersAndViews(); - std::shared_ptr<VulkanUtilities::VulkanInstance> m_VulkanInstance; + std::shared_ptr<const VulkanUtilities::VulkanInstance> m_VulkanInstance; VkSurfaceKHR m_VkSurface = VK_NULL_HANDLE; VkSwapchainKHR m_VkSwapChain = VK_NULL_HANDLE; VkFormat m_VkColorFormat = VK_FORMAT_UNDEFINED; diff --git a/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h index 911d1699..78dee56e 100644 --- a/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h @@ -29,6 +29,7 @@ #include "TextureViewVk.h" #include "RenderDeviceVk.h" #include "TextureViewBase.h" +#include "VulkanUtilities/VulkanObjectWrappers.h" namespace Diligent { @@ -44,18 +45,19 @@ public: IRenderDevice *pDevice, const TextureViewDesc& ViewDesc, class ITexture *pTexture, - VkImageView vkImgView, + VulkanUtilities::ImageViewWrapper &&ImgView, bool bIsDefaultView); + ~TextureViewVkImpl(); virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override; void GenerateMips( IDeviceContext *pContext )override; - VkImageView GetVulkanImageView()const{return m_VkImageView;} + VkImageView GetVulkanImageView()const{return m_ImageView;} protected: /// Vulkan image view descriptor handle - VkImageView m_VkImageView; + VulkanUtilities::ImageViewWrapper m_ImageView; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h index 3ca2e580..754a063d 100644 --- a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h @@ -77,15 +77,15 @@ public: */ void CopyData(IDeviceContext *pContext, - ITexture *pSrcTexture, - Uint32 SrcMipLevel, - Uint32 SrcSlice, - const Box *pSrcBox, - Uint32 DstMipLevel, - Uint32 DstSlice, - Uint32 DstX, - Uint32 DstY, - Uint32 DstZ); + ITexture *pSrcTexture, + Uint32 SrcMipLevel, + Uint32 SrcSlice, + const Box *pSrcBox, + Uint32 DstMipLevel, + Uint32 DstSlice, + Uint32 DstX, + Uint32 DstY, + Uint32 DstZ); /* Vk_CPU_DESCRIPTOR_HANDLE GetMipLevelUAV(Uint32 Mip) { @@ -114,7 +114,8 @@ protected: friend class RenderDeviceVkImpl; */ - VkImage m_VkImage; + VulkanUtilities::ImageWrapper m_VulkanImage; + VulkanUtilities::DeviceMemoryWrapper m_ImageMemory; const bool m_IsExternalHandle; }; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBufferPool.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBufferPool.h new file mode 100644 index 00000000..74e6bb35 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBufferPool.h @@ -0,0 +1,59 @@ +/* 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 <deque> +#include <memory> +#include "vulkan.h" +#include "VulkanLogicalDevice.h" +#include "VulkanObjectWrappers.h" + +namespace VulkanUtilities +{ + class VulkanCommandBufferPool + { + public: + VulkanCommandBufferPool(std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> LogicalDevice, + uint32_t queueFamilyIndex, + VkCommandPoolCreateFlags flags); + VulkanCommandBufferPool(const VulkanCommandBufferPool&) = delete; + VulkanCommandBufferPool(VulkanCommandBufferPool&&) = delete; + VulkanCommandBufferPool& operator = (const VulkanCommandBufferPool&) = delete; + VulkanCommandBufferPool& operator = (VulkanCommandBufferPool&&) = delete; + ~VulkanCommandBufferPool(); + + VkCommandBuffer GetCommandBuffer(uint64_t LastCompletedFence, const char* DebugName = ""); + void DisposeCommandBuffer(VkCommandBuffer CmdBuffer, uint64_t FenceValue); + + private: + // Shared point to logical device must be defined before the command pool + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> m_LogicalDevice; + CommandPoolWrapper m_CmdPool; + + // fist - the fence value associated with the command buffer when it was executed + // second - the command buffer + typedef std::pair<uint64_t, VkCommandBuffer > QueueElemType; + std::deque< QueueElemType > m_DiscardedCmdBuffers; + }; +} diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDebug.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDebug.h index bd213544..a68a56f2 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDebug.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDebug.h @@ -60,11 +60,14 @@ namespace VulkanUtilities //void EndRegion(VkCommandBuffer cmdBuffer); // Object specific naming functions + void SetCommandPoolName(VkDevice device, VkCommandPool cmdPool, const char * name); void SetCommandBufferName(VkDevice device, VkCommandBuffer cmdBuffer, const char * name); void SetQueueName(VkDevice device, VkQueue queue, const char * name); void SetImageName(VkDevice device, VkImage image, const char * name); + void SetImageViewName(VkDevice device, VkImageView imageView, const char * name); void SetSamplerName(VkDevice device, VkSampler sampler, const char * name); void SetBufferName(VkDevice device, VkBuffer buffer, const char * name); + void SetBufferViewName(VkDevice device, VkBufferView bufferView, const char * name); void SetDeviceMemoryName(VkDevice device, VkDeviceMemory memory, const char * name); void SetShaderModuleName(VkDevice device, VkShaderModule shaderModule, const char * name); void SetPipelineName(VkDevice device, VkPipeline pipeline, const char * name); diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanFencePool.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanFencePool.h new file mode 100644 index 00000000..3e4f5168 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanFencePool.h @@ -0,0 +1,52 @@ +/* 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 <vector> +#include <memory> +#include "vulkan.h" +#include "VulkanLogicalDevice.h" +#include "VulkanUtilities/VulkanObjectWrappers.h" + +namespace VulkanUtilities +{ + class VulkanFencePool + { + public: + VulkanFencePool(std::shared_ptr<const VulkanLogicalDevice> LogicalDevice); + VulkanFencePool(const VulkanFencePool&) = delete; + VulkanFencePool(VulkanFencePool&&) = delete; + VulkanFencePool& operator = (const VulkanFencePool&) = delete; + VulkanFencePool& operator = (VulkanFencePool&&) = delete; + ~VulkanFencePool(); + + VulkanUtilities::FenceWrapper GetFence(); + void DisposeFence(VulkanUtilities::FenceWrapper&& Fence); + + private: + // Shared pointer to logical device must be declared before fences + std::shared_ptr<const VulkanLogicalDevice> m_LogicalDevice; + std::vector<VulkanUtilities::FenceWrapper> m_Fences; + }; +} diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h index 0320afb9..0a8d67a6 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h @@ -24,19 +24,30 @@ #pragma once #include <vector> +#include <memory> #include "vulkan.h" namespace VulkanUtilities { - class VulkanInstance + class VulkanInstance : private std::enable_shared_from_this<VulkanInstance> { public: - VulkanInstance(bool EnableValidation, - uint32_t GlobalExtensionCount, - const char* const* ppGlobalExtensionNames, - VkAllocationCallbacks* pVkAllocator); + static std::shared_ptr<VulkanInstance> Create(bool EnableValidation, + uint32_t GlobalExtensionCount, + const char* const* ppGlobalExtensionNames, + VkAllocationCallbacks* pVkAllocator); ~VulkanInstance(); + std::shared_ptr<VulkanInstance> GetSharedPtr() + { + return shared_from_this(); + } + + std::shared_ptr<const VulkanInstance> GetSharedPtr()const + { + return shared_from_this(); + } + bool IsLayerAvailable(const char *LayerName)const; bool IsExtensionAvailable(const char *ExtensionName)const; VkPhysicalDevice SelectPhysicalDevice(); @@ -44,6 +55,10 @@ namespace VulkanUtilities VkInstance GetVkInstance()const{return m_VkInstance;} private: + VulkanInstance(bool EnableValidation, + uint32_t GlobalExtensionCount, + const char* const* ppGlobalExtensionNames, + VkAllocationCallbacks* pVkAllocator); bool m_ValidationEnabled = false; VkAllocationCallbacks* const m_pVkAllocator; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.h new file mode 100644 index 00000000..c4b6e480 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.h @@ -0,0 +1,104 @@ +/* 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 <memory> +#include "vulkan.h" +#include "VulkanObjectWrappers.h" + +namespace VulkanUtilities +{ + class VulkanLogicalDevice : private std::enable_shared_from_this<VulkanLogicalDevice> + { + public: + static std::shared_ptr<VulkanLogicalDevice> Create(VkPhysicalDevice vkPhysicalDevice, + const VkDeviceCreateInfo &DeviceCI, + const VkAllocationCallbacks* vkAllocator, + bool EnableDebugMarkers); + VulkanLogicalDevice(const VulkanLogicalDevice&) = delete; + VulkanLogicalDevice(VulkanLogicalDevice&&) = delete; + VulkanLogicalDevice& operator = (const VulkanLogicalDevice&) = delete; + VulkanLogicalDevice& operator = (VulkanLogicalDevice&&) = delete; + + ~VulkanLogicalDevice(); + + std::shared_ptr<VulkanLogicalDevice> GetSharedPtr() + { + return shared_from_this(); + } + + std::shared_ptr<const VulkanLogicalDevice> GetSharedPtr()const + { + return shared_from_this(); + } + + VkQueue GetQueue(uint32_t queueFamilyIndex, uint32_t queueIndex); + + VkDevice GetVkDevice()const + { + return m_VkDevice; + } + + void WaitIdle()const; + + CommandPoolWrapper CreateCommandPool (const VkCommandPoolCreateInfo &CmdPoolCI, const char *DebugName = "")const; + BufferWrapper CreateBuffer (const VkBufferCreateInfo &BufferCI, const char *DebugName = "")const; + BufferViewWrapper CreateBufferView (const VkBufferViewCreateInfo &BuffViewCI, const char *DebugName = "")const; + ImageWrapper CreateImage (const VkImageCreateInfo &ImageCI, const char *DebugName = "")const; + ImageViewWrapper CreateImageView (const VkImageViewCreateInfo &ImageViewCI, const char *DebugName = "")const; + FenceWrapper CreateFence (const VkFenceCreateInfo &FenceCI, const char *DebugName = "")const; + DeviceMemoryWrapper AllocateDeviceMemory(const VkMemoryAllocateInfo &AllocInfo, const char *DebugName = "")const; + + VkCommandBuffer AllocateVkCommandBuffer(const VkCommandBufferAllocateInfo &AllocInfo, const char *DebugName = "")const; + + void ReleaseVulkanObject(CommandPoolWrapper&& CmdPool)const; + void ReleaseVulkanObject(BufferWrapper&& Buffer)const; + void ReleaseVulkanObject(BufferViewWrapper&& BufferView)const; + void ReleaseVulkanObject(ImageWrapper&& Image)const; + void ReleaseVulkanObject(ImageViewWrapper&& ImageView)const; + void ReleaseVulkanObject(FenceWrapper&& Fence)const; + void ReleaseVulkanObject(DeviceMemoryWrapper&& Memory)const; + + VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer vkBuffer)const; + VkMemoryRequirements GetImageMemoryRequirements (VkImage vkImage )const; + + VkResult BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset)const; + VkResult BindImageMemory (VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset)const; + + VkResult MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData)const; + void UnmapMemory(VkDeviceMemory memory)const; + + VkResult GetFenceStatus(VkFence fence)const; + VkResult ResetFence(VkFence fence)const; + + private: + VulkanLogicalDevice(VkPhysicalDevice vkPhysicalDevice, + const VkDeviceCreateInfo &DeviceCI, + const VkAllocationCallbacks* vkAllocator, + bool EnableDebugMarkers); + + VkDevice m_VkDevice = VK_NULL_HANDLE; + const VkAllocationCallbacks* const m_VkAllocator; + }; +} diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.h new file mode 100644 index 00000000..00dd44d9 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.h @@ -0,0 +1,96 @@ +/* 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 <memory> +#include "vulkan.h" + +namespace VulkanUtilities +{ + class VulkanLogicalDevice; + + template<typename VulkanObjectType> + class VulkanObjectWrapper + { + public: + VulkanObjectWrapper() : + m_pLogicalDevice(nullptr), + m_VkObject(VK_NULL_HANDLE) + {} + VulkanObjectWrapper(std::shared_ptr<const VulkanLogicalDevice> pLogicalDevice, VulkanObjectType vkObject) : + m_pLogicalDevice(pLogicalDevice), + m_VkObject(vkObject) + {} + VulkanObjectWrapper(const VulkanObjectWrapper&) = delete; + VulkanObjectWrapper& operator = (const VulkanObjectWrapper&) = delete; + VulkanObjectWrapper(VulkanObjectWrapper&& rhs) : + m_pLogicalDevice(std::move(rhs.m_pLogicalDevice)), + m_VkObject(rhs.m_VkObject) + { + rhs.m_VkObject = VK_NULL_HANDLE; + } + VulkanObjectWrapper& operator = (VulkanObjectWrapper&& rhs) + { + m_pLogicalDevice = std::move(rhs.m_pLogicalDevice); + m_VkObject = rhs.m_VkObject; + rhs.m_VkObject = VK_NULL_HANDLE; + return *this; + } + + operator VulkanObjectType()const + { + return m_VkObject; + } + + void Release() + { + // For externally managed objects, m_pLogicalDevice is null + if(m_pLogicalDevice && m_VkObject != VK_NULL_HANDLE) + { + m_pLogicalDevice->ReleaseVulkanObject(std::move(*this)); + } + m_VkObject = VK_NULL_HANDLE; + m_pLogicalDevice.reset(); + } + + ~VulkanObjectWrapper() + { + Release(); + } + + private: + friend class VulkanLogicalDevice; + + std::shared_ptr<const VulkanLogicalDevice> m_pLogicalDevice; + VulkanObjectType m_VkObject; + }; + + using CommandPoolWrapper = VulkanObjectWrapper<VkCommandPool>; + using BufferWrapper = VulkanObjectWrapper<VkBuffer>; + using BufferViewWrapper = VulkanObjectWrapper<VkBufferView>; + using ImageWrapper = VulkanObjectWrapper<VkImage>; + using ImageViewWrapper = VulkanObjectWrapper<VkImageView>; + using DeviceMemoryWrapper = VulkanObjectWrapper<VkDeviceMemory>; + using FenceWrapper = VulkanObjectWrapper<VkFence>; +} diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h index b64ce488..15f9c8da 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h @@ -23,6 +23,7 @@ #pragma once +#include <memory> #include <vector> #include "vulkan.h" @@ -31,7 +32,8 @@ namespace VulkanUtilities class VulkanPhysicalDevice { public: - VulkanPhysicalDevice(VkPhysicalDevice vkDevice); + static std::unique_ptr<VulkanPhysicalDevice> Create(VkPhysicalDevice vkDevice); + uint32_t FindQueueFamily(VkQueueFlags QueueFlags)const; VkPhysicalDevice GetVkDeviceHandle()const{return m_VkDevice;} bool IsExtensionSupported(const char *ExtensionName)const; @@ -41,6 +43,8 @@ namespace VulkanUtilities uint32_t GetMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties)const; private: + VulkanPhysicalDevice(VkPhysicalDevice vkDevice); + const VkPhysicalDevice m_VkDevice; VkPhysicalDeviceProperties m_Properties = {}; VkPhysicalDeviceFeatures m_Features = {}; diff --git a/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h b/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h index c712ca84..9ed10106 100644 --- a/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h @@ -41,12 +41,12 @@ class ICommandQueueVk : public Diligent::IObject { public: /// Returns the fence value that will be signaled next time - //virtual UINT64 GetNextFenceValue() = 0; + virtual UINT64 GetNextFenceValue() = 0; - /// Executes a given command list + /// Executes a given command buffer - /// \return Fence value associated with the executed command list - //virtual UINT64 ExecuteCommandList(ID3D12GraphicsCommandList* commandList) = 0; + /// \return Fence value associated with the executed command buffer + virtual Uint64 ExecuteCommandBuffer(VkCommandBuffer cmdBuffer) = 0; /// Returns Vulkan command queue. May return VK_NULL_HANDLE if queue is anavailable virtual VkQueue GetVkQueue() = 0; @@ -55,10 +55,10 @@ public: virtual uint32_t GetQueueFamilyIndex() = 0; /// Returns value of the last completed fence - //virtual Uint64 GetCompletedFenceValue() = 0; + virtual Uint64 GetCompletedFenceValue() = 0; /// Blocks execution until all pending GPU commands are complete - //virtual void IdleGPU() = 0; + virtual void IdleGPU() = 0; }; } diff --git a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h index a5a03328..1b93ebfe 100644 --- a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h @@ -40,22 +40,19 @@ class IRenderDeviceVk : public IRenderDevice { public: - /// Returns ID3D12Device interface of the internal Direct3D12 device object. - - /// The method does *NOT* call AddRef() on the returned interface, - /// so Release() must not be called. - //virtual ID3D12Device* GetD3D12Device() = 0; + /// Returns logical Vulkan device handle + virtual VkDevice GetVkDevice() = 0; /// Returns the fence value that will be signaled by the GPU command queue next - //virtual Uint64 GetNextFenceValue() = 0; + virtual Uint64 GetNextFenceValue() = 0; /// Checks if the fence value has been signaled by the GPU. True means /// that all associated work has been finished - //virtual Bool IsFenceSignaled(Uint64 FenceValue) = 0; + virtual Bool IsFenceSignaled(Uint64 FenceValue) = 0; /// Should be called at the end of the frame when attached to existing D3D12 device /// Otherwise the method is automatically called before present - //virtual void FinishFrame() = 0; + virtual void FinishFrame() = 0; /// Creates a texture object from native d3d12 resource diff --git a/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp index ceb6f830..98b87a14 100644 --- a/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp @@ -23,6 +23,7 @@ #include "pch.h" #include "BufferViewVkImpl.h" +#include "RenderDeviceVkImpl.h" namespace Diligent { @@ -31,13 +32,19 @@ BufferViewVkImpl::BufferViewVkImpl( IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const BufferViewDesc& ViewDesc, IBuffer *pBuffer, - VkBufferView vkBuffView, + VulkanUtilities::BufferViewWrapper &&BuffView, bool bIsDefaultView ) : TBufferViewBase( pRefCounters, pDevice, ViewDesc, pBuffer, bIsDefaultView ), - m_VkBuffView(vkBuffView) + m_BuffView(std::move(BuffView)) { } +BufferViewVkImpl::~BufferViewVkImpl() +{ + auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice()); + pDeviceVkImpl->SafeReleaseVkObject(std::move(m_BuffView)); +} + IMPLEMENT_QUERY_INTERFACE( BufferViewVkImpl, IID_BufferViewVk, TBufferViewBase ) } diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp index a99afd71..3878c5cf 100644 --- a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp @@ -67,7 +67,7 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters, } } - auto vkAllocator = pRenderDeviceVk->GetVulkanInstance()->GetVkAllocator(); + 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"); @@ -107,12 +107,9 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters, VkBuffCI.pQueueFamilyIndices = nullptr; // list of queue families that will access this buffer // (ignored if sharingMode is not VK_SHARING_MODE_CONCURRENT). - auto vkDevice = pRenderDeviceVk->GetVkDevice(); - auto err = vkCreateBuffer(vkDevice, &VkBuffCI, vkAllocator, &m_VkBuffer); - CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan buffer object"); + m_VulkanBuffer = LogicalDevice.CreateBuffer(VkBuffCI, m_Desc.Name); - VkMemoryRequirements MemReqs = {}; - vkGetBufferMemoryRequirements(vkDevice, m_VkBuffer, &MemReqs); + VkMemoryRequirements MemReqs = LogicalDevice.GetBufferMemoryRequirements(m_VulkanBuffer); VkMemoryAllocateInfo MemAlloc = {}; MemAlloc.pNext = nullptr; @@ -144,32 +141,31 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters, LOG_ERROR_AND_THROW("Failed to find suitable device memory type for a buffer"); } - err = vkAllocateMemory(vkDevice, &MemAlloc, vkAllocator, &m_BufferMemory); - CHECK_VK_ERROR_AND_THROW(err, "Failed to allocate device local memory for a Vulkan buffer object"); + { + std::string MemoryName("Device local memory for buffer '"); + MemoryName += m_Desc.Name; + MemoryName += '\''; + m_BufferMemory = LogicalDevice.AllocateDeviceMemory(MemAlloc, MemoryName.c_str()); + } - err = vkBindBufferMemory(vkDevice, m_VkBuffer, m_BufferMemory, 0 /*offset*/); + 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; - if( *m_Desc.Name != 0) - VulkanUtilities::SetBufferName(vkDevice, m_VkBuffer, m_Desc.Name); - if( bInitializeBuffer ) { VkBufferCreateInfo VkStaginBuffCI = VkBuffCI; VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - VkBuffer vkStagingBuffer = VK_NULL_HANDLE; - err = vkCreateBuffer(vkDevice, &VkStaginBuffCI, vkAllocator, &vkStagingBuffer); - CHECK_VK_ERROR_AND_THROW(err, "Failed to create staging buffer"); + std::string StagingBufferName = "Staging buffer for '"; + StagingBufferName += m_Desc.Name; + StagingBufferName += '\''; + VulkanUtilities::BufferWrapper StagingBuffer = LogicalDevice.CreateBuffer(VkStaginBuffCI, StagingBufferName.c_str()); - VulkanUtilities::SetBufferName(vkDevice, vkStagingBuffer, "Staging buffer"); - - VkMemoryRequirements StagingBufferMemReqs = {}; - vkGetBufferMemoryRequirements(vkDevice, vkStagingBuffer, &StagingBufferMemReqs); + VkMemoryRequirements StagingBufferMemReqs = LogicalDevice.GetBufferMemoryRequirements(StagingBuffer); VkMemoryAllocateInfo StagingMemAlloc = {}; StagingMemAlloc.pNext = nullptr; @@ -187,32 +183,43 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters, "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)"); - VkDeviceMemory vkStagingBufferMemory = VK_NULL_HANDLE; - err = vkAllocateMemory(vkDevice, &StagingMemAlloc, vkAllocator, &vkStagingBufferMemory); - CHECK_VK_ERROR_AND_THROW(err, "Failed to allocate memory for a staging buffer object"); + 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 = vkMapMemory(vkDevice, vkStagingBufferMemory, + 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); - vkUnmapMemory(vkDevice, vkStagingBufferMemory); + LogicalDevice.UnmapMemory(StagingBufferMemory); } - err = vkBindBufferMemory(vkDevice, vkStagingBuffer, vkStagingBufferMemory, 0 /*offset*/); + 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"); + #if 0 - auto *pInitContext = pRenderDeviceVk->AllocateCommandContext(); // 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 - pInitContext->CopyResource(m_pVkResource, UploadBuffer); + + // 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 @@ -232,13 +239,14 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters, // | N+1, but resource it references | | // | was added to the delete queue | | // | with value N | | - pRenderDeviceVk->CloseAndExecuteCommandContext(pInitContext, false); + 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(UploadBuffer); -#endif + pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingBuffer)); + pRenderDeviceVk->SafeReleaseVkObject(std::move(StagingBufferMemory)); } //if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER) @@ -316,12 +324,10 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters, } BufferVkImpl :: ~BufferVkImpl() { + auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice()); // Vk object can only be destroyed when it is no longer used by the GPU - if(m_VkBuffer!=VK_NULL_HANDLE) - { - auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice()); - pDeviceVkImpl->SafeReleaseVkBuffer(m_VkBuffer); - } + pDeviceVkImpl->SafeReleaseVkObject(std::move(m_VulkanBuffer)); + pDeviceVkImpl->SafeReleaseVkObject(std::move(m_BufferMemory)); } IMPLEMENT_QUERY_INTERFACE( BufferVkImpl, IID_BufferVk, TBufferBase ) @@ -469,9 +475,9 @@ void BufferVkImpl::CreateViewInternal( const BufferViewDesc &OrigViewDesc, IBuff BufferViewDesc ViewDesc = OrigViewDesc; if( ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS || ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE ) { - auto vkView = CreateView(ViewDesc); + auto View = CreateView(ViewDesc); *ppView = NEW_RC_OBJ(BuffViewAllocator, "BufferViewVkImpl instance", BufferViewVkImpl, bIsDefaultView ? this : nullptr) - (GetDevice(), ViewDesc, this, vkView, bIsDefaultView ); + (GetDevice(), ViewDesc, this, std::move(View), bIsDefaultView ); } if( !bIsDefaultView && *ppView ) @@ -485,9 +491,9 @@ void BufferVkImpl::CreateViewInternal( const BufferViewDesc &OrigViewDesc, IBuff } -VkBufferView BufferVkImpl::CreateView(struct BufferViewDesc &ViewDesc) +VulkanUtilities::BufferViewWrapper BufferVkImpl::CreateView(struct BufferViewDesc &ViewDesc) { - VkBufferView vkBuffView = VK_NULL_HANDLE; + VulkanUtilities::BufferViewWrapper BuffView; CorrectBufferViewDesc(ViewDesc); if( (ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE || ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS) && m_Desc.Mode == BUFFER_MODE_FORMATTED) @@ -496,18 +502,16 @@ VkBufferView BufferVkImpl::CreateView(struct BufferViewDesc &ViewDesc) ViewCI.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; ViewCI.pNext = nullptr; ViewCI.flags = 0; // reserved for future use - ViewCI.buffer = m_VkBuffer; + ViewCI.buffer = m_VulkanBuffer; ViewCI.format = TypeToVkFormat(m_Desc.Format.ValueType, m_Desc.Format.NumComponents, m_Desc.Format.IsNormalized); ViewCI.offset = ViewDesc.ByteOffset; ViewCI.range = ViewDesc.ByteWidth; // size in bytes of the buffer view auto *pDeviceVkImpl = static_cast<RenderDeviceVkImpl*>(GetDevice()); - auto vkAllocator = pDeviceVkImpl->GetVulkanInstance()->GetVkAllocator(); - auto vkDevice = pDeviceVkImpl->GetVkDevice(); - auto err = vkCreateBufferView(vkDevice, &ViewCI, vkAllocator, &vkBuffView); - CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan buffer view"); + const auto& LogicalDevice = pDeviceVkImpl->GetLogicalDevice(); + BuffView = LogicalDevice.CreateBufferView(ViewCI, ViewDesc.Name); } - return vkBuffView; + return BuffView; } #if 0 diff --git a/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp b/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp index fa1157a1..0b254cfc 100644 --- a/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp +++ b/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp @@ -25,7 +25,6 @@ #include "CommandContext.h" #include "TextureVkImpl.h" #include "BufferVkImpl.h" -#include "CommandListManager.h" namespace Diligent { diff --git a/Graphics/GraphicsEngineVulkan/src/CommandListManager.cpp b/Graphics/GraphicsEngineVulkan/src/CommandListManager.cpp deleted file mode 100644 index b4d67c9a..00000000 --- a/Graphics/GraphicsEngineVulkan/src/CommandListManager.cpp +++ /dev/null @@ -1,109 +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 "CommandListManager.h" -#include "RenderDeviceVkImpl.h" - -namespace Diligent -{ - -CommandListManager::CommandListManager(RenderDeviceVkImpl *pDeviceVk)/* : - m_pDeviceVk(pDeviceVk), - m_DiscardedAllocators(STD_ALLOCATOR_RAW_MEM(DiscardedAllocatorQueueElemType, GetRawAllocator(), "Allocator for deque<DiscardedAllocatorQueueElemType>")) - */ -{ -} - -CommandListManager::~CommandListManager() -{ -} - -#if 0 -void CommandListManager::CreateNewCommandList( IVkGraphicsCommandList** List, IVkCommandAllocator** Allocator ) -{ - RequestAllocator(Allocator); - auto *pVkDevice = m_pDeviceVk->GetVkDevice(); - auto hr = pVkDevice->CreateCommandList(1, Vk_COMMAND_LIST_TYPE_DIRECT, *Allocator, nullptr, __uuidof(*List), reinterpret_cast<void**>(List) ); - VERIFY(SUCCEEDED(hr), "Failed to create command list"); - (*List)->SetName(L"CommandList"); -} - - -void CommandListManager::RequestAllocator(IVkCommandAllocator** ppAllocator) -{ - std::lock_guard<std::mutex> LockGuard(m_AllocatorMutex); - - VERIFY( (*ppAllocator) == nullptr, "Allocator pointer is not null" ); - (*ppAllocator) = nullptr; - - if (!m_DiscardedAllocators.empty()) - { - // Pick the oldest allocator at the front of the deque - // If this allocator is not yet available, there is no point in - // looking at other allocators since they were released even - // later - auto& AllocatorPair = m_DiscardedAllocators.front(); - - // Get the last completed fence value - auto CompletedFenceValue = m_pDeviceVk->GetCompletedFenceValue(); - // Note that CompletedFenceValue only grows. So if after we queried - // the value, the actual value is increased in other thread, this will not - // be an issue as the only consequence is that potentially available - // allocator may not be used. - - // AllocatorPair.first is the fence value that was signaled AFTER the - // command list has been submitted. If CompletedFenceValue is at least - // this value, the allocator can be safely reused - if ( CompletedFenceValue >= AllocatorPair.first ) - { - *ppAllocator = AllocatorPair.second.Detach(); - auto hr = (*ppAllocator)->Reset(); - VERIFY_EXPR(SUCCEEDED(hr)); - m_DiscardedAllocators.pop_front(); - } - } - - // If no allocators were ready to be reused, create a new one - if ((*ppAllocator) == nullptr) - { - auto *pVkDevice = m_pDeviceVk->GetVkDevice(); - auto hr = pVkDevice->CreateCommandAllocator(Vk_COMMAND_LIST_TYPE_DIRECT, __uuidof(*ppAllocator), reinterpret_cast<void**>(ppAllocator)); - VERIFY(SUCCEEDED(hr), "Failed to create command allocator"); - wchar_t AllocatorName[32]; - swprintf(AllocatorName, _countof(AllocatorName), L"Cmd list allocator %ld", Atomics::AtomicIncrement(m_NumAllocators)-1); - (*ppAllocator)->SetName(AllocatorName); - } -} - -void CommandListManager::DiscardAllocator( Uint64 FenceValue, IVkCommandAllocator* pAllocator ) -{ - std::lock_guard<std::mutex> LockGuard(m_AllocatorMutex); - - // FenceValue is the value that was signaled by the command queue after it - // executed the command list created by the allocator - m_DiscardedAllocators.emplace_back( FenceValue, CComPtr<IVkCommandAllocator>(pAllocator) ); -} -#endif - -} diff --git a/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp index dc6eb140..b25c412c 100644 --- a/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp @@ -27,17 +27,16 @@ namespace Diligent { -CommandQueueVkImpl::CommandQueueVkImpl(IReferenceCounters *pRefCounters, VkQueue VkNativeCmdQueue, uint32_t QueueFamilyIndex) : - TBase(pRefCounters), - m_VkQueue(VkNativeCmdQueue), - m_QueueFamilyIndex(QueueFamilyIndex) - /*m_VkFence(pVkFence), - m_NextFenceValue(1), - m_WaitForGPUEventHandle( CreateEvent(nullptr, false, false, nullptr) ) - */ +CommandQueueVkImpl::CommandQueueVkImpl(IReferenceCounters *pRefCounters, + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> LogicalDevice, + uint32_t QueueFamilyIndex) : + TBase(pRefCounters), + m_LogicalDevice(LogicalDevice), + m_VkQueue(LogicalDevice->GetQueue(QueueFamilyIndex, 0)), + m_QueueFamilyIndex(QueueFamilyIndex), + m_NextFenceValue(1), + m_FencePool(LogicalDevice) { - //VERIFY_EXPR(m_WaitForGPUEventHandle != INVALID_HANDLE_VALUE); - //m_VkFence->Signal(0); } CommandQueueVkImpl::~CommandQueueVkImpl() @@ -45,18 +44,43 @@ CommandQueueVkImpl::~CommandQueueVkImpl() // Queues are created along with a logical device during vkCreateDevice. // All queues associated with a logical device are destroyed when vkDestroyDevice // is called on that device. + + while(!m_PendingFences.empty()) + { + m_FencePool.DisposeFence(std::move(m_PendingFences.front().second)); + m_PendingFences.pop_front(); + } } IMPLEMENT_QUERY_INTERFACE( CommandQueueVkImpl, IID_CommandQueueVk, TBase ) -#if 0 -UINT64 CommandQueueVkImpl::ExecuteCommandList(IVkGraphicsCommandList* commandList) + +Uint64 CommandQueueVkImpl::ExecuteCommandBuffer(VkCommandBuffer cmdBuffer) { - IVkCommandList *const ppCmdLists[] = {commandList}; - m_pVkCmdQueue->ExecuteCommandLists(1, ppCmdLists); + std::lock_guard<std::mutex> Lock(m_QueueMutex); + + VkSubmitInfo SubmitInfo = {}; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.commandBufferCount = 1; + SubmitInfo.pCommandBuffers = &cmdBuffer; + SubmitInfo.waitSemaphoreCount = 0; // the number of semaphores upon which to wait before executing the command buffers + SubmitInfo.pWaitSemaphores = nullptr; // a pointer to an array of semaphores upon which to wait before the command + // buffers begin execution + SubmitInfo.pWaitDstStageMask = nullptr; // a pointer to an array of pipeline stages at which each corresponding + // semaphore wait will occur + SubmitInfo.signalSemaphoreCount = 0; // the number of semaphores to be signaled once the commands specified in + // pCommandBuffers have completed execution + SubmitInfo.pSignalSemaphores = nullptr; // a pointer to an array of semaphores which will be signaled when the + // command buffers for this batch have completed execution + + auto Fence = m_FencePool.GetFence(); + auto err = vkQueueSubmit(m_VkQueue, 1, &SubmitInfo, Fence); + VERIFY(err == VK_SUCCESS, "Failed to submit command buffer to the command queue"); + + // We must atomically place the (value, fence) pair into the deque auto FenceValue = m_NextFenceValue; - // Signal the fence - m_pVkCmdQueue->Signal(m_VkFence, FenceValue); + m_PendingFences.emplace_back(FenceValue, std::move(Fence)); + // Increment the value Atomics::AtomicIncrement(m_NextFenceValue); return FenceValue; @@ -64,24 +88,46 @@ UINT64 CommandQueueVkImpl::ExecuteCommandList(IVkGraphicsCommandList* commandLis void CommandQueueVkImpl::IdleGPU() { - Uint64 LastSignaledFenceValue = m_NextFenceValue; - m_pVkCmdQueue->Signal(m_VkFence, LastSignaledFenceValue); + std::lock_guard<std::mutex> Lock(m_QueueMutex); + + // Update last completed fence value to unlock all waiting events + Uint64 LastCompletedFenceValue = m_NextFenceValue; + // Increment fence before idling the queue Atomics::AtomicIncrement(m_NextFenceValue); - if (GetCompletedFenceValue() < LastSignaledFenceValue) + vkQueueWaitIdle(m_VkQueue); + if(LastCompletedFenceValue > m_LastCompletedFenceValue) + m_LastCompletedFenceValue = LastCompletedFenceValue; + for(auto& val_fence : m_PendingFences) { - m_VkFence->SetEventOnCompletion(LastSignaledFenceValue, m_WaitForGPUEventHandle); - WaitForSingleObject(m_WaitForGPUEventHandle, INFINITE); - VERIFY(GetCompletedFenceValue() == LastSignaledFenceValue, "Unexpected signaled fence value"); + auto status = m_LogicalDevice->GetFenceStatus(val_fence.second); + VERIFY(status == VK_SUCCESS, "All pending fences must now be complete!"); + m_FencePool.DisposeFence(std::move(val_fence.second)); } + m_PendingFences.clear(); } Uint64 CommandQueueVkImpl::GetCompletedFenceValue() { - auto CompletedFenceValue = m_VkFence->GetCompletedValue(); - if(CompletedFenceValue > m_LastCompletedFenceValue) - m_LastCompletedFenceValue = CompletedFenceValue; + std::lock_guard<std::mutex> Lock(m_QueueMutex); + + while(!m_PendingFences.empty()) + { + auto &Value_Fence = m_PendingFences.front(); + auto status = m_LogicalDevice->GetFenceStatus(Value_Fence.second); + if(status == VK_SUCCESS) + { + if(Value_Fence.first > m_LastCompletedFenceValue) + m_LastCompletedFenceValue = Value_Fence.first; + m_FencePool.DisposeFence(std::move(Value_Fence.second)); + m_PendingFences.pop_front(); + } + else + { + break; + } + } + return m_LastCompletedFenceValue; } -#endif } diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 95d681b7..8c1580bd 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -550,9 +550,9 @@ namespace Diligent m_CommittedIBFormat = VT_UNDEFINED; m_bCommittedVkVBsUpToDate = false; m_bCommittedVkIBUpToDate = false; +#endif m_pPipelineState.Release(); -#endif } void DeviceContextVkImpl::Flush() diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp index 36118793..d61c05b8 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp @@ -54,7 +54,7 @@ public: void AttachToVulkanDevice(std::shared_ptr<VulkanUtilities::VulkanInstance>, std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> PhysicalDevice, - VkDevice vkLogicalDevice, + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> LogicalDevice, ICommandQueueVk *pCommandQueue, const EngineVkAttribs& EngineAttribs, IRenderDevice **ppDevice, @@ -114,17 +114,16 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& Crea *ppDevice = nullptr; memset(ppContexts, 0, sizeof(*ppContexts) * (1 + NumDeferredContexts)); - std::shared_ptr<VulkanUtilities::VulkanInstance> Instance; try { - Instance = std::make_shared<VulkanUtilities::VulkanInstance>( + auto Instance = VulkanUtilities::VulkanInstance::Create( CreationAttribs.EnableValidation, CreationAttribs.GlobalExtensionCount, CreationAttribs.ppGlobalExtensionNames, reinterpret_cast<VkAllocationCallbacks*>(CreationAttribs.pVkAllocator)); auto vkDevice = Instance->SelectPhysicalDevice(); - std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> PhysicalDevice(new VulkanUtilities::VulkanPhysicalDevice(vkDevice)); + auto PhysicalDevice = VulkanUtilities::VulkanPhysicalDevice::Create(vkDevice); // If an implementation exposes any queue family that supports graphics operations, // at least one queue family of at least one physical device exposed by the implementation @@ -163,30 +162,20 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& Crea DeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data(); DeviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(DeviceExtensions.size()); - VkDevice VulkanDevice = VK_NULL_HANDLE; - auto res = vkCreateDevice(PhysicalDevice->GetVkDeviceHandle(), &DeviceCreateInfo, Instance->GetVkAllocator(), &VulkanDevice); - CHECK_VK_ERROR_AND_THROW(res, "Failed to create logical device"); - - if (CreationAttribs.EnableValidation) + if (!DebugMarkersSupported && CreationAttribs.EnableValidation) { - if(DebugMarkersSupported) - VulkanUtilities::SetupDebugMarkers(VulkanDevice); - else - LOG_INFO_MESSAGE("Debug marker extensions is not found on the system"); + LOG_INFO_MESSAGE("Debug marker extensions is not found on the system"); } - VkQueue Queue = VK_NULL_HANDLE; - vkGetDeviceQueue(VulkanDevice, - QueueInfo.queueFamilyIndex, // Index of the queue family to which the queue belongs - 0, // Index within this queue family of the queue to retrieve - &Queue); - VERIFY_EXPR(Queue != VK_NULL_HANDLE); - RefCntAutoPtr<CommandQueueVkImpl> pCmdQueueVk; + auto vkAllocator = Instance->GetVkAllocator(); + auto vkPhysicalDevice = PhysicalDevice->GetVkDeviceHandle(); + auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create(vkPhysicalDevice, DeviceCreateInfo, vkAllocator, DebugMarkersSupported && CreationAttribs.EnableValidation); + RefCntAutoPtr<CommandQueueVkImpl> pCmdQueueVk; auto &RawMemAllocator = GetRawAllocator(); - pCmdQueueVk = NEW_RC_OBJ(RawMemAllocator, "CommandQueueVk instance", CommandQueueVkImpl)(Queue, QueueInfo.queueFamilyIndex); + pCmdQueueVk = NEW_RC_OBJ(RawMemAllocator, "CommandQueueVk instance", CommandQueueVkImpl)(LogicalDevice, QueueInfo.queueFamilyIndex); - AttachToVulkanDevice(Instance, std::move(PhysicalDevice), VulkanDevice, pCmdQueueVk, CreationAttribs, ppDevice, ppContexts, NumDeferredContexts); + AttachToVulkanDevice(Instance, std::move(PhysicalDevice), LogicalDevice, pCmdQueueVk, CreationAttribs, ppDevice, ppContexts, NumDeferredContexts); } catch(std::runtime_error& ) { @@ -198,7 +187,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& Crea /// \param [in] Instance - shared pointer to a VulkanUtilities::VulkanInstance object /// \param [in] PhysicalDevice - pointer to the object representing physical device -/// \param [in] vkLogicalDevice - logical Vulkan device handle +/// \param [in] LogicalDevice - shared pointer to a VulkanUtilities::VulkanLogicalDevice object /// \param [in] pCommandQueue - pointer to the implementation of command queue /// \param [in] EngineAttribs - Engine creation attributes. /// \param [out] ppDevice - Address of the memory location where pointer to @@ -213,7 +202,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& Crea /// at position 1 void EngineFactoryVkImpl::AttachToVulkanDevice(std::shared_ptr<VulkanUtilities::VulkanInstance> Instance, std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> PhysicalDevice, - VkDevice vkLogicalDevice, + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> LogicalDevice, ICommandQueueVk *pCommandQueue, const EngineVkAttribs& EngineAttribs, IRenderDevice **ppDevice, @@ -221,7 +210,7 @@ void EngineFactoryVkImpl::AttachToVulkanDevice(std::shared_ptr<VulkanUtilities:: Uint32 NumDeferredContexts) { VERIFY( pCommandQueue && ppDevice && ppContexts, "Null pointer provided" ); - if(vkLogicalDevice == VK_NULL_HANDLE || !pCommandQueue || !ppDevice || !ppContexts ) + if(!LogicalDevice || !pCommandQueue || !ppDevice || !ppContexts ) return; *ppDevice = nullptr; @@ -230,7 +219,7 @@ void EngineFactoryVkImpl::AttachToVulkanDevice(std::shared_ptr<VulkanUtilities:: try { auto &RawMemAllocator = GetRawAllocator(); - RenderDeviceVkImpl *pRenderDeviceVk( NEW_RC_OBJ(RawMemAllocator, "RenderDeviceVkImpl instance", RenderDeviceVkImpl)(RawMemAllocator, EngineAttribs, pCommandQueue, Instance, std::move(PhysicalDevice), vkLogicalDevice, NumDeferredContexts ) ); + RenderDeviceVkImpl *pRenderDeviceVk( NEW_RC_OBJ(RawMemAllocator, "RenderDeviceVkImpl instance", RenderDeviceVkImpl)(RawMemAllocator, EngineAttribs, pCommandQueue, Instance, std::move(PhysicalDevice), LogicalDevice, NumDeferredContexts ) ); pRenderDeviceVk->QueryInterface(IID_RenderDevice, reinterpret_cast<IObject**>(ppDevice) ); RefCntAutoPtr<DeviceContextVkImpl> pImmediateCtxVk( NEW_RC_OBJ(RawMemAllocator, "DeviceContextVkImpl instance", DeviceContextVkImpl)(pRenderDeviceVk, false, EngineAttribs, 0) ); diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 53e28f9a..db6fc6e6 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -26,7 +26,7 @@ #include "PipelineStateVkImpl.h" #include "ShaderVkImpl.h" #include "TextureVkImpl.h" -//#include "DXGITypeConversions.h" +#include "VulkanTypeConversions.h" #include "SamplerVkImpl.h" #include "BufferVkImpl.h" #include "ShaderResourceBindingVkImpl.h" @@ -42,17 +42,17 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters, ICommandQueueVk *pCmdQueue, std::shared_ptr<VulkanUtilities::VulkanInstance> Instance, std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> PhysicalDevice, - VkDevice vkLogicalDevice, + std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> LogicalDevice, Uint32 NumDeferredContexts) : TRenderDeviceBase(pRefCounters, RawMemAllocator, NumDeferredContexts, sizeof(TextureVkImpl), sizeof(TextureViewVkImpl), sizeof(BufferVkImpl), sizeof(BufferViewVkImpl), sizeof(ShaderVkImpl), sizeof(SamplerVkImpl), sizeof(PipelineStateVkImpl), sizeof(ShaderResourceBindingVkImpl)), m_VulkanInstance(Instance), m_PhysicalDevice(std::move(PhysicalDevice)), - m_VkDevice(vkLogicalDevice), + m_LogicalVkDevice(LogicalDevice), m_pCommandQueue(pCmdQueue), - m_EngineAttribs(CreationAttribs) - /*m_FrameNumber(0), + m_EngineAttribs(CreationAttribs), + m_FrameNumber(0), m_NextCmdListNumber(0), - m_CmdListManager(this), + /*m_CmdListManager(this), m_CPUDescriptorHeaps { {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[0], Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Vk_DESCRIPTOR_HEAP_FLAG_NONE}, @@ -71,54 +71,62 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters, CreationAttribs.DynamicDescriptorAllocationChunkSize[1] // Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER }, m_ContextPool(STD_ALLOCATOR_RAW_MEM(ContextPoolElemType, GetRawAllocator(), "Allocator for vector<unique_ptr<CommandContext>>")), - m_AvailableContexts(STD_ALLOCATOR_RAW_MEM(CommandContext*, GetRawAllocator(), "Allocator for vector<CommandContext*>")), + m_AvailableContexts(STD_ALLOCATOR_RAW_MEM(CommandContext*, GetRawAllocator(), "Allocator for vector<CommandContext*>")),*/ 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_StaleVkObjects(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue<ReleaseQueueElemType>")),/*, m_UploadHeaps(STD_ALLOCATOR_RAW_MEM(UploadHeapPoolElemType, GetRawAllocator(), "Allocator for vector<unique_ptr<DynamicUploadHeap>>")) */ + m_CmdBufferPool(m_LogicalVkDevice, pCmdQueue->GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT) { m_DeviceCaps.DevType = DeviceType::Vulkan; m_DeviceCaps.MajorVersion = 1; m_DeviceCaps.MinorVersion = 0; m_DeviceCaps.bSeparableProgramSupported = True; m_DeviceCaps.bMultithreadedResourceCreationSupported = True; + for(int fmt = 1; fmt < m_TextureFormatsInfo.size(); ++fmt) + m_TextureFormatsInfo[fmt].Supported = true; // We will test every format on a specific hardware device } RenderDeviceVkImpl::~RenderDeviceVkImpl() { -#if 0 // Finish current frame. This will release resources taken by previous frames, and // will move all stale resources to the release queues. The resources will not be // release until next call to FinishFrame() - FinishFrame(); + FinishFrame(false); // Wait for the GPU to complete all its operations IdleGPU(true); // Call FinishFrame() again to destroy resources in // release queues FinishFrame(true); - + +#if 0 m_ContextPool.clear(); #endif - if(m_PhysicalDevice) - { - // If m_PhysicalDevice is empty, the device does not own vulkan logical device and must not - // destroy it - vkDestroyDevice(m_VkDevice, m_VulkanInstance->GetVkAllocator()); - } + VERIFY(m_StaleVkObjects.empty(), "Not all stale objects were destroyed"); + VERIFY(m_VkObjReleaseQueue.empty(), "Release queue is not empty"); + + //if(m_PhysicalDevice) + //{ + // // If m_PhysicalDevice is empty, the device does not own vulkan logical device and must not + // // destroy it + // vkDestroyDevice(m_VkDevice, m_VulkanInstance->GetVkAllocator()); + //} } -#if 0 -void RenderDeviceVkImpl::DisposeCommandContext(CommandContext* pCtx) + +void RenderDeviceVkImpl::DisposeCommandBuffer(VkCommandBuffer CmdBuff) { - std::lock_guard<std::mutex> LockGuard(m_ContextAllocationMutex); - m_AvailableContexts.push_back(pCtx); + std::lock_guard<std::mutex> LockGuard(m_CmdPoolMutex); + m_CmdBufferPool.DisposeCommandBuffer(CmdBuff, GetNextFenceValue()); } -void RenderDeviceVkImpl::CloseAndExecuteCommandContext(CommandContext *pCtx, bool DiscardStaleObjects) + +void RenderDeviceVkImpl::ExecuteCommandBuffer(VkCommandBuffer CmdBuff, bool DiscardStaleObjects) { - CComPtr<IVkCommandAllocator> pAllocator; - auto *pCmdList = pCtx->Close(&pAllocator); + VERIFY_EXPR(CmdBuff != VK_NULL_HANDLE); + auto err = vkEndCommandBuffer(CmdBuff); + VERIFY(err == VK_SUCCESS, "Failed to end command buffer"); Uint64 FenceValue = 0; Uint64 CmdListNumber = 0; @@ -126,7 +134,7 @@ void RenderDeviceVkImpl::CloseAndExecuteCommandContext(CommandContext *pCtx, boo std::lock_guard<std::mutex> LockGuard(m_CmdQueueMutex); auto NextFenceValue = m_pCommandQueue->GetNextFenceValue(); // Submit the command list to the queue - FenceValue = m_pCommandQueue->ExecuteCommandList(pCmdList); + FenceValue = m_pCommandQueue->ExecuteCommandBuffer(CmdBuff); VERIFY(FenceValue >= NextFenceValue, "Fence value of the executed command list is less than the next fence value previously queried through GetNextFenceValue()"); FenceValue = std::max(FenceValue, NextFenceValue); CmdListNumber = m_NextCmdListNumber; @@ -167,7 +175,7 @@ void RenderDeviceVkImpl::CloseAndExecuteCommandContext(CommandContext *pCtx, boo // the command list (as is the case with Unity command queue). DiscardStaleVkObjects(CmdListNumber, FenceValue); } - +#if 0 // DiscardAllocator() is thread-safe m_CmdListManager.DiscardAllocator(FenceValue, pAllocator); @@ -177,26 +185,30 @@ void RenderDeviceVkImpl::CloseAndExecuteCommandContext(CommandContext *pCtx, boo std::lock_guard<std::mutex> LockGuard(m_ContextAllocationMutex); m_AvailableContexts.push_back(pCtx); } -} #endif +} + -#if 0 void RenderDeviceVkImpl::IdleGPU(bool ReleaseStaleObjects) { Uint64 FenceValue = 0; Uint64 CmdListNumber = 0; + { // Lock the command queue to avoid other threads interfering with the GPU std::lock_guard<std::mutex> LockGuard(m_CmdQueueMutex); FenceValue = m_pCommandQueue->GetNextFenceValue(); m_pCommandQueue->IdleGPU(); + + m_LogicalVkDevice->WaitIdle(); + // Increment cmd list number while keeping queue locked. // This guarantees that any Vk object released after the lock // is released, will be associated with the incremented cmd list number CmdListNumber = m_NextCmdListNumber; Atomics::AtomicIncrement(m_NextCmdListNumber); } - + if (ReleaseStaleObjects) { // Do not wait until the end of the frame and force deletion. @@ -208,6 +220,7 @@ void RenderDeviceVkImpl::IdleGPU(bool ReleaseStaleObjects) } } + Bool RenderDeviceVkImpl::IsFenceSignaled(Uint64 FenceValue) { return FenceValue <= GetCompletedFenceValue(); @@ -218,8 +231,10 @@ Uint64 RenderDeviceVkImpl::GetCompletedFenceValue() return m_pCommandQueue->GetCompletedFenceValue(); } + void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources) { +#if 0 { if (auto pImmediateCtx = m_wpImmediateContext.Lock()) { @@ -238,7 +253,7 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources) } } } - +#endif auto CompletedFenceValue = ReleaseAllResources ? std::numeric_limits<Uint64>::max() : GetCompletedFenceValue(); // We must use NextFenceValue here, NOT current value, because the @@ -258,6 +273,7 @@ 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 @@ -298,7 +314,7 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources) { m_GPUDescriptorHeaps[GPUHeap].ReleaseStaleAllocations(CompletedFenceValue); } - +#endif // Discard all remaining objects. This is important to do if there were // no command lists submitted during the frame DiscardStaleVkObjects(CmdListNumber, NextFenceValue); @@ -307,6 +323,7 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources) Atomics::AtomicIncrement(m_FrameNumber); } +#if 0 DynamicUploadHeap* RenderDeviceVkImpl::RequestUploadHeap() { std::lock_guard<std::mutex> LockGuard(m_UploadHeapMutex); @@ -328,11 +345,15 @@ void RenderDeviceVkImpl::ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap) { } +#endif -CommandContext* RenderDeviceVkImpl::AllocateCommandContext(const Char *ID) +VkCommandBuffer RenderDeviceVkImpl::AllocateCommandBuffer(const Char *DebugName) { - std::lock_guard<std::mutex> LockGuard(m_ContextAllocationMutex); + std::lock_guard<std::mutex> LockGuard(m_CmdPoolMutex); + auto CmdBuffer = m_CmdBufferPool.GetCommandBuffer(GetCompletedFenceValue(), DebugName); + return CmdBuffer; +#if 0 CommandContext* ret = nullptr; if (m_AvailableContexts.empty()) { @@ -353,21 +374,44 @@ CommandContext* RenderDeviceVkImpl::AllocateCommandContext(const Char *ID) // EngineProfiling::BeginBlock(ID, NewContext); return ret; -} #endif +} -void RenderDeviceVkImpl::SafeReleaseVkBuffer(VkBuffer vkBuffer) + +template<typename VulkanObjectType> +class RenderDeviceVkImpl::StaleVulkanObject : public StaleVulkanObjectBase +{ +public: + StaleVulkanObject(VulkanUtilities::VulkanObjectWrapper<VulkanObjectType> &&Object) : + m_VkObject(std::move(Object)) + {} + + ~StaleVulkanObject() + { + m_VkObject.Release(); + } + +private: + VulkanUtilities::VulkanObjectWrapper<VulkanObjectType> m_VkObject; +}; + +template<typename VulkanObjectType> +void RenderDeviceVkImpl::SafeReleaseVkObject(VulkanUtilities::VulkanObjectWrapper<VulkanObjectType>&& vkObject) { // When Vk object is released, it is first moved into the // stale objects list. The list is moved into a release queue // when the next command list is executed. std::lock_guard<std::mutex> LockGuard(m_StaleObjectsMutex); -#if 0 - m_StaleVkObjects.emplace_back( m_NextCmdListNumber, CComPtr<IVkObject>(pObj) ); -#endif + m_StaleVkObjects.emplace_back(m_NextCmdListNumber, new StaleVulkanObject<VulkanObjectType>(std::move(vkObject)) ); } -#if 0 +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<VkDeviceMemory>(VulkanUtilities::DeviceMemoryWrapper &&Object); + + void RenderDeviceVkImpl::DiscardStaleVkObjects(Uint64 CmdListNumber, Uint64 FenceValue) { // Only discard these stale objects that were released before CmdListNumber @@ -403,122 +447,94 @@ void RenderDeviceVkImpl::ProcessReleaseQueue(Uint64 CompletedFenceValue) } } -bool CreateTestResource(IVkDevice *pDevice, const Vk_RESOURCE_DESC &ResDesc) -{ - // Set the texture pointer address to nullptr to validate input parameters - // without creating the texture - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn899178(v=vs.85).aspx - - Vk_HEAP_PROPERTIES HeapProps; - HeapProps.Type = Vk_HEAP_TYPE_DEFAULT; - HeapProps.CPUPageProperty = Vk_CPU_PAGE_PROPERTY_UNKNOWN; - HeapProps.MemoryPoolPreference = Vk_MEMORY_POOL_UNKNOWN; - HeapProps.CreationNodeMask = 1; - HeapProps.VisibleNodeMask = 1; - - auto hr = pDevice->CreateCommittedResource( &HeapProps, Vk_HEAP_FLAG_NONE, &ResDesc, Vk_RESOURCE_STATE_COMMON, nullptr, __uuidof(IVkResource), nullptr ); - return hr == S_FALSE; // S_FALSE means that input parameters passed validation -} -#endif void RenderDeviceVkImpl::TestTextureFormat( TEXTURE_FORMAT TexFormat ) { -#if 0 auto &TexFormatInfo = m_TextureFormatsInfo[TexFormat]; VERIFY( TexFormatInfo.Supported, "Texture format is not supported" ); - auto DXGIFormat = TexFormatToDXGI_Format(TexFormat); - Vk_RESOURCE_FLAGS DefaultResourceFlags = Vk_RESOURCE_FLAG_NONE; - if( TexFormatInfo.ComponentType == COMPONENT_TYPE_DEPTH || - TexFormatInfo.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL ) - DefaultResourceFlags = Vk_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - - const int TestTextureDim = 32; - const int TestTextureDepth = 8; - - Vk_RESOURCE_DESC ResDesc = - { - Vk_RESOURCE_DIMENSION_TEXTURE1D, - 0, // Alignment - TestTextureDim, - 1, // Height - 1, // DepthOrArraySize - 1, // MipLevels - DXGIFormat, - {1, 0}, - Vk_TEXTURE_LAYOUT_UNKNOWN, - DefaultResourceFlags - }; - - // Create test texture 1D - TexFormatInfo.Tex1DFmt = false; - if( TexFormatInfo.ComponentType != COMPONENT_TYPE_COMPRESSED ) - { - TexFormatInfo.Tex1DFmt = CreateTestResource(m_pVkDevice, ResDesc ); - } + auto vkPhysicalDevice = m_PhysicalDevice->GetVkDeviceHandle(); - // Create test texture 2D - TexFormatInfo.Tex2DFmt = false; - TexFormatInfo.TexCubeFmt = false; - TexFormatInfo.ColorRenderable = false; - TexFormatInfo.DepthRenderable = false; - TexFormatInfo.SupportsMS = false; + auto SRVFormat = GetDefaultTextureViewFormat(TexFormat, TEXTURE_VIEW_SHADER_RESOURCE, BIND_SHADER_RESOURCE); + auto RTVFormat = GetDefaultTextureViewFormat(TexFormat, TEXTURE_VIEW_RENDER_TARGET, BIND_RENDER_TARGET); + auto DSVFormat = GetDefaultTextureViewFormat(TexFormat, TEXTURE_VIEW_DEPTH_STENCIL, BIND_DEPTH_STENCIL); + + if(SRVFormat != TEX_FORMAT_UNKNOWN) { - ResDesc.Dimension = Vk_RESOURCE_DIMENSION_TEXTURE2D; - ResDesc.Height = TestTextureDim; - TexFormatInfo.Tex2DFmt = CreateTestResource( m_pVkDevice, ResDesc ); + VkFormat vkSrvFormat = TexFormatToVkFormat(SRVFormat); + VkFormatProperties vkSrvFmtProps = {}; + vkGetPhysicalDeviceFormatProperties(vkPhysicalDevice, vkSrvFormat, &vkSrvFmtProps); - if( TexFormatInfo.Tex2DFmt ) + if(vkSrvFmtProps.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { + TexFormatInfo.Filterable = true; + { - // Vk_TEXTURE2D_DESC CubeTexDesc = Tex2DDesc; - ResDesc.DepthOrArraySize = 6; - // CubeTexDesc.MiscFlags = Vk_RESOURCE_MISC_TEXTURECUBE; - TexFormatInfo.TexCubeFmt = CreateTestResource( m_pVkDevice, ResDesc ); - ResDesc.DepthOrArraySize = 1; + VkImageFormatProperties ImgFmtProps = {}; + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_1D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_SAMPLED_BIT, 0, &ImgFmtProps); + TexFormatInfo.Tex1DFmt = err == VK_SUCCESS; } - if( TexFormatInfo.ComponentType == COMPONENT_TYPE_DEPTH || - TexFormatInfo.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL ) { - ResDesc.Flags = Vk_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - ResDesc.SampleDesc.Count = 1; - TexFormatInfo.DepthRenderable = CreateTestResource( m_pVkDevice, ResDesc ); - - if( TexFormatInfo.DepthRenderable ) - { - ResDesc.SampleDesc.Count = 4; - TexFormatInfo.SupportsMS = CreateTestResource( m_pVkDevice, ResDesc ); - } + VkImageFormatProperties ImgFmtProps = {}; + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_SAMPLED_BIT, 0, &ImgFmtProps); + TexFormatInfo.Tex2DFmt = err == VK_SUCCESS; } - else if( TexFormatInfo.ComponentType != COMPONENT_TYPE_COMPRESSED && - TexFormatInfo.Format != DXGI_FORMAT_R9G9B9E5_SHAREDEXP ) + + { + VkImageFormatProperties ImgFmtProps = {}; + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_3D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_SAMPLED_BIT, 0, &ImgFmtProps); + TexFormatInfo.Tex3DFmt = err == VK_SUCCESS; + } + + { + VkImageFormatProperties ImgFmtProps = {}; + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, &ImgFmtProps); + TexFormatInfo.TexCubeFmt = err == VK_SUCCESS; + } + + } + } + + if (RTVFormat != TEX_FORMAT_UNKNOWN) + { + VkFormat vkRtvFormat = TexFormatToVkFormat(RTVFormat); + VkFormatProperties vkRtvFmtProps = {}; + vkGetPhysicalDeviceFormatProperties(vkPhysicalDevice, vkRtvFormat, &vkRtvFmtProps); + if (vkRtvFmtProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) + { + VkImageFormatProperties ImgFmtProps = {}; + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkRtvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, &ImgFmtProps); + TexFormatInfo.ColorRenderable = err == VK_SUCCESS; + if (TexFormatInfo.ColorRenderable) { - ResDesc.Flags = Vk_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - ResDesc.SampleDesc.Count = 1; - TexFormatInfo.ColorRenderable = CreateTestResource( m_pVkDevice, ResDesc ); - if( TexFormatInfo.ColorRenderable ) - { - ResDesc.SampleDesc.Count = 4; - TexFormatInfo.SupportsMS = CreateTestResource( m_pVkDevice, ResDesc ); - } + TexFormatInfo.SupportsMS = ImgFmtProps.sampleCounts > VK_SAMPLE_COUNT_1_BIT; } } } - // Create test texture 3D - TexFormatInfo.Tex3DFmt = false; - // 3D textures do not support depth formats - if( !(TexFormatInfo.ComponentType == COMPONENT_TYPE_DEPTH || - TexFormatInfo.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) ) + if (DSVFormat != TEX_FORMAT_UNKNOWN) { - ResDesc.SampleDesc.Count = 1; - ResDesc.Dimension = Vk_RESOURCE_DIMENSION_TEXTURE3D; - ResDesc.Flags = DefaultResourceFlags; - ResDesc.DepthOrArraySize = TestTextureDepth; - TexFormatInfo.Tex3DFmt = CreateTestResource( m_pVkDevice, ResDesc ); + VkFormat vkDsvFormat = TexFormatToVkFormat(DSVFormat); + VkFormatProperties vkDsvFmtProps = {}; + vkGetPhysicalDeviceFormatProperties(vkPhysicalDevice, vkDsvFormat, &vkDsvFmtProps); + if (vkDsvFmtProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) + { + VkImageFormatProperties ImgFmtProps = {}; + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkDsvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &ImgFmtProps); + TexFormatInfo.DepthRenderable = err == VK_SUCCESS; + if (TexFormatInfo.DepthRenderable) + { + TexFormatInfo.SupportsMS = ImgFmtProps.sampleCounts > VK_SAMPLE_COUNT_1_BIT; + } + } } -#endif } diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp index 30543134..606abc1f 100644 --- a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp @@ -314,12 +314,14 @@ void SwapChainVkImpl::InitBuffersAndViews() BackBufferDesc.Width = m_SwapChainDesc.Width; BackBufferDesc.Height = m_SwapChainDesc.Height; BackBufferDesc.Format = m_SwapChainDesc.ColorBufferFormat; + BackBufferDesc.BindFlags = BIND_RENDER_TARGET; BackBufferDesc.MipLevels = 1; RefCntAutoPtr<TextureVkImpl> pBackBufferTex; ValidatedCast<RenderDeviceVkImpl>(m_pRenderDevice.RawPtr())->CreateTexture(BackBufferDesc, swapchainImages[i], &pBackBufferTex); - UNSUPPORTED("TODO: move all this code to Texture creation"); + //UNSUPPORTED("TODO: move all this code to Texture creation"); + VkImageViewCreateInfo color_image_view = {}; color_image_view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; color_image_view.pNext = NULL; @@ -396,12 +398,6 @@ IMPLEMENT_QUERY_INTERFACE( SwapChainVkImpl, IID_SwapChainVk, TSwapChainBase ) void SwapChainVkImpl::Present(Uint32 SyncInterval) { -#if 0 - UINT SyncInterval = 0; -#if PLATFORM_UNIVERSAL_WINDOWS - SyncInterval = 1; // Interval 0 is not supported on Windows Phone -#endif - auto pDeviceContext = m_wpDeviceContext.Lock(); if( !pDeviceContext ) { @@ -412,16 +408,18 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval) auto *pImmediateCtx = pDeviceContext.RawPtr(); auto *pImmediateCtxVk = ValidatedCast<DeviceContextVkImpl>( pImmediateCtx ); +#if 0 auto *pCmdCtx = pImmediateCtxVk->RequestCmdContext(); auto *pBackBuffer = ValidatedCast<TextureVkImpl>( GetCurrentBackBufferRTV()->GetTexture() ); pCmdCtx->TransitionResource( pBackBuffer, Vk_RESOURCE_STATE_PRESENT); - +#endif pImmediateCtxVk->Flush(); auto *pDeviceVk = ValidatedCast<RenderDeviceVkImpl>( pImmediateCtxVk->GetDevice() ); - +#if 0 auto hr = m_pSwapChain->Present( SyncInterval, 0 ); VERIFY(SUCCEEDED(hr), "Present failed"); +#endif pDeviceVk->FinishFrame(); @@ -434,7 +432,6 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval) pImmediateCtxVk->CommitRenderTargets(); #endif #endif -#endif } void SwapChainVkImpl::Resize( Uint32 NewWidth, Uint32 NewHeight ) @@ -506,5 +503,4 @@ void SwapChainVkImpl::SetWindowedMode() { } - } diff --git a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp index be36e9dd..48536542 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp @@ -24,6 +24,7 @@ #include "pch.h" #include "TextureViewVkImpl.h" #include "DeviceContextVkImpl.h" +#include "RenderDeviceVkImpl.h" namespace Diligent { @@ -32,13 +33,19 @@ TextureViewVkImpl::TextureViewVkImpl( IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureViewDesc& ViewDesc, ITexture *pTexture, - VkImageView vkImgView, + VulkanUtilities::ImageViewWrapper &&ImgView, bool bIsDefaultView ) : TTextureViewBase( pRefCounters, pDevice, ViewDesc, pTexture, bIsDefaultView ), - m_VkImageView(vkImgView) + m_ImageView(std::move(ImgView)) { } +TextureViewVkImpl::~TextureViewVkImpl() +{ + auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice()); + pDeviceVkImpl->SafeReleaseVkObject(std::move(m_ImageView)); +} + IMPLEMENT_QUERY_INTERFACE( TextureViewVkImpl, IID_TextureViewVk, TTextureViewBase ) void TextureViewVkImpl::GenerateMips( IDeviceContext *pContext ) diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index fabf8323..bb069dd9 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -58,59 +58,92 @@ DXGI_FORMAT GetClearFormat(DXGI_FORMAT Fmt, Vk_RESOURCE_FLAGS Flags) #endif TextureVkImpl :: TextureVkImpl(IReferenceCounters *pRefCounters, - FixedBlockMemoryAllocator &TexViewObjAllocator, - RenderDeviceVkImpl *pRenderDeviceVk, - const TextureDesc& TexDesc, - const TextureData &InitData /*= TextureData()*/) : + FixedBlockMemoryAllocator &TexViewObjAllocator, + RenderDeviceVkImpl *pRenderDeviceVk, + const TextureDesc& TexDesc, + const TextureData &InitData /*= TextureData()*/) : TTextureBase(pRefCounters, TexViewObjAllocator, pRenderDeviceVk, TexDesc), m_IsExternalHandle(false) { if( m_Desc.Usage == USAGE_STATIC && InitData.pSubResources == nullptr ) LOG_ERROR_AND_THROW("Static Texture must be initialized with data at creation time"); -#if 0 - Vk_RESOURCE_DESC Desc = {}; - Desc.Alignment = 0; - if(m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) - Desc.DepthOrArraySize = (UINT16)m_Desc.ArraySize; - else if(m_Desc.Type == RESOURCE_DIM_TEX_3D ) - Desc.DepthOrArraySize = (UINT16)m_Desc.Depth; - else - Desc.DepthOrArraySize = 1; - - if( m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY ) - Desc.Dimension = Vk_RESOURCE_DIMENSION_TEXTURE1D; - else if( m_Desc.Type == RESOURCE_DIM_TEX_2D || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) - Desc.Dimension = Vk_RESOURCE_DIMENSION_TEXTURE2D; - else if( m_Desc.Type == RESOURCE_DIM_TEX_3D ) - Desc.Dimension = Vk_RESOURCE_DIMENSION_TEXTURE3D; + + const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); + const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); + + VkImageCreateInfo ImageCI = {}; + ImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + ImageCI.pNext = nullptr; + ImageCI.flags = 0; + if(m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + ImageCI.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + const auto &FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + if(FmtAttribs.IsTypeless) + ImageCI.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; // Specifies that the image can be used to create a + // VkImageView with a different format from the image. + + if (m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) + ImageCI.imageType = VK_IMAGE_TYPE_1D; + else if (m_Desc.Type == RESOURCE_DIM_TEX_2D || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + ImageCI.imageType = VK_IMAGE_TYPE_2D; + else if (m_Desc.Type == RESOURCE_DIM_TEX_3D) + ImageCI.imageType = VK_IMAGE_TYPE_3D; else { LOG_ERROR_AND_THROW("Unknown texture type"); } + if (FmtAttribs.IsTypeless) + { + // Use SRV format to create the texture + auto SRVFormat = GetDefaultTextureViewFormat(m_Desc, TEXTURE_VIEW_SHADER_RESOURCE); + ImageCI.format = TexFormatToVkFormat(SRVFormat); + } + else + { + ImageCI.format = TexFormatToVkFormat(m_Desc.Format); + } + + ImageCI.extent.width = m_Desc.Width; + ImageCI.extent.height = (m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) ? 1 : m_Desc.Height; + ImageCI.extent.depth = (m_Desc.Type == RESOURCE_DIM_TEX_3D) ? m_Desc.Depth : 1; + + ImageCI.mipLevels = m_Desc.MipLevels; + if (m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY || + m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || + m_Desc.Type == RESOURCE_DIM_TEX_CUBE || + m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + ImageCI.arrayLayers = m_Desc.ArraySize; + else + ImageCI.arrayLayers = 1; + + ImageCI.samples = static_cast<VkSampleCountFlagBits>(1 << (m_Desc.SampleCount-1)); + ImageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + + ImageCI.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + if (m_Desc.BindFlags & BIND_RENDER_TARGET) + ImageCI.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (m_Desc.BindFlags & BIND_DEPTH_STENCIL) + ImageCI.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + if ((m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS)) + ImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT; + if ((m_Desc.BindFlags & BIND_SHADER_RESOURCE) == 0) + ImageCI.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + + ImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + ImageCI.queueFamilyIndexCount = 0; + ImageCI.pQueueFamilyIndices = nullptr; + ImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + +#if 0 Desc.Flags = Vk_RESOURCE_FLAG_NONE; - if( m_Desc.BindFlags & BIND_RENDER_TARGET ) - Desc.Flags |= Vk_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - if( m_Desc.BindFlags & BIND_DEPTH_STENCIL ) - Desc.Flags |= Vk_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - if( (m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) ) - Desc.Flags |= Vk_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - if( (m_Desc.BindFlags & BIND_SHADER_RESOURCE) == 0 ) - Desc.Flags |= Vk_RESOURCE_FLAG_DENY_SHADER_RESOURCE; auto Format = TexFormatToDXGI_Format(m_Desc.Format, m_Desc.BindFlags); if (Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB && (Desc.Flags & Vk_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) Desc.Format = DXGI_FORMAT_R8G8B8A8_TYPELESS; else Desc.Format = Format; - Desc.Height = (UINT)m_Desc.Height; - Desc.Layout = Vk_TEXTURE_LAYOUT_UNKNOWN; - Desc.MipLevels = static_cast<Uint16>(m_Desc.MipLevels); - Desc.SampleDesc.Count = m_Desc.SampleCount; - Desc.SampleDesc.Quality = 0; - Desc.Width = (UINT64)m_Desc.Width; - Vk_HEAP_PROPERTIES HeapProps; HeapProps.Type = Vk_HEAP_TYPE_DEFAULT; @@ -141,19 +174,50 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters *pRefCounters, } pClearValue = &ClearValue; } +#endif bool bInitializeTexture = (InitData.pSubResources != nullptr && InitData.NumSubresources > 0); - if(bInitializeTexture) - m_UsageState = Vk_RESOURCE_STATE_COPY_DEST; + //if(bInitializeTexture) + // m_UsageState = Vk_RESOURCE_STATE_COPY_DEST; + + m_VulkanImage = LogicalDevice.CreateImage(ImageCI, m_Desc.Name); + + VkMemoryRequirements MemReqs = LogicalDevice.GetImageMemoryRequirements(m_VulkanImage); + + VkMemoryAllocateInfo MemAlloc = {}; + MemAlloc.pNext = nullptr; + MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + MemAlloc.allocationSize = MemReqs.size; + + VkMemoryPropertyFlags ImageMemoryFlags = 0; + if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE) + ImageMemoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + else + ImageMemoryFlags = 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, ImageMemoryFlags); + if (ImageMemoryFlags == 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 an image"); + } - auto hr = pVkDevice->CreateCommittedResource( &HeapProps, Vk_HEAP_FLAG_NONE, - &Desc, m_UsageState, pClearValue, __uuidof(m_pVkResource), reinterpret_cast<void**>(static_cast<IVkResource**>(&m_pVkResource)) ); - if(FAILED(hr)) - LOG_ERROR_AND_THROW("Failed to create Vk texture"); + m_ImageMemory = LogicalDevice.AllocateDeviceMemory(MemAlloc); - if( *m_Desc.Name != 0) - m_pVkResource->SetName(WidenString(m_Desc.Name).c_str()); + auto err = LogicalDevice.BindImageMemory(m_VulkanImage, m_ImageMemory, 0 /*offset*/); + CHECK_VK_ERROR_AND_THROW(err, "Failed to bind image memory"); +#if 0 if(bInitializeTexture) { Uint32 ExpectedNumSubresources = static_cast<Uint32>(Desc.MipLevels * (Desc.Dimension == Vk_RESOURCE_DIMENSION_TEXTURE3D ? 1 : Desc.DepthOrArraySize) ); @@ -277,12 +341,12 @@ static TextureDesc InitTexDescFromVkImage(VkImage vkImg, const TextureDesc& SrcT TextureVkImpl::TextureVkImpl(IReferenceCounters *pRefCounters, - FixedBlockMemoryAllocator &TexViewObjAllocator, - RenderDeviceVkImpl *pDeviceVk, - const TextureDesc& TexDesc, - VkImage VkImageHandle) : + FixedBlockMemoryAllocator &TexViewObjAllocator, + RenderDeviceVkImpl *pDeviceVk, + const TextureDesc& TexDesc, + VkImage VkImageHandle) : TTextureBase(pRefCounters, TexViewObjAllocator, pDeviceVk, InitTexDescFromVkImage(VkImageHandle, TexDesc)), - m_VkImage(VkImageHandle), + m_VulkanImage(nullptr, VkImageHandle), m_IsExternalHandle(true) { } @@ -295,7 +359,7 @@ void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc, VERIFY( *ppView == nullptr, "Overwriting reference to existing object may cause memory leaks" ); *ppView = nullptr; -#if 0 + try { auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice()); @@ -305,38 +369,38 @@ void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc, auto UpdatedViewDesc = ViewDesc; CorrectTextureViewDesc( UpdatedViewDesc ); - DescriptorHeapAllocation ViewHandleAlloc; + VulkanUtilities::ImageViewWrapper ImgView; switch( ViewDesc.ViewType ) { case TEXTURE_VIEW_SHADER_RESOURCE: { VERIFY( m_Desc.BindFlags & BIND_SHADER_RESOURCE, "BIND_SHADER_RESOURCE flag is not set" ); - ViewHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - CreateSRV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); + //ViewHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + //CreateSRV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); } break; case TEXTURE_VIEW_RENDER_TARGET: { VERIFY( m_Desc.BindFlags & BIND_RENDER_TARGET, "BIND_RENDER_TARGET flag is not set" ); - ViewHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_RTV); - CreateRTV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); + //ViewHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_RTV); + //CreateRTV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); } break; case TEXTURE_VIEW_DEPTH_STENCIL: { VERIFY( m_Desc.BindFlags & BIND_DEPTH_STENCIL, "BIND_DEPTH_STENCIL is not set" ); - ViewHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_DSV); - CreateDSV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); + //ViewHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_DSV); + //CreateDSV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); } break; case TEXTURE_VIEW_UNORDERED_ACCESS: { VERIFY( m_Desc.BindFlags & BIND_UNORDERED_ACCESS, "BIND_UNORDERED_ACCESS flag is not set" ); - ViewHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - CreateUAV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); + //ViewHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + //CreateUAV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); } break; @@ -344,7 +408,7 @@ void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc, } auto pViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, bIsDefaultView ? this : nullptr) - (GetDevice(), UpdatedViewDesc, this, std::move(ViewHandleAlloc), bIsDefaultView ); + (GetDevice(), UpdatedViewDesc, this, std::move(ImgView), bIsDefaultView ); VERIFY( pViewVk->GetDesc().ViewType == ViewDesc.ViewType, "Incorrect view type" ); if( bIsDefaultView ) @@ -357,20 +421,17 @@ void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc, const auto *ViewTypeName = GetTexViewTypeLiteralName(ViewDesc.ViewType); LOG_ERROR("Failed to create view \"", ViewDesc.Name ? ViewDesc.Name : "", "\" (", ViewTypeName, ") for texture \"", m_Desc.Name ? m_Desc.Name : "", "\"" ); } -#endif } TextureVkImpl :: ~TextureVkImpl() { if(!m_IsExternalHandle) { - + 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_VulkanImage)); + pDeviceVkImpl->SafeReleaseVkObject(std::move(m_ImageMemory)); } -#if 0 - // Vk object can only be destroyed when it is no longer used by the GPU - auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice()); - pDeviceVkImpl->SafeReleaseVkObject(m_pVkResource); -#endif } void TextureVkImpl::UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint32 Slice, const Box &DstBox, const TextureSubResData &SubresData ) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp new file mode 100644 index 00000000..89214191 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp @@ -0,0 +1,115 @@ +/* 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 <sstream> + +#include "VulkanUtilities/VulkanCommandBufferPool.h" +#include "VulkanUtilities/VulkanDebug.h" +#include "Errors.h" +#include "DebugUtilities.h" +#include "VulkanErrors.h" + +namespace VulkanUtilities +{ + VulkanCommandBufferPool::VulkanCommandBufferPool(std::shared_ptr<VulkanUtilities::VulkanLogicalDevice> LogicalDevice, + uint32_t queueFamilyIndex, + VkCommandPoolCreateFlags flags) : + m_LogicalDevice(LogicalDevice) + { + VkCommandPoolCreateInfo CmdPoolCI = {}; + CmdPoolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + CmdPoolCI.pNext = nullptr; + CmdPoolCI.queueFamilyIndex = queueFamilyIndex; + CmdPoolCI.flags = flags; + m_CmdPool = m_LogicalDevice->CreateCommandPool(CmdPoolCI); + VERIFY_EXPR(m_CmdPool != VK_NULL_HANDLE); + } + + VulkanCommandBufferPool::~VulkanCommandBufferPool() + { + m_CmdPool.Release(); + } + + VkCommandBuffer VulkanCommandBufferPool::GetCommandBuffer(uint64_t LastCompletedFence, const char* DebugName) + { + VkCommandBuffer CmdBuffer = VK_NULL_HANDLE; + + if (!m_DiscardedCmdBuffers.empty()) + { + // Pick the oldest cmd buffer at the front of the deque + // If this buffer is not yet available, there is no point in + // looking at other buffers since they were released even + // later + auto& OldestBuff = m_DiscardedCmdBuffers.front(); + + // Note that LastCompletedFence only grows. So if after we queried + // the value, the actual value is increased in other thread, this will not + // be an issue as the only consequence is that potentially available + // cmd buffer may not be used. + + // OldestBuff.first is the fence value that was signaled AFTER the + // command buffer has been submitted. If LastCompletedFence is at least + // this value, the buffer can be safely reused + if (LastCompletedFence >= OldestBuff.first) + { + CmdBuffer = OldestBuff.second; + auto err = vkResetCommandBuffer(CmdBuffer, + 0 // VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT - specifies that most or all memory resources currently owned by the command buffer should be returned to the parent command pool. + ); + VERIFY(err == VK_SUCCESS, "Failed to reset command buffer"); + m_DiscardedCmdBuffers.pop_front(); + } + } + + // If no allocators were ready to be reused, create a new one + if (CmdBuffer == VK_NULL_HANDLE) + { + VkCommandBufferAllocateInfo BuffAllocInfo = {}; + BuffAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + BuffAllocInfo.pNext = nullptr; + BuffAllocInfo.commandPool = m_CmdPool; + BuffAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + BuffAllocInfo.commandBufferCount = 1; + + CmdBuffer = m_LogicalDevice->AllocateVkCommandBuffer(BuffAllocInfo); + } + + VkCommandBufferBeginInfo CmdBuffBeginInfo = {}; + CmdBuffBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + CmdBuffBeginInfo.pNext = nullptr; + CmdBuffBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; // Each recording of the command buffer will only be + // submitted once, and the command buffer will be reset + // and recorded again between each submission. + CmdBuffBeginInfo.pInheritanceInfo = nullptr; // Ignored for a primary command buffer + auto err = vkBeginCommandBuffer(CmdBuffer, &CmdBuffBeginInfo); + VERIFY(err == VK_SUCCESS, "Failed to begin command buffer"); + + return CmdBuffer; + } + + void VulkanCommandBufferPool::DisposeCommandBuffer(VkCommandBuffer CmdBuffer, uint64_t FenceValue) + { + // FenceValue is the value that was signaled by the command queue after it + // executed the command buffer + m_DiscardedCmdBuffers.emplace_back(FenceValue, CmdBuffer); + } +} diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp index dabeef91..a66f267a 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp @@ -187,6 +187,11 @@ namespace VulkanUtilities // } //} + void SetCommandPoolName(VkDevice device, VkCommandPool cmdPool, const char * name) + { + SetObjectName(device, (uint64_t)cmdPool, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, name); + } + void SetCommandBufferName(VkDevice device, VkCommandBuffer cmdBuffer, const char * name) { SetObjectName(device, (uint64_t)cmdBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, name); @@ -202,6 +207,11 @@ namespace VulkanUtilities SetObjectName(device, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, name); } + void SetImageViewName(VkDevice device, VkImageView imageView, const char * name) + { + SetObjectName(device, (uint64_t)imageView, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT, name); + } + void SetSamplerName(VkDevice device, VkSampler sampler, const char * name) { SetObjectName(device, (uint64_t)sampler, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, name); @@ -212,6 +222,11 @@ namespace VulkanUtilities SetObjectName(device, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, name); } + void SetBufferViewName(VkDevice device, VkBufferView bufferView, const char * name) + { + SetObjectName(device, (uint64_t)bufferView, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT, name); + } + void SetDeviceMemoryName(VkDevice device, VkDeviceMemory memory, const char * name) { SetObjectName(device, (uint64_t)memory, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, name); diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp new file mode 100644 index 00000000..eaf6bd7c --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp @@ -0,0 +1,69 @@ +/* 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 <sstream> + +#include "VulkanUtilities/VulkanFencePool.h" +#include "Errors.h" +#include "DebugUtilities.h" + +namespace VulkanUtilities +{ + VulkanFencePool::VulkanFencePool(std::shared_ptr<const VulkanLogicalDevice> LogicalDevice) : + m_LogicalDevice(LogicalDevice) + {} + + VulkanFencePool::~VulkanFencePool() + { + for(const auto &fence : m_Fences) + { + VERIFY(m_LogicalDevice->GetFenceStatus(fence) == VK_SUCCESS, "Destroying a fence that has not been signaled"); + } + m_Fences.clear(); + } + + VulkanUtilities::FenceWrapper VulkanFencePool::GetFence() + { + VulkanUtilities::FenceWrapper Fence; + if(!m_Fences.empty()) + { + Fence = std::move(m_Fences.back()); + m_LogicalDevice->ResetFence(Fence); + m_Fences.pop_back(); + } + else + { + VkFenceCreateInfo FenceCI = {}; + FenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + FenceCI.pNext = nullptr; + FenceCI.flags = 0; // Available flag: VK_FENCE_CREATE_SIGNALED_BIT + Fence = m_LogicalDevice->CreateFence(FenceCI); + } + return Fence; + } + + void VulkanFencePool::DisposeFence(VulkanUtilities::FenceWrapper&& Fence) + { + VERIFY(m_LogicalDevice->GetFenceStatus(Fence) == VK_SUCCESS, "Disposing a fence that has not been signaled"); + m_Fences.emplace_back(std::move(Fence)); + } +} diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp index 4679b874..43c6d6cc 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp @@ -46,6 +46,15 @@ namespace VulkanUtilities return false; } + std::shared_ptr<VulkanInstance> VulkanInstance::Create(bool EnableValidation, + uint32_t GlobalExtensionCount, + const char* const* ppGlobalExtensionNames, + VkAllocationCallbacks* pVkAllocator) + { + auto Instance = new VulkanInstance(EnableValidation, GlobalExtensionCount, ppGlobalExtensionNames, pVkAllocator); + return std::shared_ptr<VulkanInstance>(Instance); + } + VulkanInstance::VulkanInstance(bool EnableValidation, uint32_t GlobalExtensionCount, const char* const* ppGlobalExtensionNames, diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp new file mode 100644 index 00000000..cc1370d0 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp @@ -0,0 +1,292 @@ +/* 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 <limits> +#include "VulkanErrors.h" +#include "VulkanUtilities/VulkanLogicalDevice.h" +#include "VulkanUtilities/VulkanDebug.h" + +namespace VulkanUtilities +{ + std::shared_ptr<VulkanLogicalDevice> VulkanLogicalDevice::Create(VkPhysicalDevice vkPhysicalDevice, + const VkDeviceCreateInfo &DeviceCI, + const VkAllocationCallbacks* vkAllocator, + bool EnableDebugMarkers) + { + auto *LogicalDevice = new VulkanLogicalDevice(vkPhysicalDevice, DeviceCI, vkAllocator, EnableDebugMarkers); + return std::shared_ptr<VulkanLogicalDevice>(LogicalDevice); + } + + VulkanLogicalDevice::~VulkanLogicalDevice() + { + vkDestroyDevice(m_VkDevice, m_VkAllocator); + } + + VulkanLogicalDevice::VulkanLogicalDevice(VkPhysicalDevice vkPhysicalDevice, + const VkDeviceCreateInfo &DeviceCI, + const VkAllocationCallbacks* vkAllocator, + bool EnableDebugMarkers) : + m_VkAllocator(vkAllocator) + { + auto res = vkCreateDevice(vkPhysicalDevice, &DeviceCI, vkAllocator, &m_VkDevice); + CHECK_VK_ERROR_AND_THROW(res, "Failed to create logical device"); + + if (EnableDebugMarkers) + { + VulkanUtilities::SetupDebugMarkers(m_VkDevice); + } + } + + VkQueue VulkanLogicalDevice::GetQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) + { + VkQueue vkQueue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_VkDevice, + queueFamilyIndex, // Index of the queue family to which the queue belongs + 0, // Index within this queue family of the queue to retrieve + &vkQueue); + VERIFY_EXPR(vkQueue != VK_NULL_HANDLE); + return vkQueue; + } + + void VulkanLogicalDevice::WaitIdle()const + { + auto err = vkDeviceWaitIdle(m_VkDevice); + VERIFY_EXPR(err == VK_SUCCESS); + } + + CommandPoolWrapper VulkanLogicalDevice::CreateCommandPool(const VkCommandPoolCreateInfo &CmdPoolCI, + const char *DebugName) const + { + if(DebugName == nullptr) + DebugName = ""; + + VkCommandPool CmdPool = VK_NULL_HANDLE; + auto err = vkCreateCommandPool(m_VkDevice, &CmdPoolCI, m_VkAllocator, &CmdPool); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan command pool '", DebugName, '\''); + + if(DebugName != nullptr && *DebugName != 0) + VulkanUtilities::SetCommandPoolName(m_VkDevice, CmdPool, DebugName); + + return CommandPoolWrapper{ GetSharedPtr(), CmdPool}; + } + + BufferWrapper VulkanLogicalDevice::CreateBuffer(const VkBufferCreateInfo &BufferCI, + const char *DebugName)const + { + if (DebugName == nullptr) + DebugName = ""; + + VkBuffer vkBuffer = VK_NULL_HANDLE; + auto err = vkCreateBuffer(m_VkDevice, &BufferCI, m_VkAllocator, &vkBuffer); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan buffer '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + VulkanUtilities::SetBufferName(m_VkDevice, vkBuffer, DebugName); + + return BufferWrapper{ GetSharedPtr(), vkBuffer }; + } + + BufferViewWrapper VulkanLogicalDevice::CreateBufferView(const VkBufferViewCreateInfo &BuffViewCI, + const char *DebugName)const + { + if (DebugName == nullptr) + DebugName = ""; + + VkBufferView vkBufferView = VK_NULL_HANDLE; + auto err = vkCreateBufferView(m_VkDevice, &BuffViewCI, m_VkAllocator, &vkBufferView); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan buffer view '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + VulkanUtilities::SetBufferViewName(m_VkDevice, vkBufferView, DebugName); + + return BufferViewWrapper{ GetSharedPtr(), vkBufferView }; + } + + ImageWrapper VulkanLogicalDevice::CreateImage(const VkImageCreateInfo &ImageCI, + const char *DebugName)const + { + if (DebugName == nullptr) + DebugName = ""; + + VkImage vkImage = VK_NULL_HANDLE; + auto err = vkCreateImage(m_VkDevice, &ImageCI, m_VkAllocator, &vkImage); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan image '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + VulkanUtilities::SetImageName(m_VkDevice, vkImage, DebugName); + + return ImageWrapper{ GetSharedPtr(), vkImage }; + } + + ImageViewWrapper VulkanLogicalDevice::CreateImageView(const VkImageViewCreateInfo &ImageViewCI, + const char *DebugName)const + { + if (DebugName == nullptr) + DebugName = ""; + + VkImageView vkImageView = VK_NULL_HANDLE; + auto err = vkCreateImageView(m_VkDevice, &ImageViewCI, m_VkAllocator, &vkImageView); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan image view '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + VulkanUtilities::SetImageViewName(m_VkDevice, vkImageView, DebugName); + + return ImageViewWrapper{ GetSharedPtr(), vkImageView }; + } + + FenceWrapper VulkanLogicalDevice::CreateFence(const VkFenceCreateInfo &FenceCI, const char *DebugName)const + { + if (DebugName == nullptr) + DebugName = ""; + + VkFence vkFence = VK_NULL_HANDLE; + auto err = vkCreateFence(m_VkDevice, &FenceCI, m_VkAllocator, &vkFence); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create fence '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + VulkanUtilities::SetFenceName(m_VkDevice, vkFence, DebugName); + + return FenceWrapper{ GetSharedPtr(), vkFence }; + } + + DeviceMemoryWrapper VulkanLogicalDevice::AllocateDeviceMemory(const VkMemoryAllocateInfo &AllocInfo, + const char *DebugName)const + { + if (DebugName == nullptr) + DebugName = ""; + + VkDeviceMemory vkDeviceMem = VK_NULL_HANDLE; + + auto err = vkAllocateMemory(m_VkDevice, &AllocInfo, m_VkAllocator, &vkDeviceMem); + CHECK_VK_ERROR_AND_THROW(err, "Failed to allocate device memory '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + VulkanUtilities::SetDeviceMemoryName(m_VkDevice, vkDeviceMem, DebugName); + + return DeviceMemoryWrapper{ GetSharedPtr(), vkDeviceMem }; + } + + + VkCommandBuffer VulkanLogicalDevice::AllocateVkCommandBuffer(const VkCommandBufferAllocateInfo &AllocInfo, const char *DebugName)const + { + if (DebugName == nullptr) + DebugName = ""; + + VkCommandBuffer CmdBuff = VK_NULL_HANDLE; + auto err = vkAllocateCommandBuffers(m_VkDevice, &AllocInfo, &CmdBuff); + VERIFY(err == VK_SUCCESS, "Failed to allocate command buffer '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + SetCommandBufferName(m_VkDevice, CmdBuff, DebugName); + + return CmdBuff; + } + + void VulkanLogicalDevice::ReleaseVulkanObject(CommandPoolWrapper &&CmdPool)const + { + vkDestroyCommandPool(m_VkDevice, CmdPool.m_VkObject, m_VkAllocator); + CmdPool.m_VkObject = VK_NULL_HANDLE; + } + + void VulkanLogicalDevice::ReleaseVulkanObject(BufferWrapper&& Buffer)const + { + vkDestroyBuffer(m_VkDevice, Buffer.m_VkObject, m_VkAllocator); + Buffer.m_VkObject = VK_NULL_HANDLE; + } + + void VulkanLogicalDevice::ReleaseVulkanObject(BufferViewWrapper&& BufferView)const + { + vkDestroyBufferView(m_VkDevice, BufferView.m_VkObject, m_VkAllocator); + BufferView.m_VkObject = VK_NULL_HANDLE; + } + + void VulkanLogicalDevice::ReleaseVulkanObject(ImageWrapper&& Image)const + { + vkDestroyImage(m_VkDevice, Image.m_VkObject, m_VkAllocator); + Image.m_VkObject = VK_NULL_HANDLE; + } + + void VulkanLogicalDevice::ReleaseVulkanObject(ImageViewWrapper&& ImageView)const + { + vkDestroyImageView(m_VkDevice, ImageView.m_VkObject, m_VkAllocator); + ImageView.m_VkObject = VK_NULL_HANDLE; + } + + void VulkanLogicalDevice::ReleaseVulkanObject(FenceWrapper&& Fence)const + { + vkDestroyFence(m_VkDevice, Fence.m_VkObject, m_VkAllocator); + Fence.m_VkObject = VK_NULL_HANDLE; + } + + void VulkanLogicalDevice::ReleaseVulkanObject(DeviceMemoryWrapper&& Memory)const + { + vkFreeMemory(m_VkDevice, Memory.m_VkObject, m_VkAllocator); + Memory.m_VkObject = VK_NULL_HANDLE; + } + + VkMemoryRequirements VulkanLogicalDevice::GetBufferMemoryRequirements(VkBuffer vkBuffer)const + { + VkMemoryRequirements MemReqs = {}; + vkGetBufferMemoryRequirements(m_VkDevice, vkBuffer, &MemReqs); + return MemReqs; + } + + VkMemoryRequirements VulkanLogicalDevice::GetImageMemoryRequirements(VkImage vkImage)const + { + VkMemoryRequirements MemReqs = {}; + vkGetImageMemoryRequirements(m_VkDevice, vkImage, &MemReqs); + return MemReqs; + } + + VkResult VulkanLogicalDevice::BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset)const + { + return vkBindBufferMemory(m_VkDevice, buffer, memory, memoryOffset); + } + + VkResult VulkanLogicalDevice::BindImageMemory(VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset)const + { + return vkBindImageMemory(m_VkDevice, image, memory, memoryOffset); + } + + VkResult VulkanLogicalDevice::MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData)const + { + return vkMapMemory(m_VkDevice, memory, offset, size, flags, ppData); + } + + void VulkanLogicalDevice::UnmapMemory(VkDeviceMemory memory)const + { + vkUnmapMemory(m_VkDevice, memory); + } + + VkResult VulkanLogicalDevice::GetFenceStatus(VkFence fence)const + { + return vkGetFenceStatus(m_VkDevice, fence); + } + + VkResult VulkanLogicalDevice::ResetFence(VkFence fence)const + { + auto err = vkResetFences(m_VkDevice, 1, &fence); + VERIFY(err == VK_SUCCESS, "Failed to reset fence"); + return err; + } +} diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index f09dd271..26f5e18a 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -27,6 +27,12 @@ namespace VulkanUtilities { + std::unique_ptr<VulkanPhysicalDevice> VulkanPhysicalDevice::Create(VkPhysicalDevice vkDevice) + { + auto *PhysicalDevice = new VulkanPhysicalDevice(vkDevice); + return std::unique_ptr<VulkanPhysicalDevice>(PhysicalDevice); + } + VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice) : m_VkDevice(vkDevice) { |
